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