Panda3D
mayaShader.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 mayaShader.cxx
10  * @author drose
11  * @date 2000-02-01
12  * Modified 19Mar10 by ETC PandaSE team (see
13  * header comment for mayaToEgg.cxx for details)
14  */
15 
16 #include "mayaShader.h"
17 #include "maya_funcs.h"
18 #include "config_maya.h"
19 #include "string_utils.h"
20 #include "pnmImageHeader.h" // for lumin_red, etc.
21 #include "pset.h"
22 
23 #include "pre_maya_include.h"
24 #include <maya/MFnDependencyNode.h>
25 #include <maya/MFnLambertShader.h>
26 #include <maya/MFnPhongShader.h>
27 #include <maya/MFnMesh.h>
28 #include <maya/MPlug.h>
29 #include <maya/MPlugArray.h>
30 #include <maya/MColor.h>
31 #include <maya/MObject.h>
32 #include <maya/MStatus.h>
33 #include "post_maya_include.h"
34 
35 using std::endl;
36 using std::string;
37 
38 /**
39  * Reads the Maya "shading engine" to determine the relevant shader
40  * properties.
41  */
43 MayaShader(MObject engine, bool legacy_shader) {
44  MFnDependencyNode engine_fn(engine);
45 
46  set_name(engine_fn.name().asChar());
47 
48  if (maya_cat.is_debug()) {
49  maya_cat.debug()
50  << "Reading shading engine " << get_name() << "\n";
51  }
52  _legacy_mode = false;
53  _flat_color.set(1,1,1,1);
54 
55  MPlug shader_plug = engine_fn.findPlug("surfaceShader");
56  bool found_shader = false;
57  if (!shader_plug.isNull()) {
58  MPlugArray shader_pa;
59  shader_plug.connectedTo(shader_pa, true, false);
60  maya_cat.spam() << "shader plug connected to: " << shader_pa.length() << endl;
61  for (size_t i = 0; i < shader_pa.length() && !found_shader; i++) {
62  MObject shader = shader_pa[0].node();
63  if (shader.hasFn(MFn::kPhong)) {
64  if (legacy_shader) {
65  found_shader = find_textures_legacy(shader);
66  } else {
67  found_shader = find_textures_modern(shader);
68  }
69  } else if (shader.hasFn(MFn::kLambert)) {
70  found_shader = find_textures_legacy(shader);
71  if (found_shader) {
72  _legacy_mode = true;
73  }
74  } else if (shader.hasFn(MFn::kSurfaceShader)) {
75  found_shader = find_textures_legacy(shader);
76  if (found_shader) {
77  _legacy_mode = true;
78  }
79  } else {
80  maya_cat.warning() <<
81  "Unrecognized shader type: only lambert and phong supported (lambert deprecated).\n";
82  }
83  }
84  }
85 }
86 
87 /**
88  *
89  */
90 MayaShader::
91 ~MayaShader() {
92 }
93 
94 /**
95  *
96  */
97 void MayaShader::
98 output(std::ostream &out) const {
99  out << "Shader " << get_name();
100 }
101 
102 /**
103  *
104  */
105 void MayaShader::
106 write(std::ostream &out) const {
107  out << "Shader " << get_name() << "\n";
108 }
109 
110 /**
111  * This is part of the deprecated codepath. return the color def i.e.
112  * texture at idx
113  */
115 get_color_def(size_t idx) const {
116  if (_color.size() > 0)
117  return _color[idx];
118  else
119  return nullptr;
120 }
121 /**
122  * Returns the overall color of the shader as a single-precision rgba value,
123  * where the alpha component represents transparency according to the Panda
124  * convention. If no overall color is specified (_has_flat_color is not
125  * true), this returns white.
126  *
127  * Normally, Maya makes texture color override the flat color, so if a texture
128  * is also applied (_has_texture is true), this value is not used by Maya.
129  */
131 get_rgba(size_t idx) const {
132  LColor rgba(1.0f, 1.0f, 1.0f, 1.0f);
133 
134  if (_color.size() && _color[idx]->_has_flat_color) {
135  rgba[0] = (PN_stdfloat)_color[idx]->_flat_color[0];
136  rgba[1] = (PN_stdfloat)_color[idx]->_flat_color[1];
137  rgba[2] = (PN_stdfloat)_color[idx]->_flat_color[2];
138  }
139 
140  if (_transparency._has_flat_color) {
141  // Maya supports colored transparency, but we only support grayscale
142  // transparency. Use the pnmimage constants to convert color to
143  // grayscale.
144  double trans =
145  _transparency._flat_color[0] * lumin_red +
146  _transparency._flat_color[1] * lumin_grn +
147  _transparency._flat_color[2] * lumin_blu;
148  rgba[3] = 1.0f - (PN_stdfloat)trans;
149  }
150 
151  return rgba;
152 }
153 
154 /**
155  * Recalculates the all_maps list.
156  */
158 collect_maps() {
159  _all_maps.clear();
160 
161  for (size_t i=0; i<_color_maps.size(); i++) {
162  _all_maps.push_back(_color_maps[i]);
163  }
164  for (size_t i=0; i<_trans_maps.size(); i++) {
165  _all_maps.push_back(_trans_maps[i]);
166  }
167  for (size_t i=0; i<_normal_maps.size(); i++) {
168  _all_maps.push_back(_normal_maps[i]);
169  }
170  for (size_t i=0; i<_glow_maps.size(); i++) {
171  _all_maps.push_back(_glow_maps[i]);
172  }
173  for (size_t i=0; i<_gloss_maps.size(); i++) {
174  _all_maps.push_back(_gloss_maps[i]);
175  }
176  for (size_t i=0; i<_height_maps.size(); i++) {
177  _all_maps.push_back(_height_maps[i]);
178  }
179 
180  for (size_t i=0; i<_color.size(); i++) {
181  if (_color[i]->_has_texture) {
182  _all_maps.push_back(_color[i]);
183  }
184  }
185  if (_transparency._has_texture) {
186  _all_maps.push_back(&_transparency);
187  }
188 }
189 
190 /**
191  * Locates all file textures leading into the given shader.
192  */
193 bool MayaShader::
194 find_textures_modern(MObject shader) {
195  if (!shader.hasFn(MFn::kPhong)) {
196  maya_cat.warning()
197  << "The new codepath expects to see phong shaders only.\n";
198  return false;
199  }
200  MStatus status;
201  MFnPhongShader phong_fn(shader);
202  MFnDependencyNode shader_fn(shader);
203 
204  if (maya_cat.is_spam()) {
205  maya_cat.spam()
206  << " Reading modern surface shader " << shader_fn.name().asChar() << "\n";
207  }
208 
209  string n = shader_fn.name().asChar();
210 
211  MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("color"), false);
212  if (_color_maps.size() == 0) {
213  MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("colorR"), false);
214  }
215  MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparency"), true);
216  if (_trans_maps.size() == 0) {
217  MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparencyR"), true);
218  }
219  MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCamera"), false);
220  if (_normal_maps.size() == 0) {
221  MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCameraR"), false);
222  }
223  MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColor"), true);
224  if (_gloss_maps.size() == 0) {
225  MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColorR"), true);
226  }
227  MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescence"), true);
228  if (_glow_maps.size() == 0) {
229  MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescenceR"), true);
230  }
231  MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThickness"), true);
232  if (_height_maps.size() == 0) {
233  MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThicknessR"), true);
234  }
235 
236  collect_maps();
237 
238  MColor color = phong_fn.color(&status);
239  if (status) {
240  _flat_color.set(color.r, color.g, color.b, color.a);
241  }
242 
243  color = phong_fn.transparency(&status);
244  if (status) {
245  _flat_color[3] = 1.0 - ((color[0] + color[1] + color[2]) * (1.0/3.0));
246  }
247  return true;
248 }
249 
250 /**
251  * Assigns the uvset_name of each MayaShaderColorDef using the given file-to-
252  * uvset map.
253  */
256  for (size_t i=0; i<_all_maps.size(); i++) {
257  MayaShaderColorDef *def = _all_maps[i];
258  MayaFileToUVSetMap::iterator p = map.find(def->_texture_name);
259  if (p == map.end()) {
260  def->_uvset_name = "map1";
261  } else {
262  def->_uvset_name = (*p).second;
263  }
264  }
265 
266  calculate_pairings();
267 }
268 
269 /**
270  * For each Alpha texture, try to find an RGB texture that has the same
271  * properties. Attempt to make it so that the alpha texture isn't a separate
272  * texture, but rather, an Alpha-Filename associated with an existing texture.
273  */
274 void MayaShader::
275 calculate_pairings() {
276 
277  if (_legacy_mode) {
278  return;
279  }
280 
281  for (size_t i=0; i<_all_maps.size(); i++) {
282  _all_maps[i]->_opposite = 0;
283  }
284 
285  bool using_transparency = (_trans_maps.size() > 0);
286 
287  for (int retry=0; retry<2; retry++) {
288  bool perfect=(retry==0);
289  for (size_t i=0; i<_color_maps.size(); i++) {
290  if ((_color_maps[i]->_blend_type == MayaShaderColorDef::BT_modulate)||
291  (_color_maps[i]->_blend_type == MayaShaderColorDef::BT_unspecified)) {
292  for (size_t j=0; j<_trans_maps.size(); j++) {
293  try_pair(_color_maps[i], _trans_maps[j], perfect);
294  }
295  }
296  }
297  }
298 
299  if (!using_transparency) {
300  for (int retry=0; retry<2; retry++) {
301  bool perfect=(retry==0);
302  for (size_t i=0; i<_color_maps.size(); i++) {
303  for (size_t j=0; j<_glow_maps.size(); j++) {
304  try_pair(_color_maps[i], _glow_maps[j], perfect);
305  }
306  for (size_t j=0; j<_gloss_maps.size(); j++) {
307  try_pair(_color_maps[i], _gloss_maps[j], perfect);
308  }
309  }
310  }
311  }
312 
313  for (int retry=0; retry<2; retry++) {
314  bool perfect=(retry==0);
315  for (size_t i=0; i<_normal_maps.size(); i++) {
316  for (size_t j=0; j<_height_maps.size(); j++) {
317  try_pair(_normal_maps[i], _height_maps[j], perfect);
318  }
319  }
320  }
321 
322  for (size_t i=0; i<_normal_maps.size(); i++) {
323  _normal_maps[i]->_blend_type = MayaShaderColorDef::BT_normal;
324  }
325  for (size_t i=0; i<_glow_maps.size(); i++) {
326  if (_glow_maps[i]->_opposite) {
327  _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified;
328  _glow_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_glow;
329  } else {
330  _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_glow;
331  }
332  }
333  for (size_t i=0; i<_gloss_maps.size(); i++) {
334  if (_gloss_maps[i]->_opposite) {
335  _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified;
336  _gloss_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_gloss;
337  } else {
338  _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_gloss;
339  }
340  }
341  for (size_t i=0; i<_height_maps.size(); i++) {
342  if (_height_maps[i]->_opposite) {
343  _height_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified;
344  _height_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_normal_height;
345  } else {
346  _height_maps[i]->_blend_type = MayaShaderColorDef::BT_height;
347  }
348  }
349  for (size_t i=0; i<_trans_maps.size(); i++) {
350  if (_trans_maps[i]->_opposite) {
351  _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified;
352  _trans_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate;
353  } else {
354  _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_modulate;
355  }
356  }
357 }
358 
359 /**
360  * Try to associate an RGB tex with an Alpha tex.
361  */
362 bool MayaShader::try_pair(MayaShaderColorDef *map1,
363  MayaShaderColorDef *map2,
364  bool perfect) {
365  if ((map1->_opposite)||(map2->_opposite)) {
366  // one of the maps is already paired
367  return false;
368  }
369  if (perfect) {
370  if (map1->_texture_filename != map2->_texture_filename) {
371  // perfect mode requires a filename match.
372  return false;
373  }
374  } else {
375  string pre1 = get_file_prefix(map1->_texture_filename);
376  string pre2 = get_file_prefix(map2->_texture_filename);
377  if (pre1 != pre2) {
378  // imperfect mode requires a filename prefix match.
379  return false;
380  }
381  }
382 
383  if ((map1->_projection_type != map2->_projection_type) ||
384  (map1->_projection_matrix != map2->_projection_matrix) ||
385  (map1->_u_angle != map2->_u_angle) ||
386  (map1->_v_angle != map2->_v_angle) ||
387  (map1->_uvset_name != map2->_uvset_name) ||
388  (map1->_mirror != map2->_mirror) ||
389  (map1->_stagger != map2->_stagger) ||
390  (map1->_wrap_u != map2->_wrap_u) ||
391  (map1->_wrap_v != map2->_wrap_v) ||
392  (map1->_repeat_uv != map2->_repeat_uv) ||
393  (map1->_offset != map2->_offset) ||
394  (map1->_rotate_uv != map2->_rotate_uv)) {
395  return false;
396  }
397  // Pairing successful.
398  map1->_opposite = map2;
399  map2->_opposite = map1;
400  return true;
401 }
402 
403 /**
404  * Try to associate an RGB tex with an Alpha tex.
405  */
406 string MayaShader::
407 get_file_prefix(const string &fn) {
409  string base = pfn.get_basename_wo_extension();
410  size_t offs = base.find("_");
411  if (offs != string::npos) {
412  base = base.substr(0, offs);
413  }
414  offs = base.find("-");
415  if (offs != string::npos) {
416  base = base.substr(0, offs);
417  }
418  return base;
419 }
420 
421 /**
422  * This is part of the legacy codepath. Extracts out the shading information
423  * from the Maya surface shader.
424  */
425 bool MayaShader::
426 find_textures_legacy(MObject shader) {
427  MStatus status;
428  MFnDependencyNode shader_fn(shader);
429 
430  if (maya_cat.is_spam()) {
431  maya_cat.spam()
432  << " Reading legacy surface shader " << shader_fn.name().asChar() << "\n";
433  }
434 
435  // First, check for a connection to the color attribute. This could be a
436  // texture map or something, and will override whatever the shader says for
437  // color.
438 
439  MPlug color_plug = shader_fn.findPlug("color");
440  if (color_plug.isNull()) {
441  // Or maybe a connection to outColor. Not sure how this differs from just
442  // color, but empirically it seems that either might be used.
443  color_plug = shader_fn.findPlug("outColor");
444  }
445 
446  if (!color_plug.isNull()) {
447  MPlugArray color_pa;
448  color_plug.connectedTo(color_pa, true, false);
449 
450  MayaShaderColorDef *color_p = new MayaShaderColorDef;
451  for (size_t i = 0; i < color_pa.length(); i++) {
452  maya_cat.spam() << "color_pa[" << i << "]:" << color_pa[i].name().asChar() << endl;
453  color_p->find_textures_legacy(this, color_pa[0].node());
454  }
455 
456  if (color_pa.length() < 1) {
457  // assign a blank default color to this shader
458  maya_cat.spam() << shader_fn.name().asChar() << " was not connected to texture" << endl;
459  this->_color.push_back(color_p);
460  }
461  }
462 
463  // Transparency is stored separately.
464  MPlug trans_plug = shader_fn.findPlug("transparency");
465  if (trans_plug.isNull()) {
466  trans_plug = shader_fn.findPlug("outTransparency");
467  }
468 
469  if (!trans_plug.isNull()) {
470  MPlugArray trans_pa;
471  trans_plug.connectedTo(trans_pa, true, false);
472 
473  for (size_t i = 0; i < trans_pa.length(); i++) {
474  maya_cat.spam() << "read a transparency texture" << endl;
475  _transparency.find_textures_legacy(this, trans_pa[0].node(), true);
476  }
477  }
478 
479  // Also try to get the ordinary color directly from the surface shader.
480  bool b_color_def = true;
481  if (shader.hasFn(MFn::kLambert)) {
482  MFnLambertShader lambert_fn(shader);
483  MColor color = lambert_fn.color(&status);
484  if (status) {
485  // Warning! The alpha component of color doesn't mean transparency in
486  // Maya.
487  for (size_t i=0; i<_color.size(); ++i) {
488  _color[i]->_has_flat_color = true;
489  _color[i]->_flat_color.set(color.r, color.g, color.b, color.a);
490  maya_cat.spam() << shader_fn.name().asChar() << " set shader color" << endl;
491  // needed to print the final check
492  if (!_color[i]->_has_flat_color && !_color[i]->_has_texture)
493  b_color_def = false;
494 
495  _transparency._flat_color.set(0.0, 0.0, 0.0, 0.0);
496 
497  // Get the transparency separately.
498  color = lambert_fn.transparency(&status);
499  if (status) {
500  _transparency._has_flat_color = true;
501  _transparency._flat_color.set(color.r, color.g, color.b, color.a);
502  }
503  }
504  }
505  }
506  // if (!_color._has_flat_color && !_color._has_texture) {
507  if (!b_color_def) {
508  maya_cat.info() << shader_fn.name().asChar() << "Color def not found" << endl;
509  if (maya_cat.is_spam()) {
510  maya_cat.spam()
511  << " Color definition not found.\n";
512  }
513  }
514 
515  collect_maps();
516  return true;
517 }
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 get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
This defines the various attributes that Maya may associate with the "color" channel for a particular...
MayaShader(MObject engine, bool legacy_shader)
Reads the Maya "shading engine" to determine the relevant shader properties.
Definition: mayaShader.cxx:43
void collect_maps()
Recalculates the all_maps list.
Definition: mayaShader.cxx:158
LColor get_rgba(size_t idx=0) const
Returns the overall color of the shader as a single-precision rgba value, where the alpha component r...
Definition: mayaShader.cxx:131
MayaShaderColorDef * get_color_def(size_t idx=0) const
This is part of the deprecated codepath.
Definition: mayaShader.cxx:115
void bind_uvsets(MayaFileToUVSetMap &map)
Assigns the uvset_name of each MayaShaderColorDef using the given file-to- uvset map.
Definition: mayaShader.cxx:255
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.