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  */
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  */
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  */
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  */
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  */
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 
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 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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...
Definition: filename.cxx:1182
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1359
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.
Definition: maya_funcs.cxx:440
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
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
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
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
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
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
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
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.