Panda3D
|
00001 // Filename: mayaShader.cxx 00002 // Created by: drose (01Feb00) 00003 // Modified 19Mar10 by ETC PandaSE team (see 00004 // header comment for mayaToEgg.cxx for details) 00005 // 00006 //////////////////////////////////////////////////////////////////// 00007 // 00008 // PANDA 3D SOFTWARE 00009 // Copyright (c) Carnegie Mellon University. All rights reserved. 00010 // 00011 // All use of this software is subject to the terms of the revised BSD 00012 // license. You should have received a copy of this license along 00013 // with this source code in a file named "LICENSE." 00014 // 00015 //////////////////////////////////////////////////////////////////// 00016 00017 #include "mayaShader.h" 00018 #include "maya_funcs.h" 00019 #include "config_maya.h" 00020 #include "string_utils.h" 00021 #include "pnmImageHeader.h" // for lumin_red, etc. 00022 #include "pset.h" 00023 00024 #include "pre_maya_include.h" 00025 #include <maya/MFnDependencyNode.h> 00026 #include <maya/MFnLambertShader.h> 00027 #include <maya/MFnPhongShader.h> 00028 #include <maya/MFnMesh.h> 00029 #include <maya/MPlug.h> 00030 #include <maya/MPlugArray.h> 00031 #include <maya/MColor.h> 00032 #include <maya/MObject.h> 00033 #include <maya/MStatus.h> 00034 #include "post_maya_include.h" 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: MayaShader::Constructor 00038 // Access: Public 00039 // Description: Reads the Maya "shading engine" to determine the 00040 // relevant shader properties. 00041 //////////////////////////////////////////////////////////////////// 00042 MayaShader:: 00043 MayaShader(MObject engine, bool legacy_shader) { 00044 MFnDependencyNode engine_fn(engine); 00045 00046 set_name(engine_fn.name().asChar()); 00047 00048 if (maya_cat.is_debug()) { 00049 maya_cat.debug() 00050 << "Reading shading engine " << get_name() << "\n"; 00051 } 00052 _legacy_mode = false; 00053 _flat_color.set(1,1,1,1); 00054 00055 MPlug shader_plug = engine_fn.findPlug("surfaceShader"); 00056 bool found_shader = false; 00057 if (!shader_plug.isNull()) { 00058 MPlugArray shader_pa; 00059 shader_plug.connectedTo(shader_pa, true, false); 00060 maya_cat.spam() << "shader plug connected to: " << shader_pa.length() << endl; 00061 for (size_t i = 0; i < shader_pa.length() && !found_shader; i++) { 00062 MObject shader = shader_pa[0].node(); 00063 if (shader.hasFn(MFn::kPhong)) { 00064 if (legacy_shader) { 00065 found_shader = find_textures_legacy(shader); 00066 } else { 00067 found_shader = find_textures_modern(shader); 00068 } 00069 } else if (shader.hasFn(MFn::kLambert)) { 00070 found_shader = find_textures_legacy(shader); 00071 if (found_shader) { 00072 _legacy_mode = true; 00073 } 00074 } else if (shader.hasFn(MFn::kSurfaceShader)) { 00075 found_shader = find_textures_legacy(shader); 00076 if (found_shader) { 00077 _legacy_mode = true; 00078 } 00079 } else { 00080 maya_cat.warning() << 00081 "Unrecognized shader type: only lambert and phong supported (lambert deprecated).\n"; 00082 } 00083 } 00084 } 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: MayaShader::Destructor 00089 // Access: Public 00090 // Description: 00091 //////////////////////////////////////////////////////////////////// 00092 MayaShader:: 00093 ~MayaShader() { 00094 } 00095 00096 //////////////////////////////////////////////////////////////////// 00097 // Function: MayaShader::output 00098 // Access: Public 00099 // Description: 00100 //////////////////////////////////////////////////////////////////// 00101 void MayaShader:: 00102 output(ostream &out) const { 00103 out << "Shader " << get_name(); 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: MayaShader::write 00108 // Access: Public 00109 // Description: 00110 //////////////////////////////////////////////////////////////////// 00111 void MayaShader:: 00112 write(ostream &out) const { 00113 out << "Shader " << get_name() << "\n"; 00114 } 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: MayaShader::get_color_def 00118 // Access: Public 00119 // Description: This is part of the deprecated codepath. 00120 // return the color def i.e. texture at idx 00121 //////////////////////////////////////////////////////////////////// 00122 MayaShaderColorDef *MayaShader:: 00123 get_color_def(size_t idx) const { 00124 if (_color.size() > 0) 00125 return _color[idx]; 00126 else 00127 return (MayaShaderColorDef *)NULL; 00128 } 00129 //////////////////////////////////////////////////////////////////// 00130 // Function: MayaShader::get_rgba 00131 // Access: Public 00132 // Description: Returns the overall color of the shader as a 00133 // single-precision rgba value, where the alpha 00134 // component represents transparency according to the 00135 // Panda convention. If no overall color is specified 00136 // (_has_flat_color is not true), this returns white. 00137 // 00138 // Normally, Maya makes texture color override the flat 00139 // color, so if a texture is also applied (_has_texture 00140 // is true), this value is not used by Maya. 00141 //////////////////////////////////////////////////////////////////// 00142 LColor MayaShader:: 00143 get_rgba(size_t idx) const { 00144 LColor rgba(1.0f, 1.0f, 1.0f, 1.0f); 00145 00146 if (_color.size() && _color[idx]->_has_flat_color) { 00147 rgba[0] = (PN_stdfloat)_color[idx]->_flat_color[0]; 00148 rgba[1] = (PN_stdfloat)_color[idx]->_flat_color[1]; 00149 rgba[2] = (PN_stdfloat)_color[idx]->_flat_color[2]; 00150 } 00151 00152 if (_transparency._has_flat_color) { 00153 // Maya supports colored transparency, but we only support 00154 // grayscale transparency. Use the pnmimage constants to 00155 // convert color to grayscale. 00156 double trans = 00157 _transparency._flat_color[0] * lumin_red + 00158 _transparency._flat_color[1] * lumin_grn + 00159 _transparency._flat_color[2] * lumin_blu; 00160 rgba[3] = 1.0f - (PN_stdfloat)trans; 00161 } 00162 00163 return rgba; 00164 } 00165 00166 //////////////////////////////////////////////////////////////////// 00167 // Function: MayaShader::collect_maps 00168 // Access: Private 00169 // Description: Recalculates the all_maps list. 00170 //////////////////////////////////////////////////////////////////// 00171 void MayaShader:: 00172 collect_maps() { 00173 _all_maps.clear(); 00174 00175 for (size_t i=0; i<_color_maps.size(); i++) { 00176 _all_maps.push_back(_color_maps[i]); 00177 } 00178 for (size_t i=0; i<_trans_maps.size(); i++) { 00179 _all_maps.push_back(_trans_maps[i]); 00180 } 00181 for (size_t i=0; i<_normal_maps.size(); i++) { 00182 _all_maps.push_back(_normal_maps[i]); 00183 } 00184 for (size_t i=0; i<_glow_maps.size(); i++) { 00185 _all_maps.push_back(_glow_maps[i]); 00186 } 00187 for (size_t i=0; i<_gloss_maps.size(); i++) { 00188 _all_maps.push_back(_gloss_maps[i]); 00189 } 00190 for (size_t i=0; i<_height_maps.size(); i++) { 00191 _all_maps.push_back(_height_maps[i]); 00192 } 00193 00194 for (size_t i=0; i<_color.size(); i++) { 00195 if (_color[i]->_has_texture) { 00196 _all_maps.push_back(_color[i]); 00197 } 00198 } 00199 if (_transparency._has_texture) { 00200 _all_maps.push_back(&_transparency); 00201 } 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: MayaShader::find_textures_modern 00206 // Access: Private 00207 // Description: Locates all file textures leading into the given 00208 // shader. 00209 //////////////////////////////////////////////////////////////////// 00210 bool MayaShader:: 00211 find_textures_modern(MObject shader) { 00212 if (!shader.hasFn(MFn::kPhong)) { 00213 maya_cat.warning() 00214 << "The new codepath expects to see phong shaders only.\n"; 00215 return false; 00216 } 00217 MStatus status; 00218 MFnPhongShader phong_fn(shader); 00219 MFnDependencyNode shader_fn(shader); 00220 00221 if (maya_cat.is_spam()) { 00222 maya_cat.spam() 00223 << " Reading modern surface shader " << shader_fn.name().asChar() << "\n"; 00224 } 00225 00226 string n = shader_fn.name().asChar(); 00227 00228 MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("color"), false); 00229 if (_color_maps.size() == 0) { 00230 MayaShaderColorDef::find_textures_modern(n, _color_maps, shader_fn.findPlug("colorR"), false); 00231 } 00232 MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparency"), true); 00233 if (_trans_maps.size() == 0) { 00234 MayaShaderColorDef::find_textures_modern(n, _trans_maps, shader_fn.findPlug("transparencyR"), true); 00235 } 00236 MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCamera"), false); 00237 if (_normal_maps.size() == 0) { 00238 MayaShaderColorDef::find_textures_modern(n, _normal_maps, shader_fn.findPlug("normalCameraR"), false); 00239 } 00240 MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColor"), true); 00241 if (_gloss_maps.size() == 0) { 00242 MayaShaderColorDef::find_textures_modern(n, _gloss_maps, shader_fn.findPlug("specularColorR"), true); 00243 } 00244 MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescence"), true); 00245 if (_glow_maps.size() == 0) { 00246 MayaShaderColorDef::find_textures_modern(n, _glow_maps, shader_fn.findPlug("incandescenceR"), true); 00247 } 00248 MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThickness"), true); 00249 if (_height_maps.size() == 0) { 00250 MayaShaderColorDef::find_textures_modern(n, _height_maps, shader_fn.findPlug("surfaceThicknessR"), true); 00251 } 00252 00253 collect_maps(); 00254 00255 MColor color = phong_fn.color(&status); 00256 if (status) { 00257 _flat_color.set(color.r, color.g, color.b, color.a); 00258 } 00259 00260 color = phong_fn.transparency(&status); 00261 if (status) { 00262 _flat_color[3] = 1.0 - ((color[0] + color[1] + color[2]) * (1.0/3.0)); 00263 } 00264 return true; 00265 } 00266 00267 //////////////////////////////////////////////////////////////////// 00268 // Function: MayaShader::bind_uvsets 00269 // Access: Public 00270 // Description: Assigns the uvset_name of each MayaShaderColorDef 00271 // using the given file-to-uvset map. 00272 //////////////////////////////////////////////////////////////////// 00273 void MayaShader:: 00274 bind_uvsets(MayaFileToUVSetMap &map) { 00275 for (size_t i=0; i<_all_maps.size(); i++) { 00276 MayaShaderColorDef *def = _all_maps[i]; 00277 MayaFileToUVSetMap::iterator p = map.find(def->_texture_name); 00278 if (p == map.end()) { 00279 def->_uvset_name = "map1"; 00280 } else { 00281 def->_uvset_name = (*p).second; 00282 } 00283 } 00284 00285 calculate_pairings(); 00286 } 00287 00288 //////////////////////////////////////////////////////////////////// 00289 // Function: MayaShader::calculate_pairings 00290 // Access: Public 00291 // Description: For each Alpha texture, try to find an RGB texture 00292 // that has the same properties. Attempt to make it 00293 // so that the alpha texture isn't a separate texture, 00294 // but rather, an Alpha-Filename associated with an 00295 // existing texture. 00296 //////////////////////////////////////////////////////////////////// 00297 void MayaShader:: 00298 calculate_pairings() { 00299 00300 if (_legacy_mode) { 00301 return; 00302 } 00303 00304 for (size_t i=0; i<_all_maps.size(); i++) { 00305 _all_maps[i]->_opposite = 0; 00306 } 00307 00308 bool using_transparency = (_trans_maps.size() > 0); 00309 00310 for (int retry=0; retry<2; retry++) { 00311 bool perfect=(retry==0); 00312 for (size_t i=0; i<_color_maps.size(); i++) { 00313 if ((_color_maps[i]->_blend_type == MayaShaderColorDef::BT_modulate)|| 00314 (_color_maps[i]->_blend_type == MayaShaderColorDef::BT_unspecified)) { 00315 for (size_t j=0; j<_trans_maps.size(); j++) { 00316 try_pair(_color_maps[i], _trans_maps[j], perfect); 00317 } 00318 } 00319 } 00320 } 00321 00322 if (!using_transparency) { 00323 for (int retry=0; retry<2; retry++) { 00324 bool perfect=(retry==0); 00325 for (size_t i=0; i<_color_maps.size(); i++) { 00326 for (size_t j=0; j<_glow_maps.size(); j++) { 00327 try_pair(_color_maps[i], _glow_maps[j], perfect); 00328 } 00329 for (size_t j=0; j<_gloss_maps.size(); j++) { 00330 try_pair(_color_maps[i], _gloss_maps[j], perfect); 00331 } 00332 } 00333 } 00334 } 00335 00336 for (int retry=0; retry<2; retry++) { 00337 bool perfect=(retry==0); 00338 for (size_t i=0; i<_normal_maps.size(); i++) { 00339 for (size_t j=0; j<_height_maps.size(); j++) { 00340 try_pair(_normal_maps[i], _height_maps[j], perfect); 00341 } 00342 } 00343 } 00344 00345 for (size_t i=0; i<_normal_maps.size(); i++) { 00346 _normal_maps[i]->_blend_type = MayaShaderColorDef::BT_normal; 00347 } 00348 for (size_t i=0; i<_glow_maps.size(); i++) { 00349 if (_glow_maps[i]->_opposite) { 00350 _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; 00351 _glow_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_glow; 00352 } else { 00353 _glow_maps[i]->_blend_type = MayaShaderColorDef::BT_glow; 00354 } 00355 } 00356 for (size_t i=0; i<_gloss_maps.size(); i++) { 00357 if (_gloss_maps[i]->_opposite) { 00358 _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; 00359 _gloss_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate_gloss; 00360 } else { 00361 _gloss_maps[i]->_blend_type = MayaShaderColorDef::BT_gloss; 00362 } 00363 } 00364 for (size_t i=0; i<_height_maps.size(); i++) { 00365 if (_height_maps[i]->_opposite) { 00366 _height_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; 00367 _height_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_normal_height; 00368 } else { 00369 _height_maps[i]->_blend_type = MayaShaderColorDef::BT_height; 00370 } 00371 } 00372 for (size_t i=0; i<_trans_maps.size(); i++) { 00373 if (_trans_maps[i]->_opposite) { 00374 _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_unspecified; 00375 _trans_maps[i]->_opposite->_blend_type = MayaShaderColorDef::BT_modulate; 00376 } else { 00377 _trans_maps[i]->_blend_type = MayaShaderColorDef::BT_modulate; 00378 } 00379 } 00380 } 00381 00382 //////////////////////////////////////////////////////////////////// 00383 // Function: MayaShader::try_pair 00384 // Access: Private 00385 // Description: Try to associate an RGB tex with an Alpha tex. 00386 //////////////////////////////////////////////////////////////////// 00387 bool MayaShader::try_pair(MayaShaderColorDef *map1, 00388 MayaShaderColorDef *map2, 00389 bool perfect) { 00390 if ((map1->_opposite)||(map2->_opposite)) { 00391 // one of the maps is already paired 00392 return false; 00393 } 00394 if (perfect) { 00395 if (map1->_texture_filename != map2->_texture_filename) { 00396 // perfect mode requires a filename match. 00397 return false; 00398 } 00399 } else { 00400 string pre1 = get_file_prefix(map1->_texture_filename); 00401 string pre2 = get_file_prefix(map2->_texture_filename); 00402 if (pre1 != pre2) { 00403 // imperfect mode requires a filename prefix match. 00404 return false; 00405 } 00406 } 00407 00408 if ((map1->_projection_type != map2->_projection_type) || 00409 (map1->_projection_matrix != map2->_projection_matrix) || 00410 (map1->_u_angle != map2->_u_angle) || 00411 (map1->_v_angle != map2->_v_angle) || 00412 (map1->_uvset_name != map2->_uvset_name) || 00413 (map1->_mirror != map2->_mirror) || 00414 (map1->_stagger != map2->_stagger) || 00415 (map1->_wrap_u != map2->_wrap_u) || 00416 (map1->_wrap_v != map2->_wrap_v) || 00417 (map1->_repeat_uv != map2->_repeat_uv) || 00418 (map1->_offset != map2->_offset) || 00419 (map1->_rotate_uv != map2->_rotate_uv)) { 00420 return false; 00421 } 00422 // Pairing successful. 00423 map1->_opposite = map2; 00424 map2->_opposite = map1; 00425 return true; 00426 } 00427 00428 //////////////////////////////////////////////////////////////////// 00429 // Function: MayaShader::get_file_prefix 00430 // Access: Private 00431 // Description: Try to associate an RGB tex with an Alpha tex. 00432 //////////////////////////////////////////////////////////////////// 00433 string MayaShader:: 00434 get_file_prefix(const string &fn) { 00435 Filename pfn = Filename::from_os_specific(fn); 00436 string base = pfn.get_basename_wo_extension(); 00437 size_t offs = base.find("_"); 00438 if (offs != string::npos) { 00439 base = base.substr(0, offs); 00440 } 00441 offs = base.find("-"); 00442 if (offs != string::npos) { 00443 base = base.substr(0, offs); 00444 } 00445 return base; 00446 } 00447 00448 //////////////////////////////////////////////////////////////////// 00449 // Function: MayaShader::find_textures_legacy 00450 // Access: Private 00451 // Description: This is part of the legacy codepath. 00452 // Extracts out the shading information from the Maya 00453 // surface shader. 00454 //////////////////////////////////////////////////////////////////// 00455 bool MayaShader:: 00456 find_textures_legacy(MObject shader) { 00457 MStatus status; 00458 MFnDependencyNode shader_fn(shader); 00459 00460 if (maya_cat.is_spam()) { 00461 maya_cat.spam() 00462 << " Reading legacy surface shader " << shader_fn.name().asChar() << "\n"; 00463 } 00464 00465 // First, check for a connection to the color attribute. This could 00466 // be a texture map or something, and will override whatever the 00467 // shader says for color. 00468 00469 MPlug color_plug = shader_fn.findPlug("color"); 00470 if (color_plug.isNull()) { 00471 // Or maybe a connection to outColor. Not sure how this differs 00472 // from just color, but empirically it seems that either might be 00473 // used. 00474 color_plug = shader_fn.findPlug("outColor"); 00475 } 00476 00477 if (!color_plug.isNull()) { 00478 MPlugArray color_pa; 00479 color_plug.connectedTo(color_pa, true, false); 00480 00481 MayaShaderColorDef *color_p = new MayaShaderColorDef; 00482 for (size_t i = 0; i < color_pa.length(); i++) { 00483 maya_cat.spam() << "color_pa[" << i << "]:" << color_pa[i].name().asChar() << endl; 00484 color_p->find_textures_legacy(this, color_pa[0].node()); 00485 } 00486 00487 if (color_pa.length() < 1) { 00488 // assign a blank default color to this shader 00489 maya_cat.spam() << shader_fn.name().asChar() << " was not connected to texture" << endl; 00490 this->_color.push_back(color_p); 00491 } 00492 } 00493 00494 // Transparency is stored separately. 00495 MPlug trans_plug = shader_fn.findPlug("transparency"); 00496 if (trans_plug.isNull()) { 00497 trans_plug = shader_fn.findPlug("outTransparency"); 00498 } 00499 00500 if (!trans_plug.isNull()) { 00501 MPlugArray trans_pa; 00502 trans_plug.connectedTo(trans_pa, true, false); 00503 00504 for (size_t i = 0; i < trans_pa.length(); i++) { 00505 maya_cat.spam() << "read a transparency texture" << endl; 00506 _transparency.find_textures_legacy(this, trans_pa[0].node(), true); 00507 } 00508 } 00509 00510 // Also try to get the ordinary color directly from the surface 00511 // shader. 00512 bool b_color_def = true; 00513 if (shader.hasFn(MFn::kLambert)) { 00514 MFnLambertShader lambert_fn(shader); 00515 MColor color = lambert_fn.color(&status); 00516 if (status) { 00517 // Warning! The alpha component of color doesn't mean 00518 // transparency in Maya. 00519 for (size_t i=0; i<_color.size(); ++i) { 00520 _color[i]->_has_flat_color = true; 00521 _color[i]->_flat_color.set(color.r, color.g, color.b, color.a); 00522 maya_cat.spam() << shader_fn.name().asChar() << " set shader color" << endl; 00523 // needed to print the final check 00524 if (!_color[i]->_has_flat_color && !_color[i]->_has_texture) 00525 b_color_def = false; 00526 00527 _transparency._flat_color.set(0.0, 0.0, 0.0, 0.0); 00528 00529 // Get the transparency separately. 00530 color = lambert_fn.transparency(&status); 00531 if (status) { 00532 _transparency._has_flat_color = true; 00533 _transparency._flat_color.set(color.r, color.g, color.b, color.a); 00534 } 00535 } 00536 } 00537 } 00538 // if (!_color._has_flat_color && !_color._has_texture) { 00539 if (!b_color_def) { 00540 maya_cat.info() << shader_fn.name().asChar() << "Color def not found" << endl; 00541 if (maya_cat.is_spam()) { 00542 maya_cat.spam() 00543 << " Color definition not found.\n"; 00544 } 00545 } 00546 00547 collect_maps(); 00548 return true; 00549 }