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 */
42 MayaShader::
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 */
114 MayaShaderColorDef *MayaShader::
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 */
130 LColor MayaShader::
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 */
157 void MayaShader::
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 */
254 void MayaShader::
255 bind_uvsets(MayaFileToUVSetMap &map) {
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) {
408 Filename pfn = Filename::from_os_specific(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 }
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::get_basename_wo_extension
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
MayaShaderColorDef
This defines the various attributes that Maya may associate with the "color" channel for a particular...
Definition: mayaShaderColorDef.h:34
MayaShader::MayaShader
MayaShader(MObject engine, bool legacy_shader)
Reads the Maya "shading engine" to determine the relevant shader properties.
Definition: mayaShader.cxx:43
MayaShader::collect_maps
void collect_maps()
Recalculates the all_maps list.
Definition: mayaShader.cxx:158
MayaShader::get_rgba
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
MayaShader::get_color_def
MayaShaderColorDef * get_color_def(size_t idx=0) const
This is part of the deprecated codepath.
Definition: mayaShader.cxx:115
MayaShader::bind_uvsets
void bind_uvsets(MayaFileToUVSetMap &map)
Assigns the uvset_name of each MayaShaderColorDef using the given file-to- uvset map.
Definition: mayaShader.cxx:255
pmap< std::string, std::string >
config_maya.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mayaShader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
maya_funcs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmImageHeader.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.