1 //////////////////////////////////////////////////////////////////////////////// 2 // material.cpp 3 // Author : Francesco Giordana 4 // Sponsored by : Anygma N.V. (http://www.nazooka.com) 5 // Start Date : January 13, 2005 6 // Copyright : (C) 2006 by Francesco Giordana 7 // Email : fra.giordana@tiscali.it 8 //////////////////////////////////////////////////////////////////////////////// 9 10 /********************************************************************************* 11 * * 12 * This program is free software; you can redistribute it and/or modify * 13 * it under the terms of the GNU Lesser General Public License as published by * 14 * the Free Software Foundation; either version 2 of the License, or * 15 * (at your option) any later version. * 16 * * 17 **********************************************************************************/ 18 19 #include "material.h" 20 21 namespace OgreMayaExporter 22 { 23 // Constructor Material()24 Material::Material() 25 { 26 clear(); 27 } 28 29 30 // Destructor ~Material()31 Material::~Material() 32 { 33 } 34 35 36 // Get material name name()37 MString& Material::name() 38 { 39 return m_name; 40 } 41 42 43 // Clear data clear()44 void Material::clear() 45 { 46 m_name = ""; 47 m_type = MT_LAMBERT; 48 m_lightingOff = false; 49 m_isTransparent = false; 50 m_isTextured = false; 51 m_isMultiTextured = false; 52 m_ambient = MColor(0,0,0,0); 53 m_diffuse = MColor(0,0,0,0); 54 m_specular = MColor(0,0,0,0); 55 m_emissive = MColor(0,0,0,0); 56 m_textures.clear(); 57 } 58 59 60 // Load material data load(MFnDependencyNode * pShader,MStringArray & uvsets,ParamList & params)61 MStatus Material::load(MFnDependencyNode* pShader,MStringArray& uvsets,ParamList& params) 62 { 63 MStatus stat; 64 clear(); 65 //read material name, adding the requested prefix 66 MString tmpStr = params.matPrefix; 67 if (tmpStr != "") 68 tmpStr += "/"; 69 tmpStr += pShader->name(); 70 MStringArray tmpStrArray; 71 tmpStr.split(':',tmpStrArray); 72 m_name = ""; 73 for (int i=0; i<tmpStrArray.length(); i++) 74 { 75 m_name += tmpStrArray[i]; 76 if (i < tmpStrArray.length()-1) 77 m_name += "_"; 78 } 79 80 //check if we want to export with lighting off option 81 m_lightingOff = params.lightingOff; 82 83 // GET MATERIAL DATA 84 85 // Check material type 86 if (pShader->object().hasFn(MFn::kPhong)) 87 { 88 stat = loadPhong(pShader); 89 } 90 else if (pShader->object().hasFn(MFn::kBlinn)) 91 { 92 stat = loadBlinn(pShader); 93 } 94 else if (pShader->object().hasFn(MFn::kLambert)) 95 { 96 stat = loadLambert(pShader); 97 } 98 else if (pShader->object().hasFn(MFn::kPluginHwShaderNode)) 99 { 100 stat = loadCgFxShader(pShader); 101 } 102 else 103 { 104 stat = loadSurfaceShader(pShader); 105 } 106 107 // Get textures data 108 MPlugArray colorSrcPlugs; 109 MPlugArray texSrcPlugs; 110 MPlugArray placetexSrcPlugs; 111 if (m_isTextured) 112 { 113 // Translate multiple textures if material is multitextured 114 if (m_isMultiTextured) 115 { 116 // Get layered texture node 117 MFnDependencyNode* pLayeredTexNode = NULL; 118 if (m_type == MT_SURFACE_SHADER) 119 pShader->findPlug("outColor").connectedTo(colorSrcPlugs,true,false); 120 else 121 pShader->findPlug("color").connectedTo(colorSrcPlugs,true,false); 122 for (int i=0; i<colorSrcPlugs.length(); i++) 123 { 124 if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) 125 { 126 pLayeredTexNode = new MFnDependencyNode(colorSrcPlugs[i].node()); 127 continue; 128 } 129 } 130 131 // Get inputs to layered texture 132 MPlug inputsPlug = pLayeredTexNode->findPlug("inputs"); 133 134 // Scan inputs and export textures 135 for (int i=inputsPlug.numElements()-1; i>=0; i--) 136 { 137 MFnDependencyNode* pTextureNode = NULL; 138 // Search for a connected texture 139 inputsPlug[i].child(0).connectedTo(colorSrcPlugs,true,false); 140 for (int j=0; j<colorSrcPlugs.length(); j++) 141 { 142 if (colorSrcPlugs[j].node().hasFn(MFn::kFileTexture)) 143 { 144 pTextureNode = new MFnDependencyNode(colorSrcPlugs[j].node()); 145 continue; 146 } 147 } 148 149 // Translate the texture if it was found 150 if (pTextureNode) 151 { 152 // Get blend mode 153 TexOpType opType; 154 short bm; 155 inputsPlug[i].child(2).getValue(bm); 156 switch(bm) 157 { 158 case 0: 159 opType = TOT_REPLACE; 160 break; 161 case 1: 162 opType = TOT_ALPHABLEND; 163 break; 164 case 4: 165 opType = TOT_ADD; 166 break; 167 case 6: 168 opType = TOT_MODULATE; 169 break; 170 default: 171 opType = TOT_MODULATE; 172 } 173 174 stat = loadTexture(pTextureNode,opType,uvsets,params); 175 delete pTextureNode; 176 if (MS::kSuccess != stat) 177 { 178 std::cout << "Error loading layered texture\n"; 179 std::cout.flush(); 180 delete pLayeredTexNode; 181 return MS::kFailure; 182 } 183 } 184 } 185 if (pLayeredTexNode) 186 delete pLayeredTexNode; 187 } 188 // Else translate the single texture 189 else 190 { 191 // Get texture node 192 MFnDependencyNode* pTextureNode = NULL; 193 if (m_type == MT_SURFACE_SHADER) 194 pShader->findPlug("outColor").connectedTo(colorSrcPlugs,true,false); 195 else 196 pShader->findPlug("color").connectedTo(colorSrcPlugs,true,false); 197 for (int i=0; i<colorSrcPlugs.length(); i++) 198 { 199 if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) 200 { 201 pTextureNode = new MFnDependencyNode(colorSrcPlugs[i].node()); 202 continue; 203 } 204 } 205 if (pTextureNode) 206 { 207 TexOpType opType = TOT_MODULATE; 208 stat = loadTexture(pTextureNode,opType,uvsets,params); 209 delete pTextureNode; 210 if (MS::kSuccess != stat) 211 { 212 std::cout << "Error loading texture\n"; 213 std::cout.flush(); 214 return MS::kFailure; 215 } 216 } 217 } 218 } 219 220 return MS::kSuccess; 221 } 222 223 224 // Load a surface shader loadSurfaceShader(MFnDependencyNode * pShader)225 MStatus Material::loadSurfaceShader(MFnDependencyNode *pShader) 226 { 227 m_type = MT_SURFACE_SHADER; 228 MPlugArray colorSrcPlugs; 229 // Check if material is textured 230 pShader->findPlug("outColor").connectedTo(colorSrcPlugs,true,false); 231 for (int i=0; i<colorSrcPlugs.length(); i++) 232 { 233 if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) 234 { 235 m_isTextured = true; 236 continue; 237 } 238 else if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) 239 { 240 m_isTextured = true; 241 m_isMultiTextured = true; 242 continue; 243 } 244 } 245 246 // Check if material is transparent 247 float trasp; 248 pShader->findPlug("outTransparencyR").getValue(trasp); 249 if (pShader->findPlug("outTransparency").isConnected() || trasp>0.0f) 250 m_isTransparent = true; 251 252 // Get material colours 253 if (m_isTextured) 254 m_diffuse = MColor(1.0,1.0,1.0,1.0); 255 else 256 { 257 pShader->findPlug("outColorR").getValue(m_diffuse.r); 258 pShader->findPlug("outColorG").getValue(m_diffuse.g); 259 pShader->findPlug("outColorB").getValue(m_diffuse.b); 260 float trasp; 261 pShader->findPlug("outTransparencyR").getValue(trasp); 262 m_diffuse.a = 1.0 - trasp; 263 } 264 m_ambient = MColor(0,0,0,1); 265 m_emissive = MColor(0,0,0,1); 266 m_specular = MColor(0,0,0,1); 267 return MS::kSuccess; 268 } 269 270 // Load a lambert shader loadLambert(MFnDependencyNode * pShader)271 MStatus Material::loadLambert(MFnDependencyNode *pShader) 272 { 273 MPlugArray colorSrcPlugs; 274 m_type = MT_LAMBERT; 275 MFnLambertShader* pLambert = new MFnLambertShader(pShader->object()); 276 // Check if material is textured 277 pLambert->findPlug("color").connectedTo(colorSrcPlugs,true,false); 278 for (int i=0; i<colorSrcPlugs.length(); i++) 279 { 280 if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) 281 { 282 m_isTextured = true; 283 continue; 284 } 285 else if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) 286 { 287 m_isTextured = true; 288 m_isMultiTextured = true; 289 continue; 290 } 291 } 292 293 // Check if material is transparent 294 if (pLambert->findPlug("transparency").isConnected() || pLambert->transparency().r>0.0f) 295 m_isTransparent = true; 296 297 // Get material colours 298 //diffuse colour 299 if (m_isTextured) 300 m_diffuse = MColor(1.0,1.0,1.0,1.0); 301 else 302 { 303 m_diffuse = pLambert->color(); 304 m_diffuse.a = 1.0 - pLambert->transparency().r; 305 } 306 //ambient colour 307 m_ambient = pLambert->ambientColor(); 308 //emissive colour 309 m_emissive = pLambert->incandescence(); 310 //specular colour 311 m_specular = MColor(0,0,0,1); 312 delete pLambert; 313 return MS::kSuccess; 314 } 315 316 // Load a phong shader loadPhong(MFnDependencyNode * pShader)317 MStatus Material::loadPhong(MFnDependencyNode *pShader) 318 { 319 MPlugArray colorSrcPlugs; 320 m_type = MT_PHONG; 321 MFnPhongShader* pPhong = new MFnPhongShader(pShader->object()); 322 // Check if material is textured 323 pPhong->findPlug("color").connectedTo(colorSrcPlugs,true,false); 324 for (int i=0; i<colorSrcPlugs.length(); i++) 325 { 326 if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) 327 { 328 m_isTextured = true; 329 continue; 330 } 331 else if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) 332 { 333 m_isTextured = true; 334 m_isMultiTextured = true; 335 continue; 336 } 337 } 338 339 // Check if material is transparent 340 if (pPhong->findPlug("transparency").isConnected() || pPhong->transparency().r>0.0f) 341 m_isTransparent = true; 342 343 // Get material colours 344 //diffuse colour 345 if (m_isTextured) 346 m_diffuse = MColor(1.0,1.0,1.0,1.0); 347 else 348 { 349 m_diffuse = pPhong->color(); 350 m_diffuse.a = 1.0 - pPhong->transparency().r; 351 } 352 //ambient colour 353 m_ambient = pPhong->ambientColor(); 354 //emissive colour 355 m_emissive = pPhong->incandescence(); 356 //specular colour 357 m_specular = pPhong->specularColor(); 358 m_specular.a = pPhong->cosPower()*1.28; 359 delete pPhong; 360 return MS::kSuccess; 361 } 362 363 // load a blinn shader loadBlinn(MFnDependencyNode * pShader)364 MStatus Material::loadBlinn(MFnDependencyNode *pShader) 365 { 366 MPlugArray colorSrcPlugs; 367 m_type = MT_BLINN; 368 MFnBlinnShader* pBlinn = new MFnBlinnShader(pShader->object()); 369 // Check if material is textured 370 pBlinn->findPlug("color").connectedTo(colorSrcPlugs,true,false); 371 for (int i=0; i<colorSrcPlugs.length(); i++) 372 { 373 if (colorSrcPlugs[i].node().hasFn(MFn::kFileTexture)) 374 { 375 m_isTextured = true; 376 continue; 377 } 378 else if (colorSrcPlugs[i].node().hasFn(MFn::kLayeredTexture)) 379 { 380 m_isTextured = true; 381 m_isMultiTextured = true; 382 continue; 383 } 384 } 385 386 // Check if material is transparent 387 if (pBlinn->findPlug("transparency").isConnected() || pBlinn->transparency().r>0.0f) 388 m_isTransparent = true; 389 390 // Get material colours 391 //diffuse colour 392 if (m_isTextured) 393 m_diffuse = MColor(1.0,1.0,1.0,1.0); 394 else 395 { 396 m_diffuse = pBlinn->color(); 397 m_diffuse.a = 1.0 - pBlinn->transparency().r; 398 } 399 //ambient colour 400 m_ambient = pBlinn->ambientColor(); 401 //emissive colour 402 m_emissive = pBlinn->incandescence(); 403 //specular colour 404 m_specular = pBlinn->specularColor(); 405 m_specular.a = 128.0-(128.0*pBlinn->eccentricity()); 406 delete pBlinn; 407 return MS::kSuccess; 408 } 409 410 // load a cgFx shader loadCgFxShader(MFnDependencyNode * pShader)411 MStatus Material::loadCgFxShader(MFnDependencyNode *pShader) 412 { 413 m_type = MT_CGFX; 414 // Create a default white lambert 415 m_isTextured = false; 416 m_isMultiTextured = false; 417 m_diffuse = MColor(1.0,1.0,1.0,1.0); 418 m_specular = MColor(0,0,0,1); 419 m_emissive = MColor(0,0,0,1); 420 m_ambient = MColor(0,0,0,1); 421 return MS::kSuccess; 422 } 423 424 // Load texture data from a texture node loadTexture(MFnDependencyNode * pTexNode,TexOpType & opType,MStringArray & uvsets,ParamList & params)425 MStatus Material::loadTexture(MFnDependencyNode* pTexNode,TexOpType& opType,MStringArray& uvsets,ParamList& params) 426 { 427 Texture tex; 428 // Get texture filename 429 MString filename, absFilename; 430 MRenderUtil::exactFileTextureName(pTexNode->object(),absFilename); 431 filename = absFilename.substring(absFilename.rindex('/')+1,absFilename.length()-1); 432 MString command = "toNativePath(\""; 433 command += absFilename; 434 command += "\")"; 435 MGlobal::executeCommand(command,absFilename); 436 tex.absFilename = absFilename; 437 tex.filename = filename; 438 tex.uvsetIndex = 0; 439 tex.uvsetName = ""; 440 // Set texture operation type 441 tex.opType = opType; 442 // Get connections to uvCoord attribute of texture node 443 MPlugArray texSrcPlugs; 444 pTexNode->findPlug("uvCoord").connectedTo(texSrcPlugs,true,false); 445 // Get place2dtexture node (if connected) 446 MFnDependencyNode* pPlace2dTexNode = NULL; 447 for (int j=0; j<texSrcPlugs.length(); j++) 448 { 449 if (texSrcPlugs[j].node().hasFn(MFn::kPlace2dTexture)) 450 { 451 pPlace2dTexNode = new MFnDependencyNode(texSrcPlugs[j].node()); 452 continue; 453 } 454 } 455 // Get uvChooser node (if connected) 456 MFnDependencyNode* pUvChooserNode = NULL; 457 if (pPlace2dTexNode) 458 { 459 MPlugArray placetexSrcPlugs; 460 pPlace2dTexNode->findPlug("uvCoord").connectedTo(placetexSrcPlugs,true,false); 461 for (int j=0; j<placetexSrcPlugs.length(); j++) 462 { 463 if (placetexSrcPlugs[j].node().hasFn(MFn::kUvChooser)) 464 { 465 pUvChooserNode = new MFnDependencyNode(placetexSrcPlugs[j].node()); 466 continue; 467 } 468 } 469 } 470 // Get uvset index 471 if (pUvChooserNode) 472 { 473 bool foundMesh = false; 474 bool foundUvset = false; 475 MPlug uvsetsPlug = pUvChooserNode->findPlug("uvSets"); 476 MPlugArray uvsetsSrcPlugs; 477 for (int i=0; i<uvsetsPlug.evaluateNumElements() && !foundMesh; i++) 478 { 479 uvsetsPlug[i].connectedTo(uvsetsSrcPlugs,true,false); 480 for (int j=0; j<uvsetsSrcPlugs.length() && !foundMesh; j++) 481 { 482 if (uvsetsSrcPlugs[j].node().hasFn(MFn::kMesh)) 483 { 484 uvsetsSrcPlugs[j].getValue(tex.uvsetName); 485 for (int k=0; k<uvsets.length() && !foundUvset; k++) 486 { 487 if (uvsets[k] == tex.uvsetName) 488 { 489 tex.uvsetIndex = k; 490 foundUvset = true; 491 } 492 } 493 } 494 } 495 } 496 } 497 // Get texture options from Place2dTexture node 498 if (pPlace2dTexNode) 499 { 500 // Get address mode 501 //U 502 bool wrapU, mirrorU; 503 pPlace2dTexNode->findPlug("wrapU").getValue(wrapU); 504 pPlace2dTexNode->findPlug("mirrorU").getValue(mirrorU); 505 if (mirrorU) 506 tex.am_u = TAM_MIRROR; 507 else if (wrapU) 508 tex.am_u = TAM_WRAP; 509 else 510 tex.am_u = TAM_CLAMP; 511 // V 512 bool wrapV,mirrorV; 513 pPlace2dTexNode->findPlug("wrapV").getValue(wrapV); 514 pPlace2dTexNode->findPlug("mirrorV").getValue(mirrorV); 515 if (mirrorV) 516 tex.am_v = TAM_MIRROR; 517 else if (wrapV) 518 tex.am_v = TAM_WRAP; 519 else 520 tex.am_v = TAM_CLAMP; 521 // Get texture scale 522 double covU,covV; 523 pPlace2dTexNode->findPlug("coverageU").getValue(covU); 524 pPlace2dTexNode->findPlug("coverageV").getValue(covV); 525 tex.scale_u = covU; 526 if (fabs(tex.scale_u) < PRECISION) 527 tex.scale_u = 0; 528 tex.scale_v = covV; 529 if (fabs(tex.scale_v) < PRECISION) 530 tex.scale_v = 0; 531 // Get texture scroll 532 double transU,transV; 533 pPlace2dTexNode->findPlug("translateFrameU").getValue(transU); 534 pPlace2dTexNode->findPlug("translateFrameV").getValue(transV); 535 tex.scroll_u = -0.5 * (covU-1.0)/covU - transU/covU; 536 if (fabs(tex.scroll_u) < PRECISION) 537 tex.scroll_u = 0; 538 tex.scroll_v = 0.5 * (covV-1.0)/covV + transV/covV; 539 if (fabs(tex.scroll_v) < PRECISION) 540 tex.scroll_v = 0; 541 // Get texture rotation 542 double rot; 543 pPlace2dTexNode->findPlug("rotateFrame").getValue(rot); 544 tex.rot = -rot; 545 if (fabs(rot) < PRECISION) 546 tex.rot = 0; 547 } 548 // add texture to material texture list 549 m_textures.push_back(tex); 550 // free up memory 551 if (pUvChooserNode) 552 delete pUvChooserNode; 553 if (pPlace2dTexNode) 554 delete pPlace2dTexNode; 555 556 return MS::kSuccess; 557 } 558 559 560 // Write material data to an Ogre material script file writeOgreScript(ParamList & params)561 MStatus Material::writeOgreScript(ParamList ¶ms) 562 { 563 //Start material description 564 params.outMaterial << "material " << m_name.asChar() << "\n"; 565 params.outMaterial << "{\n"; 566 567 //Start technique description 568 params.outMaterial << "\ttechnique\n"; 569 params.outMaterial << "\t{\n"; 570 571 //Start render pass description 572 params.outMaterial << "\t\tpass\n"; 573 params.outMaterial << "\t\t{\n"; 574 //set lighting off option if requested 575 if (m_lightingOff) 576 params.outMaterial << "\t\t\tlighting off\n\n"; 577 //set phong shading if requested (default is gouraud) 578 if (m_type == MT_PHONG) 579 params.outMaterial << "\t\t\tshading phong\n"; 580 //ambient colour 581 params.outMaterial << "\t\t\tambient " << m_ambient.r << " " << m_ambient.g << " " << m_ambient.b 582 << " " << m_ambient.a << "\n"; 583 //diffuse colour 584 params.outMaterial << "\t\t\tdiffuse " << m_diffuse.r << " " << m_diffuse.g << " " << m_diffuse.b 585 << " " << m_diffuse.a << "\n"; 586 //specular colour 587 params.outMaterial << "\t\t\tspecular " << m_specular.r << " " << m_specular.g << " " << m_specular.b 588 << " " << m_specular.a << "\n"; 589 //emissive colour 590 params.outMaterial << "\t\t\temissive " << m_emissive.r << " " << m_emissive.g << " " 591 << m_emissive.b << "\n"; 592 //if material is transparent set blend mode and turn off depth_writing 593 if (m_isTransparent) 594 { 595 params.outMaterial << "\n\t\t\tscene_blend alpha_blend\n"; 596 params.outMaterial << "\t\t\tdepth_write off\n"; 597 } 598 //write texture units 599 for (int i=0; i<m_textures.size(); i++) 600 { 601 //start texture unit description 602 params.outMaterial << "\n\t\t\ttexture_unit\n"; 603 params.outMaterial << "\t\t\t{\n"; 604 //write texture name 605 params.outMaterial << "\t\t\t\ttexture " << m_textures[i].filename.asChar() << "\n"; 606 //write texture coordinate index 607 params.outMaterial << "\t\t\t\ttex_coord_set " << m_textures[i].uvsetIndex << "\n"; 608 //write colour operation 609 switch (m_textures[i].opType) 610 { 611 case TOT_REPLACE: 612 params.outMaterial << "\t\t\t\tcolour_op replace\n"; 613 break; 614 case TOT_ADD: 615 params.outMaterial << "\t\t\t\tcolour_op add\n"; 616 break; 617 case TOT_MODULATE: 618 params.outMaterial << "\t\t\t\tcolour_op modulate\n"; 619 break; 620 case TOT_ALPHABLEND: 621 params.outMaterial << "\t\t\t\tcolour_op alpha_blend\n"; 622 break; 623 } 624 //write texture transforms 625 params.outMaterial << "\t\t\t\tscale " << m_textures[i].scale_u << " " << m_textures[i].scale_v << "\n"; 626 params.outMaterial << "\t\t\t\tscroll " << m_textures[i].scroll_u << " " << m_textures[i].scroll_v << "\n"; 627 params.outMaterial << "\t\t\t\trotate " << m_textures[i].rot << "\n"; 628 //end texture unit desription 629 params.outMaterial << "\t\t\t}\n"; 630 } 631 632 //End render pass description 633 params.outMaterial << "\t\t}\n"; 634 635 //End technique description 636 params.outMaterial << "\t}\n"; 637 638 //End material description 639 params.outMaterial << "}\n"; 640 641 //Copy textures to output dir if required 642 if (params.copyTextures) 643 copyTextures(params); 644 645 return MS::kSuccess; 646 } 647 648 649 // Copy textures to path specified by params copyTextures(ParamList & params)650 MStatus Material::copyTextures(ParamList ¶ms) 651 { 652 for (int i=0; i<m_textures.size(); i++) 653 { 654 // Copy file texture to output dir 655 MString command = "copy \""; 656 command += m_textures[i].absFilename; 657 command += "\" \""; 658 command += params.texOutputDir; 659 command += "\""; 660 system(command.asChar()); 661 } 662 return MS::kSuccess; 663 } 664 665 }; //end namespace