Panda3D
Loading...
Searching...
No Matches
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
35using std::endl;
36using std::string;
37
38/**
39 * Reads the Maya "shading engine" to determine the relevant shader
40 * properties.
41 */
43MayaShader(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 */
90MayaShader::
91~MayaShader() {
92}
93
94/**
95 *
96 */
97void MayaShader::
98output(std::ostream &out) const {
99 out << "Shader " << get_name();
100}
101
102/**
103 *
104 */
105void MayaShader::
106write(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 */
115get_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 */
131get_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 */
158collect_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 */
193bool MayaShader::
194find_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 */
274void MayaShader::
275calculate_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 */
362bool 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 */
406string MayaShader::
407get_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 */
425bool MayaShader::
426find_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
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: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 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.
void collect_maps()
Recalculates the all_maps list.
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...
MayaShaderColorDef * get_color_def(size_t idx=0) const
This is part of the deprecated codepath.
void bind_uvsets(MayaFileToUVSetMap &map)
Assigns the uvset_name of each MayaShaderColorDef using the given file-to- uvset map.
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.