Panda3D
Loading...
Searching...
No Matches
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
32using std::endl;
33using std::string;
34
35/**
36 *
37 */
38MayaShaderColorDef::
39MayaShaderColorDef() {
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 */
86MayaShaderColorDef::
87MayaShaderColorDef(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 */
132MayaShaderColorDef::
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 */
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 */
162has_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 */
174project_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 */
182void MayaShaderColorDef::
183write(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 */
210reset_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 */
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 */
247void MayaShaderColorDef::
248find_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 }
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 */
488void MayaShaderColorDef::
489find_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
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 */
665void MayaShaderColorDef::
666set_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 */
705LPoint2d MayaShaderColorDef::
706map_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 */
716LPoint2d MayaShaderColorDef::
717map_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 */
763LPoint2d MayaShaderColorDef::
764map_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}
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
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
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...
bool is_directory() const
Returns true if the filename exists on the physical disk and is a directory name, false otherwise.
This defines the various attributes that Maya may associate with the "color" channel for a particular...
bool reset_maya_texture(const Filename &texture)
Changes the texture filename stored in the Maya file for this particular shader.
LMatrix3d compute_texture_matrix() const
Returns a texture matrix corresponding to the texture transforms indicated by the shader.
bool has_projection() const
Returns true if the shader has a projection in effect.
std::string get_panda_uvset_name()
Maya's default uvset name is "map1".
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...
Corresponds to a single "shader" in Maya.
Definition mayaShader.h:30
This is our own Panda specialization on the default STL set.
Definition pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool get_string_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the named string attribute from the MObject.
bool get_angle_attribute(MObject &node, const string &attribute_name, double &value)
Extracts the named angle in degrees from the MObject.
bool set_string_attribute(MObject &node, const string &attribute_name, const string &value)
Sets the named string attribute on the MObject.
bool get_vec3_attribute(MObject &node, const string &attribute_name, LVecBase3 &value)
Extracts the named three-component vector from the MObject.
bool get_enum_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the enum attribute from the MObject as a string value.
bool get_mat4d_attribute(MObject &node, const string &attribute_name, LMatrix4d &value)
Extracts the named 4x4 matrix from the MObject.
bool get_vec2_attribute(MObject &node, const string &attribute_name, LVecBase2 &value)
Extracts the named two-component vector from the MObject.
bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value)
Extracts the named boolean attribute from the MObject.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.