Panda3D

mayaShaderColorDef.cxx
Go to the documentation of this file.
1 /**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file mayaShaderColorDef.cxx
10 * @author drose
11 * @date 2003-04-12
12 * Modified 19Mar10 by ETC PandaSE team (see
13 * header comment for mayaToEgg.cxx for details)
14 */
15
16 #include "mayaShaderColorDef.h"
17 #include "mayaShader.h"
18 #include "maya_funcs.h"
19 #include "config_maya.h"
20 #include "string_utils.h"
21 #include "pset.h"
22
23 #include "pre_maya_include.h"
24 #include <maya/MFnDependencyNode.h>
25 #include <maya/MPlug.h>
26 #include <maya/MPlugArray.h>
27 #include <maya/MObject.h>
28 #include <maya/MStatus.h>
29 #include <maya/MFnEnumAttribute.h>
30 #include "post_maya_include.h"
31
32 using std::endl;
33 using std::string;
34
35 /**
36 *
37 */
38 MayaShaderColorDef::
39 MayaShaderColorDef() {
40
41 _blend_type = BT_unspecified;
42
43 _projection_type = PT_off;
44 _projection_matrix = LMatrix4d::ident_mat();
45 _u_angle = 0.0;
46 _v_angle = 0.0;
47
48 _texture_filename = "";
49 _texture_name = "";
50 _color_gain.set(1.0f, 1.0f, 1.0f, 1.0f);
51
52 _coverage.set(1.0, 1.0);
53 _translate_frame.set(0.0, 0.0);
54 _rotate_frame = 0.0;
55
56 _mirror = false;
57 _stagger = false;
58 _wrap_u = true;
59 _wrap_v = true;
60
61 _repeat_uv.set(1.0, 1.0);
62 _offset.set(0.0, 0.0);
63 _rotate_uv = 0.0;
64
65 _is_alpha = false;
66
67 _opposite = 0;
68
69 _color_object = nullptr;
70
71 _has_texture = false;
72 _has_flat_color = false;
73 _flat_color.set(0.0, 0.0, 0.0, 0.0);
74 _has_alpha_channel = false;
75 _keep_color = false; // classic mode overwrites color: new mode retains color with a 3rd layer
76 _keep_alpha = false;
77 _interpolate = false;
78 _uvset_name = "map1";
79
80 _map_uvs = nullptr;
81 }
82
83 /**
84 *
85 */
86 MayaShaderColorDef::
87 MayaShaderColorDef(MayaShaderColorDef &copy) {
88 _has_texture = copy._has_texture;
89 _texture_filename = copy._texture_filename;
90 _texture_name = copy._texture_name;
91 _uvset_name = copy._uvset_name;
92 _color_gain = copy._color_gain;
93
94 _has_flat_color = copy._has_flat_color;
95 _flat_color = copy._flat_color;
96
97 _projection_type = copy._projection_type;
98 _projection_matrix = copy._projection_matrix;
99 _u_angle = copy._u_angle;
100 _v_angle = copy._v_angle;
101
102 _coverage = copy._coverage;
103 _translate_frame = copy._translate_frame;
104 _rotate_frame = copy._rotate_frame;
105
106 _mirror = copy._mirror;
107 _stagger = copy._stagger;
108 _wrap_u = copy._wrap_u;
109 _wrap_v = copy._wrap_v;
110
111 _blend_type = copy._blend_type;
112 _has_alpha_channel = copy._has_alpha_channel;
113 _keep_color = copy._keep_color;
114 _keep_alpha = copy._keep_alpha;
115 _interpolate = copy._interpolate;
116
117 _repeat_uv = copy._repeat_uv;
118 _offset = copy._offset;
119 _rotate_uv = copy._rotate_uv;
120
121 _is_alpha = copy._is_alpha;
122
123 _map_uvs = copy._map_uvs;
124 _color_object = copy._color_object;
125
126 _opposite = 0;
127 }
128
129 /**
130 *
131 */
132 MayaShaderColorDef::
133 ~MayaShaderColorDef() {
134 if (_color_object != nullptr) {
135 delete _color_object;
136 }
137 }
138
139 /**
140 * Returns a texture matrix corresponding to the texture transforms indicated
141 * by the shader.
142 */
143 LMatrix3d MayaShaderColorDef::
144 compute_texture_matrix() const {
145 LVector2d scale(_repeat_uv[0] / _coverage[0],
146 _repeat_uv[1] / _coverage[1]);
147 LVector2d trans(_offset[0] - _translate_frame[0] / _coverage[0],
148 _offset[1] - _translate_frame[1] / _coverage[1]);
149
150 return
151 (LMatrix3d::translate_mat(LVector2d(-0.5, -0.5)) *
152 LMatrix3d::rotate_mat(_rotate_frame) *
153 LMatrix3d::translate_mat(LVector2d(0.5, 0.5))) *
154 LMatrix3d::scale_mat(scale) *
155 LMatrix3d::translate_mat(trans);
156 }
157
158 /**
159 * Returns true if the shader has a projection in effect.
160 */
161 bool MayaShaderColorDef::
162 has_projection() const {
163 return (_projection_type != PT_off);
164 }
165
166 /**
167 * If the shader has a projection (has_projection() returns true), this
168 * computes the appropriate UV corresponding to the indicated 3-d point.
169 * Seams that might be introduced on polygons that cross quadrants are closed
170 * up by ensuring the point is in the same quadrant as the indicated reference
171 * point.
172 */
173 LTexCoordd MayaShaderColorDef::
174 project_uv(const LPoint3d &pos, const LPoint3d &centroid) const {
175 nassertr(_map_uvs != nullptr, LTexCoordd::zero());
176 return (this->*_map_uvs)(pos * _projection_matrix, centroid * _projection_matrix);
177 }
178
179 /**
180 *
181 */
182 void MayaShaderColorDef::
183 write(std::ostream &out) const {
184 if (_has_texture) {
185 out << " texture filename is " << _texture_filename << "\n"
186 << " texture name is " << _texture_name << "\n"
187 << " uv_set name is " << _uvset_name << "\n"
188 << " coverage is " << _coverage << "\n"
189 << " translate_frame is " << _translate_frame << "\n"
190 << " rotate_frame is " << _rotate_frame << "\n"
191 << " mirror is " << _mirror << "\n"
192 << " stagger is " << _stagger << "\n"
193 << " wrap_u is " << _wrap_u << "\n"
194 << " wrap_v is " << _wrap_v << "\n"
195 << " repeat_uv is " << _repeat_uv << "\n"
196 << " offset is " << _offset << "\n"
197 << " rotate_uv is " << _rotate_uv << "\n"
198 << " color_gain is " << _color_gain << "\n";
199
200 } else if (_has_flat_color) {
201 out << " flat color is " << _flat_color << "\n";
202 }
203 }
204
205 /**
206 * Changes the texture filename stored in the Maya file for this particular
207 * shader.
208 */
209 bool MayaShaderColorDef::
210 reset_maya_texture(const Filename &texture) {
211 if (_color_object != nullptr) {
212 _has_texture = set_string_attribute(*_color_object, "fileTextureName",
213 texture.to_os_generic());
214 _texture_filename = texture;
215
216 if (!_has_texture) {
217 maya_cat.error()
218 << "Unable to reset texture filename.\n";
219 }
220
221 return _has_texture;
222 }
223
224 maya_cat.error()
225 << "Attempt to reset texture on Maya object that has no color set.\n";
226 return false;
227 }
228
229
230 /**
231 * Maya's default uvset name is "map1". Panda's default uvset name is
232 * "default". Otherwise, leaves uvset name untranslated.
233 */
234 string MayaShaderColorDef::
235 get_panda_uvset_name() {
236 if (_uvset_name == "map1") {
237 return "default";
238 }
239 return _uvset_name;
240 }
241
242 /**
243 * This is part of the deprecated codepath. Determines the surface color
244 * specified by the shader. This includes texturing and other advanced shader
245 * properties.
246 */
247 void MayaShaderColorDef::
248 find_textures_legacy(MayaShader *shader, MObject color, bool trans) {
249 LRGBColor color_gain;
250 if (get_vec3_attribute(color, "colorGain", color_gain)) {
251 color_gain[0] = color_gain[0] > 1.0 ? 1.0 : color_gain[0];
252 color_gain[0] = color_gain[0] < 0.0 ? 0.0 : color_gain[0];
253 _color_gain[0] *= color_gain[0];
254 color_gain[1] = color_gain[1] > 1.0 ? 1.0 : color_gain[1];
255 color_gain[1] = color_gain[1] < 0.0 ? 0.0 : color_gain[1];
256 _color_gain[1] *= color_gain[1];
257 color_gain[2] = color_gain[2] > 1.0 ? 1.0 : color_gain[2];
258 color_gain[2] = color_gain[2] < 0.0 ? 0.0 : color_gain[2];
259 _color_gain[2] *= color_gain[2];
260 }
261 PN_stdfloat alpha_gain;
262 if (get_maya_attribute(color, "alphaGain", alpha_gain)) {
263 alpha_gain = alpha_gain > 1.0 ? 1.0 : alpha_gain;
264 alpha_gain = alpha_gain < 0.0 ? 0.0 : alpha_gain;
265 _color_gain[3] *= alpha_gain;
266 }
267 if (color.hasFn(MFn::kFileTexture)) {
268 MFnDependencyNode dfn(color);
269 _color_object = new MObject(color);
270 _texture_name = dfn.name().asChar();
271 string filename;
272 _has_texture = get_string_attribute(color, "fileTextureName", filename);
273 _has_texture = _has_texture && !filename.empty();
274 if (_has_texture) {
275 _texture_filename = Filename::from_os_specific(filename);
276 if (_texture_filename.is_directory()) {
277 maya_cat.warning()
278 << "Shader " << shader->get_name()
279 << " references texture filename " << filename
280 << " which is a directory; clearing.\n";
281 _has_texture = false;
282 set_string_attribute(color, "fileTextureName", "");
283 }
284 }
285
286 get_vec2_attribute(color, "coverage", _coverage);
287 get_vec2_attribute(color, "translateFrame", _translate_frame);
288 get_angle_attribute(color, "rotateFrame", _rotate_frame);
289
290 // get_bool_attribute(color, "alphaIsLuminance", _alpha_is_luminance);
291
292 get_bool_attribute(color, "mirror", _mirror);
293 get_bool_attribute(color, "stagger", _stagger);
294 get_bool_attribute(color, "wrapU", _wrap_u);
295 get_bool_attribute(color, "wrapV", _wrap_v);
296
297 get_vec2_attribute(color, "repeatUV", _repeat_uv);
298 get_vec2_attribute(color, "offset", _offset);
299 get_angle_attribute(color, "rotateUV", _rotate_uv);
300
301 if (!trans) {
302 if (maya_cat.is_debug()) {
303 maya_cat.debug() << "pushed a file texture" << endl;
304 }
305 shader->_color.push_back(this);
306 }
307
308 } else if (color.hasFn(MFn::kProjection)) {
309 if (maya_cat.is_debug()) {
310 maya_cat.debug() << "reading a projection texture" << endl;
311 }
312 // This is a projected texture. We will have to step one level deeper to
313 // find the actual texture.
314 MFnDependencyNode projection_fn(color);
315 MPlug image_plug = projection_fn.findPlug("image");
316 if (!image_plug.isNull()) {
317 MPlugArray image_pa;
318 image_plug.connectedTo(image_pa, true, false);
319
320 for (size_t i = 0; i < image_pa.length(); i++) {
321 find_textures_legacy(shader, image_pa[0].node());
322 }
323 }
324
325 if (!get_mat4d_attribute(color, "placementMatrix", _projection_matrix)) {
326 _projection_matrix = LMatrix4d::ident_mat();
327 }
328
329 // The uAngle and vAngle might be used for certain kinds of projections.
330 if (!get_angle_attribute(color, "uAngle", _u_angle)) {
331 _u_angle = 360.0;
332 }
333 if (!get_angle_attribute(color, "vAngle", _v_angle)) {
334 _v_angle = 180.0;
335 }
336
337 string type;
338 if (get_enum_attribute(color, "projType", type)) {
339 set_projection_type(type);
340 }
341
342 } else if (color.hasFn(MFn::kLayeredTexture)) {
343 if (maya_cat.is_debug()) {
344 maya_cat.debug() << "Found layered texture" << endl;
345 }
346
347 int blendValue;
348 MStatus status;
349 MPlugArray color_pa;
350 MFnDependencyNode layered_fn(color);
351 layered_fn.getConnections(color_pa);
352 MPlug inputsPlug = layered_fn.findPlug("inputs", &status);
353 MPlug blendModePlug = layered_fn.findPlug("blendMode", &status);
354
355 if (maya_cat.is_debug()) {
356 maya_cat.debug() << "number of connections: " << color_pa.length() << endl;
357 }
358 bool first = true;
359 BlendType bt = BT_modulate;
360 for (size_t i=0; i<color_pa.length(); ++i) {
361 MPlug pl = color_pa[i];
362 MPlugArray pla;
363 pl.connectedTo(pla, true, false);
364
365 // First figure out the blend mode intended for this shadercolordef
366 int li = pl.logicalIndex();
367 if (li > -1) {
368 // found a blend mode
369 if (maya_cat.is_spam()) {
370 MString name = inputsPlug.name();
371 maya_cat.spam() << "*** Start doIt... ***" << endl;
372 maya_cat.spam() << "inputsPlug Name: " << name.asChar() << endl;
373 }
374 status = blendModePlug.selectAncestorLogicalIndex(li,inputsPlug);
375 blendModePlug.getValue(blendValue);
376
377 if (maya_cat.is_spam()) {
378 MString name = blendModePlug.name();
379 maya_cat.spam()
380 << name.asChar() << ": has value " << blendValue << endl;
381 }
382
383 MFnEnumAttribute blendModeEnum(blendModePlug);
384 MString blendName = blendModeEnum.fieldName(blendValue, &status);
385
386 switch (blendValue) {
387 case 1:
388 bt = BT_decal;
389 get_bool_attribute(color, "interpolate", _interpolate);
390 maya_cat.info() << "interpolate: " << _interpolate << endl;
391 _keep_color = true;
392 break;
393 case 6:
394 bt = BT_modulate;
395 get_bool_attribute(color, "keepAlpha", _keep_alpha);
396 maya_cat.info() << "keepAlpha: " << _keep_alpha << endl;
397 break;
398 case 4:
399 bt = BT_add;
400 break;
401 }
402
403 if (maya_cat.is_info()) {
404 MString name = layered_fn.name();
405 maya_cat.info() << name.asChar() << ": blendMode used " << blendName.asChar() << endl;
406 if (maya_cat.is_spam()) {
407 maya_cat.spam() << "*** END doIt... ***" << endl;
408 }
409 }
410
411 // advance to the next plug, because that is where the shader info are
412 pl = color_pa[++i];
413 pl.connectedTo(pla, true, false);
414 }
415 for (size_t j=0; j<pla.length(); ++j) {
416 // maya_cat.debug() << pl.name() << " is(pl) " <<
417 // pl.node().apiTypeStr() << endl; maya_cat.debug() << pla[j].name()
418 // << " is(pla) " << pla[j].node().apiTypeStr() << endl;
419 string pla_name = pla[j].name().asChar();
420 // sometimes, by default, maya gives a outAlpha on subsequent plugs,
421 // ignore that
422 if (pla_name.find("outAlpha") != string::npos) {
423 // top texture has an alpha channel, so make sure that this alpha is
424 // retained by egg file
425 if (maya_cat.is_debug()) {
426 maya_cat.debug() << pl.name().asChar() << ":has alpha channel" << pla_name << endl;
427 }
428 _has_alpha_channel = true;
429 continue;
430 }
431 if (!first) {
432 if (maya_cat.is_debug()) {
433 maya_cat.debug() << pl.name().asChar() << " next:connectedTo: " << pla_name << endl;
434 }
435 MayaShaderColorDef *color_p = new MayaShaderColorDef;
436 color_p->find_textures_legacy(shader, pla[j].node());
437 color_p->_blend_type = bt;
438 size_t loc = color_p->_texture_name.find('.',0);
439 if (loc != string::npos) {
440 color_p->_texture_name.resize(loc);
441 }
442 if (maya_cat.is_debug()) {
443 maya_cat.debug() << "uv_name : " << color_p->_texture_name << endl;
444 }
445 }
446 else {
447 if (maya_cat.is_debug()) {
448 maya_cat.debug() << pl.name().asChar() << " first:connectedTo: " << pla_name << endl;
449 }
450 find_textures_legacy(shader, pla[j].node());
451 _texture_name.assign(pla[j].name().asChar());
452 _blend_type = bt;
453 size_t loc = _texture_name.find('.',0);
454 if (loc != string::npos) {
455 _texture_name.resize(loc);
456 }
457 if (maya_cat.is_debug()) {
458 maya_cat.debug() << "uv_name : " << _texture_name << endl;
459 }
460 first = false;
461 }
462 }
463 }
464 } else {
465 // This shader wasn't understood.
466 if (maya_cat.is_debug()) {
467 maya_cat.info()
468 << "**Don't know how to interpret color attribute type "
469 << color.apiTypeStr() << "\n";
470
471 } else {
472 // If we don't have a heavy verbose count, only report each type of
473 // unsupported shader once.
474 static pset<MFn::Type> bad_types;
475 if (bad_types.insert(color.apiType()).second) {
476 maya_cat.info()
477 << "**Don't know how to interpret color attribute type "
478 << color.apiTypeStr() << "\n";
479 }
480 }
481 }
482 }
483
484 /**
485 * Search to find any file textures that lead into the given input plug. Any
486 * textures found will be added to the provided MayaShaderColorList.
487 */
488 void MayaShaderColorDef::
489 find_textures_modern(const string &shadername, MayaShaderColorList &list, MPlug inplug, bool is_alpha) {
490
491 MPlugArray outplugs;
492 inplug.connectedTo(outplugs, true, false);
493 if (outplugs.length() == 0) {
494 return;
495 }
496 if (outplugs.length() > 1) {
497 // Only one output plug should be connected to a given input plug.
498 maya_cat.warning()
499 << "Shader " << shadername << " has weird plug connections.\n";
500 return;
501 }
502 MPlug outplug = outplugs[0];
503 MObject source = outplug.node();
504 MFnDependencyNode sourceFn(source);
505
506 if (source.hasFn(MFn::kFileTexture)) {
507
508 string filename;
509 bool hasfn = get_string_attribute(source, "fileTextureName", filename);
510 if ((!hasfn) || (filename.empty())) {
511 maya_cat.warning()
512 << "Shader " << shadername << " references file texture "
513 << "with no file name, ignoring invalid file texture.\n";
514 return;
515 }
516 Filename fn = filename;
517 if (fn.is_directory()) {
518 maya_cat.warning()
519 << "Shader " << shadername << " references file name "
520 << filename << " which is a directory, ignoring it.\n";
521 return;
522 }
523
524 MayaShaderColorDef *def = new MayaShaderColorDef;
525
526 def->_color_object = new MObject(source);
527 def->_texture_filename = Filename::from_os_specific(filename);
528 def->_texture_name = sourceFn.name().asChar();
529
530 get_vec2_attribute(source, "coverage", def->_coverage);
531 get_vec2_attribute(source, "translateFrame", def->_translate_frame);
532 get_angle_attribute(source, "rotateFrame", def->_rotate_frame);
533
534 get_bool_attribute(source, "mirror", def->_mirror);
535 get_bool_attribute(source, "stagger", def->_stagger);
536 get_bool_attribute(source, "wrapU", def->_wrap_u);
537 get_bool_attribute(source, "wrapV", def->_wrap_v);
538
539 get_vec2_attribute(source, "repeatUV", def->_repeat_uv);
540 get_vec2_attribute(source, "offset", def->_offset);
541 get_angle_attribute(source, "rotateUV", def->_rotate_uv);
542
543 LRGBColor color_gain;
544 PN_stdfloat alpha_gain;
545 get_vec3_attribute(source, "colorGain", color_gain);
546 get_maya_attribute(source, "alphaGain", alpha_gain);
547 def->_color_gain[0] = color_gain[0];
548 def->_color_gain[1] = color_gain[1];
549 def->_color_gain[2] = color_gain[2];
550 def->_color_gain[3] = alpha_gain;
551
552 def->_is_alpha = is_alpha;
553
554 if (maya_cat.is_debug()) {
555 maya_cat.debug() << "pushed a file texture" << endl;
556 }
557 list.push_back(def);
558
559 return;
560 }
561
562 if (source.hasFn(MFn::kProjection)) {
563 // This is a projected texture. We will have to step one level deeper to
564 // find the actual texture.
565 size_t before = list.size();
566 MPlug image_plug = sourceFn.findPlug("image");
567 if (!image_plug.isNull()) {
568 MPlugArray image_pa;
569 image_plug.connectedTo(image_pa, true, false);
570
571 for (size_t i = 0; i < image_pa.length(); i++) {
572 find_textures_modern(shadername, list, image_pa[0], is_alpha);
573 }
574 }
575
576 // Now apply any inherited attributes to all textures found.
577
578 for (size_t i=before; i<list.size(); i++) {
579 MayaShaderColorDef *def = list[i];
580
581 if (!get_mat4d_attribute(source, "placementMatrix", def->_projection_matrix)) {
582 def->_projection_matrix = LMatrix4d::ident_mat();
583 }
584
585 // The uAngle and vAngle might be used for certain kinds of projections.
586 if (!get_angle_attribute(source, "uAngle", def->_u_angle)) {
587 def->_u_angle = 360.0;
588 }
589 if (!get_angle_attribute(source, "vAngle", def->_v_angle)) {
590 def->_v_angle = 180.0;
591 }
592
593 string type;
594 if (get_enum_attribute(source, "projType", type)) {
595 def->set_projection_type(type);
596 }
597 }
598 return;
599 }
600
601 if (source.hasFn(MFn::kLayeredTexture)) {
602 if (maya_cat.is_debug()) {
603 maya_cat.debug() << "Found layered texture" << endl;
604 }
605
606 MPlug inputsPlug = sourceFn.findPlug("inputs");
607 size_t nlayers = inputsPlug.numElements();
608 for (size_t layer=0; layer<nlayers; layer++) {
609 MPlug elt = inputsPlug.elementByPhysicalIndex(layer);
610 MPlug color;
611 MPlug blend;
612 for (size_t j=0; j<elt.numChildren(); j++) {
613 MPlug child = elt.child(j);
614 MFnAttribute att(child.attribute());
615 if (att.name() == "color") color = child;
616 if (att.name() == "blendMode") blend = child;
617 }
618 if (color.isNull() || blend.isNull()) {
619 maya_cat.warning() << "Invalid layered texture - bad inputs.\n";
620 return;
621 }
622 size_t before = list.size();
623 find_textures_modern(shadername, list, color, is_alpha);
624 int blendValue;
625 blend.getValue(blendValue);
626 for (size_t sub=before; sub<list.size(); sub++) {
627 MayaShaderColorDef *def = list[sub];
628 switch (blendValue) {
629 case 1: def->_blend_type = BT_decal; break;
630 case 6: def->_blend_type = BT_modulate; break;
631 case 4: def->_blend_type = BT_add; break;
632 }
633 }
634 }
635 return;
636 }
637
638 if (source.apiType() == MFn::kReverse) {
639 MPlug input_plug = sourceFn.findPlug("input");
640 find_textures_modern(shadername, list, input_plug, is_alpha);
641 return;
642 }
643
644 // This shader wasn't understood.
645 if (maya_cat.is_debug()) {
646 maya_cat.info()
647 << "**Don't know how to interpret color attribute type "
648 << source.apiTypeStr() << "\n";
649 } else {
650 // If we don't have a heavy verbose count, only report each type of
651 // unsupported shader once.
652 static pset<MFn::Type> bad_types;
653 if (bad_types.insert(source.apiType()).second) {
654 maya_cat.warning()
655 << "Don't know how to export a shader of type "
656 << source.apiTypeStr() << " " << sourceFn.type() << "\n";
657 }
658 }
659 }
660
661 /**
662 * Sets up the shader to apply UV's according to the indicated projection
663 * type.
664 */
665 void MayaShaderColorDef::
666 set_projection_type(const string &type) {
667 if (cmp_nocase(type, "planar") == 0) {
668 _projection_type = PT_planar;
669 _map_uvs = &MayaShaderColorDef::map_planar;
670
671 // The Planar projection normally projects to a range (-1, 1) in both
672 // axes. Scale this into our UV range of (0, 1).
673 _projection_matrix = _projection_matrix * LMatrix4d(0.5, 0.0, 0.0, 0.0,
674 0.0, 0.5, 0.0, 0.0,
675 0.0, 0.0, 1.0, 0.0,
676 0.5, 0.5, 0.0, 1.0);
677
678 } else if (cmp_nocase(type, "cylindrical") == 0) {
679 _projection_type = PT_cylindrical;
680 _map_uvs = &MayaShaderColorDef::map_cylindrical;
681
682 // The cylindrical projection is orthographic in the Y axis; scale the
683 // range (-1, 1) in this axis into our UV range (0, 1).
684 _projection_matrix = _projection_matrix * LMatrix4d(1.0, 0.0, 0.0, 0.0,
685 0.0, 0.5, 0.0, 0.0,
686 0.0, 0.0, 1.0, 0.0,
687 0.0, 0.5, 0.0, 1.0);
688
689 } else if (cmp_nocase(type, "spherical") == 0) {
690 _projection_type = PT_spherical;
691 _map_uvs = &MayaShaderColorDef::map_spherical;
692
693 } else {
694 // Other projection types are currently unimplemented by the converter.
695 maya_cat.error()
696 << "Don't know how to handle type " << type << " projections.\n";
697 _projection_type = PT_off;
698 _map_uvs = nullptr;
699 }
700 }
701
702 /**
703 * Computes a UV based on the given point in space, using a planar projection.
704 */
705 LPoint2d MayaShaderColorDef::
706 map_planar(const LPoint3d &pos, const LPoint3d &) const {
707 // A planar projection is about as easy as can be. We ignore the Z axis,
708 // and project the point into the XY plane. Done.
709 return LPoint2d(pos[0], pos[1]);
710 }
711
712 /**
713 * Computes a UV based on the given point in space, using a spherical
714 * projection.
715 */
716 LPoint2d MayaShaderColorDef::
717 map_spherical(const LPoint3d &pos, const LPoint3d &centroid) const {
718 // To compute the x position on the frame, we only need to consider the
719 // angle of the vector about the Y axis. Project the vector into the XZ
720 // plane to do this.
721
722 LVector2d xz(pos[0], pos[2]);
723 double xz_length = xz.length();
724
725 if (xz_length < 0.01) {
726 // If we have a point on or near either pole, we've got problems. This
727 // point maps to the entire bottom edge of the image, so which U value
728 // should we choose? It does make a difference, especially if we have a
729 // number of polygons around the south pole that all share the common
730 // vertex.
731
732 // We choose the U value based on the polygon's centroid.
733 xz.set(centroid[0], centroid[2]);
734 }
735
736 // Now, if the polygon crosses the seam, we also have problems. Make sure
737 // that the u value is in the same half of the texture as the centroid's u
738 // value.
739 double u = rad_2_deg(atan2(xz[0], xz[1])) / (2.0 * _u_angle);
740 double c = rad_2_deg(atan2(centroid[0], centroid[2])) / (2.0 * _u_angle);
741
742 if (u - c > 0.5) {
743 u -= floor(u - c + 0.5);
744 } else if (u - c < -0.5) {
745 u += floor(c - u + 0.5);
746 }
747
748 // Now rotate the vector into the YZ plane, and the V value is based on the
749 // latitude: the angle about the X axis.
750 LVector2d yz(pos[1], xz_length);
751 double v = rad_2_deg(atan2(yz[0], yz[1])) / (2.0 * _v_angle);
752
753 LPoint2d uv(u - 0.5, v - 0.5);
754
755 nassertr(fabs(u - c) <= 0.5, uv);
756 return uv;
757 }
758
759 /**
760 * Computes a UV based on the given point in space, using a cylindrical
761 * projection.
762 */
763 LPoint2d MayaShaderColorDef::
764 map_cylindrical(const LPoint3d &pos, const LPoint3d &centroid) const {
765 // This is almost identical to the spherical projection, except for the
766 // computation of V.
767
768 LVector2d xz(pos[0], pos[2]);
769 double xz_length = xz.length();
770
771 if (xz_length < 0.01) {
772 /*
773 * A cylindrical mapping has the same singularity problem at the pole as a
774 * spherical mapping does: points at the pole do not map to a single point on
775 * the texture. (It's technically a slightly different problem: in a
776 * cylindrical mapping, points at the pole do not map to any point on the
777 * texture, while in a spherical mapping, points at the pole map to the top or
778 * bottom edge of the texture. But this is a technicality that doesn't really
779 * apply to us.) We still solve it the same way: if our point is at or near
780 * the pole, compute the angle based on the centroid of the polygon (which we
781 * assume is further from the pole).
782 */
783 xz.set(centroid[0], centroid[2]);
784 }
785
786 // And cylinders do still have a seam at the back.
787 double u = rad_2_deg(atan2(xz[0], xz[1])) / _u_angle;
788 double c = rad_2_deg(atan2(centroid[0], centroid[2])) / _u_angle;
789
790 if (u - c > 0.5) {
791 u -= floor(u - c + 0.5);
792 } else if (u - c < -0.5) {
793 u += floor(c - u + 0.5);
794 }
795
796 // For a cylindrical mapping, the V value comes directly from Y. Easy.
797 LPoint2d uv(u - 0.5, pos[1]);
798
799 nassertr(fabs(u - c) <= 0.5, uv);
800 return uv;
801 }
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::from_os_specific
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328
Filename::to_os_generic
std::string to_os_generic() const
This is similar to to_os_specific(), but it is designed to generate a filename that can be understood...
Definition: filename.cxx:1182
Filename::is_directory
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1359
MayaShaderColorDef
This defines the various attributes that Maya may associate with the "color" channel for a particular...
Definition: mayaShaderColorDef.h:34
MayaShaderColorDef::reset_maya_texture
bool reset_maya_texture(const Filename &texture)
Changes the texture filename stored in the Maya file for this particular shader.
Definition: mayaShaderColorDef.cxx:210
MayaShaderColorDef::compute_texture_matrix
LMatrix3d compute_texture_matrix() const
Returns a texture matrix corresponding to the texture transforms indicated by the shader.
Definition: mayaShaderColorDef.cxx:144
MayaShaderColorDef::has_projection
bool has_projection() const
Returns true if the shader has a projection in effect.
Definition: mayaShaderColorDef.cxx:162
MayaShaderColorDef::get_panda_uvset_name
std::string get_panda_uvset_name()
Maya's default uvset name is "map1".
Definition: mayaShaderColorDef.cxx:235
MayaShaderColorDef::project_uv
LTexCoordd project_uv(const LPoint3d &pos, const LPoint3d &ref_point) const
If the shader has a projection (has_projection() returns true), this computes the appropriate UV corr...
Definition: mayaShaderColorDef.cxx:174
MayaShader
Corresponds to a single "shader" in Maya.
Definition: mayaShader.h:30
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
pvector< MayaShaderColorDef * >
config_maya.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mayaShaderColorDef.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mayaShader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_string_attribute
bool get_string_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the named string attribute from the MObject.
Definition: maya_funcs.cxx:440
get_angle_attribute
bool get_angle_attribute(MObject &node, const string &attribute_name, double &value)
Extracts the named angle in degrees from the MObject.
Definition: maya_funcs.cxx:179
set_string_attribute
bool set_string_attribute(MObject &node, const string &attribute_name, const string &value)
Sets the named string attribute on the MObject.
Definition: maya_funcs.cxx:469
get_vec3_attribute
bool get_vec3_attribute(MObject &node, const string &attribute_name, LVecBase3 &value)
Extracts the named three-component vector from the MObject.
Definition: maya_funcs.cxx:232
get_enum_attribute
bool get_enum_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the enum attribute from the MObject as a string value.
Definition: maya_funcs.cxx:398
get_mat4d_attribute
bool get_mat4d_attribute(MObject &node, const string &attribute_name, LMatrix4d &value)
Extracts the named 4x4 matrix from the MObject.
Definition: maya_funcs.cxx:337
get_vec2_attribute
bool get_vec2_attribute(MObject &node, const string &attribute_name, LVecBase2 &value)
Extracts the named two-component vector from the MObject.
Definition: maya_funcs.cxx:197
get_bool_attribute
bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value)
Extracts the named boolean attribute from the MObject.
Definition: maya_funcs.cxx:157
maya_funcs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
post_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pre_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pset.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.