/// <summary> /// Extract a material and its linked texture, if any. /// </summary> private static void ExtractMaterial(MayaM2Mesh mesh, MObject material) { var fnShader = new MFnLambertShader(material); // Get lambert out of the shader var strName = fnShader.name; MGlobal.displayInfo("Detected material : " + strName + " of type " + material.apiTypeStr); //TODO use this type // ReSharper disable once UnusedVariable var clrDiffuse = fnShader.color; // ReSharper disable once UnusedVariable var clrAmbient = fnShader.ambientColor; if (material.hasFn(MFn.Type.kReflect)) { var fnReflectShader = new MFnReflectShader(material); // ReSharper disable once UnusedVariable var clrSpec = fnReflectShader.specularColor; } // Look for textures at the color plug var colorPlug = fnShader.findPlug("color"); var fileTextureIter = new MItDependencyGraph(colorPlug.node, MFn.Type.kFileTexture, MItDependencyGraph.Direction.kUpstream, MItDependencyGraph.Traversal.kDepthFirst, MItDependencyGraph.Level.kNodeLevel); while (!fileTextureIter.isDone) { //TODO hardcoded textures var nodeFn = new MFnDependencyNode(fileTextureIter.thisNode()); var fileNamePlug = nodeFn.findPlug("fileTextureName"); string textureFileName; fileNamePlug.getValue(out textureFileName); MGlobal.displayInfo("\t Texture found : " + textureFileName); var wrapUPlug = nodeFn.findPlug("wrapU"); var wrapU = false; wrapUPlug.getValue(ref wrapU); var wrapVPlug = nodeFn.findPlug("wrapV"); var wrapV = false; wrapVPlug.getValue(ref wrapV); var tex = new MayaM2Texture { WrapU = wrapU, WrapV = wrapV }; mesh.Textures.Add(tex); fileTextureIter.next();//maybe now the loop is fixed } }
private void ExportMaterial(MFnDependencyNode materialDependencyNode, BabylonScene babylonScene, bool fullPBR) { MObject materialObject = materialDependencyNode.objectProperty; var name = materialDependencyNode.name; var id = materialDependencyNode.uuid().asString(); RaiseMessage(name, 1); RaiseMessage(materialObject.apiType.ToString(), 1); RaiseVerbose("materialObject.hasFn(MFn.Type.kBlinn)=" + materialObject.hasFn(MFn.Type.kBlinn), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhong)=" + materialObject.hasFn(MFn.Type.kPhong), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhongExplorer)=" + materialObject.hasFn(MFn.Type.kPhongExplorer), 2); Print(materialDependencyNode, 2, "Print ExportMaterial materialDependencyNode"); // Retreive Babylon Material dependency node MFnDependencyNode babylonAttributesDependencyNode = getBabylonMaterialNode(materialDependencyNode); // Standard material if (materialObject.hasFn(MFn.Type.kLambert)) { if (materialObject.hasFn(MFn.Type.kBlinn)) { RaiseMessage("Blinn shader", 2); } else if (materialObject.hasFn(MFn.Type.kPhong)) { RaiseMessage("Phong shader", 2); } else if (materialObject.hasFn(MFn.Type.kPhongExplorer)) { RaiseMessage("Phong E shader", 2); } else { RaiseMessage("Lambert shader", 2); } var lambertShader = new MFnLambertShader(materialObject); RaiseVerbose("typeId=" + lambertShader.typeId, 2); RaiseVerbose("typeName=" + lambertShader.typeName, 2); RaiseVerbose("color=" + lambertShader.color.toString(), 2); RaiseVerbose("transparency=" + lambertShader.transparency.toString(), 2); RaiseVerbose("ambientColor=" + lambertShader.ambientColor.toString(), 2); RaiseVerbose("incandescence=" + lambertShader.incandescence.toString(), 2); RaiseVerbose("diffuseCoeff=" + lambertShader.diffuseCoeff, 2); RaiseVerbose("translucenceCoeff=" + lambertShader.translucenceCoeff, 2); BabylonStandardMaterial babylonMaterial = new BabylonStandardMaterial(id) { name = name, diffuse = lambertShader.color.toArrayRGB() }; // User custom attributes babylonMaterial.metadata = ExportCustomAttributeFromMaterial(babylonMaterial); bool isTransparencyModeFromBabylonMaterialNode = false; if (babylonAttributesDependencyNode != null) { // Transparency mode if (babylonAttributesDependencyNode.hasAttribute("babylonTransparencyMode")) { int transparencyMode = babylonAttributesDependencyNode.findPlug("babylonTransparencyMode").asInt(); babylonMaterial.transparencyMode = transparencyMode; isTransparencyModeFromBabylonMaterialNode = true; } } // Maya ambient <=> babylon emissive babylonMaterial.emissive = lambertShader.ambientColor.toArrayRGB(); babylonMaterial.linkEmissiveWithDiffuse = true; // Incandescence (or Illumination) is not exported if (isTransparencyModeFromBabylonMaterialNode == false || babylonMaterial.transparencyMode != 0) { // If transparency is not a shade of grey (shade of grey <=> R=G=B) if (lambertShader.transparency[0] != lambertShader.transparency[1] || lambertShader.transparency[0] != lambertShader.transparency[2]) { RaiseWarning("Transparency color is not a shade of grey. Only it's R channel is used.", 2); } // Convert transparency to opacity babylonMaterial.alpha = 1.0f - lambertShader.transparency[0]; } // Specular power if (materialObject.hasFn(MFn.Type.kReflect)) { var reflectShader = new MFnReflectShader(materialObject); RaiseVerbose("specularColor=" + reflectShader.specularColor.toString(), 2); RaiseVerbose("reflectivity=" + reflectShader.reflectivity, 2); RaiseVerbose("reflectedColor=" + reflectShader.reflectedColor.toString(), 2); babylonMaterial.specular = reflectShader.specularColor.toArrayRGB(); if (materialObject.hasFn(MFn.Type.kBlinn)) { MFnBlinnShader blinnShader = new MFnBlinnShader(materialObject); babylonMaterial.specularPower = (1.0f - blinnShader.eccentricity) * 256; } else if (materialObject.hasFn(MFn.Type.kPhong)) { MFnPhongShader phongShader = new MFnPhongShader(materialObject); float glossiness = (float)Math.Log(phongShader.cosPower, 2) * 10; babylonMaterial.specularPower = glossiness / 100 * 256; } else if (materialObject.hasFn(MFn.Type.kPhongExplorer)) { MFnPhongEShader phongEShader = new MFnPhongEShader(materialObject); // No use of phongE.whiteness and phongE.highlightSize babylonMaterial.specularPower = (1.0f - phongEShader.roughness) * 256; } else { RaiseWarning("Unknown reflect shader type: " + reflectShader.typeName + ". Specular power is default 64. Consider using a Blinn or Phong shader instead.", 2); } } // TODO //babylonMaterial.wireframe = stdMat.Wire; // --- Textures --- babylonMaterial.diffuseTexture = ExportTexture(materialDependencyNode, "color", babylonScene); babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "ambientColor", babylonScene); // Maya ambient <=> babylon emissive babylonMaterial.bumpTexture = ExportTexture(materialDependencyNode, "normalCamera", babylonScene); if (isTransparencyModeFromBabylonMaterialNode == false || babylonMaterial.transparencyMode != 0) { babylonMaterial.opacityTexture = ExportTexture(materialDependencyNode, "transparency", babylonScene, false, true); } if (materialObject.hasFn(MFn.Type.kReflect)) { babylonMaterial.specularTexture = ExportTexture(materialDependencyNode, "specularColor", babylonScene); babylonMaterial.reflectionTexture = ExportTexture(materialDependencyNode, "reflectedColor", babylonScene, true, false, true); } if (isTransparencyModeFromBabylonMaterialNode == false && (babylonMaterial.alpha != 1.0f || (babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.hasAlpha) || babylonMaterial.opacityTexture != null)) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; } // Constraints if (babylonMaterial.diffuseTexture != null) { babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f }; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new float[] { 0, 0, 0 }; } if (babylonMaterial.transparencyMode == (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST) { // Set the alphaCutOff value explicitely to avoid different interpretations on different engines // Use the glTF default value rather than the babylon one babylonMaterial.alphaCutOff = 0.5f; } if (babylonAttributesDependencyNode == null) { // Create Babylon Material dependency node babylonStandardMaterialNode.Create(materialDependencyNode); // Retreive Babylon Material dependency node babylonAttributesDependencyNode = getBabylonMaterialNode(materialDependencyNode); } if (babylonAttributesDependencyNode != null) { // Ensure all attributes are setup babylonStandardMaterialNode.Init(babylonAttributesDependencyNode, babylonMaterial); RaiseVerbose("Babylon Attributes of " + babylonAttributesDependencyNode.name, 2); // Common attributes ExportCommonBabylonAttributes(babylonAttributesDependencyNode, babylonMaterial); // Special treatment for Unlit if (babylonMaterial.isUnlit) { if ((babylonMaterial.emissive != null && (babylonMaterial.emissive[0] != 0 || babylonMaterial.emissive[1] != 0 || babylonMaterial.emissive[2] != 0)) || (babylonMaterial.emissiveTexture != null) || (babylonMaterial.emissiveFresnelParameters != null)) { RaiseWarning("Material is unlit. Emission is discarded and replaced by diffuse.", 2); } // Copy diffuse to emissive babylonMaterial.emissive = babylonMaterial.diffuse; babylonMaterial.emissiveTexture = babylonMaterial.diffuseTexture; babylonMaterial.emissiveFresnelParameters = babylonMaterial.diffuseFresnelParameters; babylonMaterial.disableLighting = true; babylonMaterial.linkEmissiveWithDiffuse = false; } // Special treatment for "Alpha test" transparency mode if (babylonMaterial.transparencyMode == (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST && ((babylonMaterial.diffuseTexture != null && babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture.originalPath != babylonMaterial.opacityTexture.originalPath) || (babylonMaterial.diffuseTexture == null && babylonMaterial.opacityTexture != null))) { // Base color and alpha files need to be merged into a single file Color defaultColor = Color.FromArgb((int)(babylonMaterial.diffuse[0] * 255), (int)(babylonMaterial.diffuse[1] * 255), (int)(babylonMaterial.diffuse[2] * 255)); MFnDependencyNode baseColorTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "color"); MFnDependencyNode opacityTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "transparency"); babylonMaterial.diffuseTexture = ExportBaseColorAlphaTexture(baseColorTextureDependencyNode, opacityTextureDependencyNode, babylonScene, name, defaultColor, babylonMaterial.alpha); babylonMaterial.opacityTexture = null; babylonMaterial.alpha = 1.0f; } } babylonScene.MaterialsList.Add(babylonMaterial); } // Stingray PBS material else if (isStingrayPBSMaterial(materialDependencyNode)) { RaiseMessage("Stingray shader", 2); var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial(id) { name = name }; // --- Global --- // Color3 babylonMaterial.baseColor = materialDependencyNode.findPlug("base_color").asFloatArray(); // Alpha string opacityAttributeName = "opacity"; if (materialDependencyNode.hasAttribute(opacityAttributeName)) { float opacityAttributeValue = materialDependencyNode.findPlug(opacityAttributeName).asFloat(); babylonMaterial.alpha = 1.0f - opacityAttributeValue; } // Metallic & roughness babylonMaterial.metallic = materialDependencyNode.findPlug("metallic").asFloat(); babylonMaterial.roughness = materialDependencyNode.findPlug("roughness").asFloat(); // Emissive float emissiveIntensity = materialDependencyNode.findPlug("emissive_intensity").asFloat(); // Factor emissive color with emissive intensity emissiveIntensity = Tools.Clamp(emissiveIntensity, 0f, 1f); babylonMaterial.emissive = materialDependencyNode.findPlug("emissive").asFloatArray().Multiply(emissiveIntensity); // --- Textures --- // Base color & alpha bool useColorMap = materialDependencyNode.findPlug("use_color_map").asBool(); bool useOpacityMap = false; string useOpacityMapAttributeName = "use_opacity_map"; if (materialDependencyNode.hasAttribute(useOpacityMapAttributeName)) { useOpacityMap = materialDependencyNode.findPlug(useOpacityMapAttributeName).asBool(); } if (materialDependencyNode.hasAttribute("mask_threshold")) // Preset "Masked" { if (useColorMap && useOpacityMap) { // Texture is assumed to be already merged babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "TEX_color_map", babylonScene, false, true); } else if (useColorMap || useOpacityMap) { // Merge Diffuse and Mask Color defaultColor = Color.FromArgb((int)(babylonMaterial.baseColor[0] * 255), (int)(babylonMaterial.baseColor[1] * 255), (int)(babylonMaterial.baseColor[2] * 255)); // In Maya, a Masked StingrayPBS material without opacity or mask textures is counted as being fully transparent // Such material is visible only when the mask threshold is set to 0 float defaultOpacity = 0; // Either use the color map MFnDependencyNode baseColorTextureDependencyNode = null; if (useColorMap) { baseColorTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "TEX_color_map"); } // Or the opacity map MFnDependencyNode opacityTextureDependencyNode = null; if (useOpacityMap) { opacityTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "TEX_color_map"); } // Merge default value and texture babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(baseColorTextureDependencyNode, opacityTextureDependencyNode, babylonScene, babylonMaterial.name, defaultColor, defaultOpacity); } else { // In Maya, a Masked StingrayPBS material without opacity or mask textures is counted as being fully transparent // Such material is visible only when the mask threshold is set to 0 babylonMaterial.alpha = 0; } } else { if (useColorMap || useOpacityMap) { // Force non use map to default value // Ex: if useOpacityMap == false, force alpha = 255 for all pixels. babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "TEX_color_map", babylonScene, false, useOpacityMap); } } if (babylonMaterial.transparencyMode == (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST) { // Set the alphaCutOff value explicitely to avoid different interpretations on different engines // Use the glTF default value rather than the babylon one babylonMaterial.alphaCutOff = 0.5f; } // Alpha cuttoff if (materialDependencyNode.hasAttribute("mask_threshold")) // Preset "Masked" { babylonMaterial.alphaCutOff = materialDependencyNode.findPlug("mask_threshold").asFloat(); } // Metallic, roughness, ambient occlusion bool useMetallicMap = materialDependencyNode.findPlug("use_metallic_map").asBool(); bool useRoughnessMap = materialDependencyNode.findPlug("use_roughness_map").asBool(); string useAOMapAttributeName = "use_ao_map"; bool useAOMap = materialDependencyNode.hasAttribute(useAOMapAttributeName) && materialDependencyNode.findPlug(useAOMapAttributeName).asBool(); MFnDependencyNode metallicTextureDependencyNode = useMetallicMap ? getTextureDependencyNode(materialDependencyNode, "TEX_metallic_map") : null; MFnDependencyNode roughnessTextureDependencyNode = useRoughnessMap ? getTextureDependencyNode(materialDependencyNode, "TEX_roughness_map") : null; MFnDependencyNode ambientOcclusionTextureDependencyNode = useAOMap ? getTextureDependencyNode(materialDependencyNode, "TEX_ao_map") : null; // Check if MR or ORM textures are already merged bool areTexturesAlreadyMerged = false; if (metallicTextureDependencyNode != null && roughnessTextureDependencyNode != null) { string sourcePathMetallic = getSourcePathFromFileTexture(metallicTextureDependencyNode); string sourcePathRoughness = getSourcePathFromFileTexture(roughnessTextureDependencyNode); if (sourcePathMetallic == sourcePathRoughness) { if (ambientOcclusionTextureDependencyNode != null) { string sourcePathAmbientOcclusion = getSourcePathFromFileTexture(ambientOcclusionTextureDependencyNode); if (sourcePathMetallic == sourcePathAmbientOcclusion) { // Metallic, roughness and ambient occlusion are already merged RaiseVerbose("Metallic, roughness and ambient occlusion are already merged", 2); BabylonTexture ormTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); babylonMaterial.metallicRoughnessTexture = ormTexture; babylonMaterial.occlusionTexture = ormTexture; areTexturesAlreadyMerged = true; } } else { // Metallic and roughness are already merged RaiseVerbose("Metallic and roughness are already merged", 2); BabylonTexture ormTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); babylonMaterial.metallicRoughnessTexture = ormTexture; areTexturesAlreadyMerged = true; } } } if (areTexturesAlreadyMerged == false) { if (metallicTextureDependencyNode != null || roughnessTextureDependencyNode != null) { // Merge metallic, roughness and ambient occlusion RaiseVerbose("Merge metallic, roughness and ambient occlusion", 2); BabylonTexture ormTexture = ExportORMTexture(babylonScene, metallicTextureDependencyNode, roughnessTextureDependencyNode, ambientOcclusionTextureDependencyNode, babylonMaterial.metallic, babylonMaterial.roughness); babylonMaterial.metallicRoughnessTexture = ormTexture; if (ambientOcclusionTextureDependencyNode != null) { babylonMaterial.occlusionTexture = ormTexture; } } else if (ambientOcclusionTextureDependencyNode != null) { // Simply export occlusion texture RaiseVerbose("Simply export occlusion texture", 2); babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTextureDependencyNode, babylonScene); } } // Normal if (materialDependencyNode.findPlug("use_normal_map").asBool()) { babylonMaterial.normalTexture = ExportTexture(materialDependencyNode, "TEX_normal_map", babylonScene); } // Emissive bool useEmissiveMap = materialDependencyNode.findPlug("use_emissive_map").asBool(); if (useEmissiveMap) { babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "TEX_emissive_map", babylonScene, false, false, false, emissiveIntensity); } // Constraints if (useColorMap) { babylonMaterial.baseColor = new[] { 1.0f, 1.0f, 1.0f }; } if (useOpacityMap) { babylonMaterial.alpha = 1.0f; } if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)) { if (materialDependencyNode.hasAttribute("mask_threshold")) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST; } else { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; } } if (useMetallicMap) { babylonMaterial.metallic = 1.0f; } if (useRoughnessMap) { babylonMaterial.roughness = 1.0f; } if (useEmissiveMap) { babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f }; } // User custom attributes babylonMaterial.metadata = ExportCustomAttributeFromMaterial(babylonMaterial); if (babylonAttributesDependencyNode == null) { // Create Babylon Material dependency node babylonStingrayPBSMaterialNode.Create(materialDependencyNode); // Retreive Babylon Material dependency node babylonAttributesDependencyNode = getBabylonMaterialNode(materialDependencyNode); } if (babylonAttributesDependencyNode != null) { // Ensure all attributes are setup babylonStingrayPBSMaterialNode.Init(babylonAttributesDependencyNode, babylonMaterial); RaiseVerbose("Babylon Attributes of " + babylonAttributesDependencyNode.name, 2); // Common attributes ExportCommonBabylonAttributes(babylonAttributesDependencyNode, babylonMaterial); babylonMaterial.doubleSided = !babylonMaterial.backFaceCulling; babylonMaterial._unlit = babylonMaterial.isUnlit; // Update displayed Transparency mode value based on StingrayPBS preset material MGlobal.executeCommand($"setAttr - l false {{ \"{babylonAttributesDependencyNode.name}.babylonTransparencyMode\" }}"); // Unlock attribute int babylonTransparencyMode = 0; if (materialDependencyNode.hasAttribute("mask_threshold")) { babylonTransparencyMode = 1; } else if (materialDependencyNode.hasAttribute("use_opacity_map")) { babylonTransparencyMode = 2; } MGlobal.executeCommand($"setAttr \"{babylonAttributesDependencyNode.name}.babylonTransparencyMode\" {babylonTransparencyMode};"); MGlobal.executeCommand($"setAttr - l true {{ \"{babylonAttributesDependencyNode.name}.babylonTransparencyMode\" }}"); // Lock it afterwards } babylonScene.MaterialsList.Add(babylonMaterial); } // Arnold Ai Standard Surface else if (isAiStandardSurface(materialDependencyNode)) { RaiseMessage("Ai Standard Surface shader", 2); var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial(id) { name = name }; // User custom attributes babylonMaterial.metadata = ExportCustomAttributeFromMaterial(babylonMaterial); // --- Global --- bool isTransparencyModeFromBabylonMaterialNode = false; if (babylonAttributesDependencyNode != null) { // Transparency mode if (babylonAttributesDependencyNode.hasAttribute("babylonTransparencyMode")) { babylonMaterial.transparencyMode = babylonAttributesDependencyNode.findPlug("babylonTransparencyMode").asInt(); isTransparencyModeFromBabylonMaterialNode = true; } } // Color3 float baseWeight = materialDependencyNode.findPlug("base").asFloat(); float[] baseColor = materialDependencyNode.findPlug("baseColor").asFloatArray(); babylonMaterial.baseColor = baseColor.Multiply(baseWeight); // Alpha MaterialDuplicationData materialDuplicationData = materialDuplicationDatas[id]; // If at least one mesh is Transparent and is using this material either directly or as a sub material if ((isTransparencyModeFromBabylonMaterialNode == false || babylonMaterial.transparencyMode != 0) && materialDuplicationData.isArnoldTransparent()) { float[] opacityAttributeValue = materialDependencyNode.findPlug("opacity").asFloatArray(); babylonMaterial.alpha = opacityAttributeValue[0]; } else { // Do not bother about alpha babylonMaterial.alpha = 1.0f; } // Metallic & roughness babylonMaterial.metallic = materialDependencyNode.findPlug("metalness").asFloat(); babylonMaterial.roughness = materialDependencyNode.findPlug("specularRoughness").asFloat(); // Emissive float emissionWeight = materialDependencyNode.findPlug("emission").asFloat(); babylonMaterial.emissive = materialDependencyNode.findPlug("emissionColor").asFloatArray().Multiply(emissionWeight); var list = new List <string>(); for (int i = 0; i < materialDependencyNode.attributeCount; i++) { var attr = materialDependencyNode.attribute((uint)i); var plug = materialDependencyNode.findPlug(attr); //string aliasName; //materialDependencyNode.getPlugsAlias(plug, out aliasName); System.Diagnostics.Debug.WriteLine(plug.name + i.ToString()); } // --- Clear Coat --- float coatWeight = materialDependencyNode.findPlug("coat").asFloat(); MFnDependencyNode intensityCoatTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "coat"); if (coatWeight > 0.0f || intensityCoatTextureDependencyNode != null) { babylonMaterial.clearCoat.isEnabled = true; babylonMaterial.clearCoat.indexOfRefraction = materialDependencyNode.findPlug("coatIOR").asFloat(); var coatRoughness = materialDependencyNode.findPlug("coatRoughness").asFloat(); MFnDependencyNode roughnessCoatTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "coatRoughness"); var coatTexture = ExportCoatTexture(intensityCoatTextureDependencyNode, roughnessCoatTextureDependencyNode, babylonScene, name, coatWeight, coatRoughness); if (coatTexture != null) { babylonMaterial.clearCoat.texture = coatTexture; babylonMaterial.clearCoat.roughness = 1.0f; babylonMaterial.clearCoat.intensity = 1.0f; } else { babylonMaterial.clearCoat.intensity = coatWeight; babylonMaterial.clearCoat.roughness = coatRoughness; } float[] coatColor = materialDependencyNode.findPlug("coatColor").asFloatArray(); if (coatColor[0] != 1.0f || coatColor[1] != 1.0f || coatColor[2] != 1.0f) { babylonMaterial.clearCoat.isTintEnabled = true; babylonMaterial.clearCoat.tintColor = coatColor; } babylonMaterial.clearCoat.tintTexture = ExportTexture(materialDependencyNode, "coatColor", babylonScene); if (babylonMaterial.clearCoat.tintTexture != null) { babylonMaterial.clearCoat.tintColor = new[] { 1.0f, 1.0f, 1.0f }; babylonMaterial.clearCoat.isTintEnabled = true; } // EyeBall deduction... babylonMaterial.clearCoat.tintThickness = 0.65f; babylonMaterial.clearCoat.bumpTexture = ExportTexture(materialDependencyNode, "coatNormal", babylonScene); } // --- Textures --- // Base color & alpha if ((isTransparencyModeFromBabylonMaterialNode == false || babylonMaterial.transparencyMode != 0) && materialDuplicationData.isArnoldTransparent()) { MFnDependencyNode baseColorTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "baseColor"); MFnDependencyNode opacityTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "opacity"); if (baseColorTextureDependencyNode != null && opacityTextureDependencyNode != null && getSourcePathFromFileTexture(baseColorTextureDependencyNode) == getSourcePathFromFileTexture(opacityTextureDependencyNode)) { // If the same file is used for base color and opacity // Base color and alpha are already merged into a single file babylonMaterial.baseTexture = ExportTexture(baseColorTextureDependencyNode, babylonScene, false, true); } else { // Base color and alpha files need to be merged into a single file Color _baseColor = Color.FromArgb((int)(baseColor[0] * 255), (int)(baseColor[1] * 255), (int)(baseColor[2] * 255)); babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(baseColorTextureDependencyNode, opacityTextureDependencyNode, babylonScene, name, _baseColor, babylonMaterial.alpha); } } else { // Base color only // Do not bother about alpha babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "baseColor", babylonScene); } // Metallic & roughness MFnDependencyNode metallicTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "metalness"); MFnDependencyNode roughnessTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "specularRoughness"); if (metallicTextureDependencyNode != null && roughnessTextureDependencyNode != null && getSourcePathFromFileTexture(metallicTextureDependencyNode) == getSourcePathFromFileTexture(roughnessTextureDependencyNode)) { // If the same file is used for metallic and roughness // Then we assume it's an ORM file (Red=Occlusion, Green=Roughness, Blue=Metallic) // Metallic and roughness are already merged into a single file babylonMaterial.metallicRoughnessTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); // Use same file for Ambient occlusion babylonMaterial.occlusionTexture = babylonMaterial.metallicRoughnessTexture; } else { // Metallic and roughness files need to be merged into a single file // Occlusion texture is not exported since aiStandardSurface material doesn't provide input for it babylonMaterial.metallicRoughnessTexture = ExportORMTexture(babylonScene, metallicTextureDependencyNode, roughnessTextureDependencyNode, null, babylonMaterial.metallic, babylonMaterial.roughness); } // Normal babylonMaterial.normalTexture = ExportTexture(materialDependencyNode, "normalCamera", babylonScene); // Emissive babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "emissionColor", babylonScene); // Constraints if (babylonMaterial.baseTexture != null) { babylonMaterial.baseColor = new[] { baseWeight, baseWeight, baseWeight }; babylonMaterial.alpha = 1.0f; } if (babylonMaterial.metallicRoughnessTexture != null) { babylonMaterial.metallic = 1.0f; babylonMaterial.roughness = 1.0f; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new[] { emissionWeight, emissionWeight, emissionWeight }; } // If this material is containing alpha data if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)) { if (isTransparencyModeFromBabylonMaterialNode == false) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; } // If this material is assigned to both Transparent and Opaque meshes (either directly or as a sub material) if (materialDuplicationData.isDuplicationRequired()) { // Duplicate material BabylonPBRMetallicRoughnessMaterial babylonMaterialCloned = DuplicateMaterial(babylonMaterial, materialDuplicationData); // Store duplicated material too babylonScene.MaterialsList.Add(babylonMaterialCloned); } } if (babylonMaterial.transparencyMode == (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHATEST) { // Set the alphaCutOff value explicitely to avoid different interpretations on different engines // Use the glTF default value rather than the babylon one babylonMaterial.alphaCutOff = 0.5f; } if (babylonAttributesDependencyNode == null) { // Create Babylon Material dependency node babylonAiStandardSurfaceMaterialNode.Create(materialDependencyNode); // Retreive Babylon Material dependency node babylonAttributesDependencyNode = getBabylonMaterialNode(materialDependencyNode); } if (babylonAttributesDependencyNode != null) { // Ensure all attributes are setup babylonAiStandardSurfaceMaterialNode.Init(babylonAttributesDependencyNode, babylonMaterial); RaiseVerbose("Babylon Attributes of " + babylonAttributesDependencyNode.name, 2); // Common attributes ExportCommonBabylonAttributes(babylonAttributesDependencyNode, babylonMaterial); babylonMaterial.doubleSided = !babylonMaterial.backFaceCulling; babylonMaterial._unlit = babylonMaterial.isUnlit; } if (fullPBR) { var fullPBRMaterial = new BabylonPBRMaterial(babylonMaterial); babylonScene.MaterialsList.Add(fullPBRMaterial); } else { babylonScene.MaterialsList.Add(babylonMaterial); } } else { RaiseWarning("Unsupported material type '" + materialObject.apiType + "' for material named '" + materialDependencyNode.name + "'", 2); } }
private void ExportMaterial(MFnDependencyNode materialDependencyNode, BabylonScene babylonScene) { MObject materialObject = materialDependencyNode.objectProperty; var name = materialDependencyNode.name; var id = materialDependencyNode.uuid().asString(); RaiseMessage(name, 1); RaiseVerbose("materialObject.hasFn(MFn.Type.kBlinn)=" + materialObject.hasFn(MFn.Type.kBlinn), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhong)=" + materialObject.hasFn(MFn.Type.kPhong), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhongExplorer)=" + materialObject.hasFn(MFn.Type.kPhongExplorer), 2); Print(materialDependencyNode, 2, "Print ExportMaterial materialDependencyNode"); // Standard material if (materialObject.hasFn(MFn.Type.kLambert)) { if (materialObject.hasFn(MFn.Type.kBlinn)) { RaiseMessage("Blinn shader", 2); } else if (materialObject.hasFn(MFn.Type.kPhong)) { RaiseMessage("Phong shader", 2); } else if (materialObject.hasFn(MFn.Type.kPhongExplorer)) { RaiseMessage("Phong E shader", 2); } else { RaiseMessage("Lambert shader", 2); } var lambertShader = new MFnLambertShader(materialObject); RaiseVerbose("typeId=" + lambertShader.typeId, 2); RaiseVerbose("typeName=" + lambertShader.typeName, 2); RaiseVerbose("color=" + lambertShader.color.toString(), 2); RaiseVerbose("transparency=" + lambertShader.transparency.toString(), 2); RaiseVerbose("ambientColor=" + lambertShader.ambientColor.toString(), 2); RaiseVerbose("incandescence=" + lambertShader.incandescence.toString(), 2); RaiseVerbose("diffuseCoeff=" + lambertShader.diffuseCoeff, 2); RaiseVerbose("translucenceCoeff=" + lambertShader.translucenceCoeff, 2); var babylonMaterial = new BabylonStandardMaterial { name = name, id = id, diffuse = lambertShader.color.toArrayRGB(), alpha = 1.0f - lambertShader.transparency[0] }; // Maya ambient <=> babylon emissive babylonMaterial.emissive = lambertShader.ambientColor.toArrayRGB(); babylonMaterial.linkEmissiveWithDiffuse = true; // Incandescence (or Illumination) is not exported // If transparency is not a shade of grey (shade of grey <=> R=G=B) if (lambertShader.transparency[0] != lambertShader.transparency[1] || lambertShader.transparency[0] != lambertShader.transparency[2]) { RaiseWarning("Transparency color is not a shade of grey. Only it's R channel is used.", 2); } // Convert transparency to opacity babylonMaterial.alpha = 1.0f - lambertShader.transparency[0]; // Specular power if (materialObject.hasFn(MFn.Type.kReflect)) { var reflectShader = new MFnReflectShader(materialObject); RaiseVerbose("specularColor=" + reflectShader.specularColor.toString(), 2); RaiseVerbose("reflectivity=" + reflectShader.reflectivity, 2); RaiseVerbose("reflectedColor=" + reflectShader.reflectedColor.toString(), 2); babylonMaterial.specular = reflectShader.specularColor.toArrayRGB(); if (materialObject.hasFn(MFn.Type.kBlinn)) { MFnBlinnShader blinnShader = new MFnBlinnShader(materialObject); babylonMaterial.specularPower = (1.0f - blinnShader.eccentricity) * 256; } else if (materialObject.hasFn(MFn.Type.kPhong)) { MFnPhongShader phongShader = new MFnPhongShader(materialObject); float glossiness = (float)Math.Log(phongShader.cosPower, 2) * 10; babylonMaterial.specularPower = glossiness / 100 * 256; } else if (materialObject.hasFn(MFn.Type.kPhongExplorer)) { MFnPhongEShader phongEShader = new MFnPhongEShader(materialObject); // No use of phongE.whiteness and phongE.highlightSize babylonMaterial.specularPower = (1.0f - phongEShader.roughness) * 256; } else { RaiseWarning("Unknown reflect shader type: " + reflectShader.typeName + ". Specular power is default 64. Consider using a Blinn or Phong shader instead.", 2); } } // TODO //babylonMaterial.backFaceCulling = !stdMat.TwoSided; //babylonMaterial.wireframe = stdMat.Wire; // --- Textures --- babylonMaterial.diffuseTexture = ExportTexture(materialDependencyNode, "color", babylonScene); babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "ambientColor", babylonScene); // Maya ambient <=> babylon emissive babylonMaterial.bumpTexture = ExportTexture(materialDependencyNode, "normalCamera", babylonScene); babylonMaterial.opacityTexture = ExportTexture(materialDependencyNode, "transparency", babylonScene, false, true); if (materialObject.hasFn(MFn.Type.kReflect)) { babylonMaterial.specularTexture = ExportTexture(materialDependencyNode, "specularColor", babylonScene); babylonMaterial.reflectionTexture = ExportTexture(materialDependencyNode, "reflectedColor", babylonScene, true, false, true); } // Constraints if (babylonMaterial.diffuseTexture != null) { babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f }; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new float[] { 0, 0, 0 }; } babylonScene.MaterialsList.Add(babylonMaterial); } // Stingray PBS material else if (isStingrayPBSMaterial(materialDependencyNode)) { RaiseMessage("Stingray shader", 2); var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial { name = name, id = id }; // --- Global --- // Color3 babylonMaterial.baseColor = materialDependencyNode.findPlug("base_color").asFloatArray(); // Alpha string opacityAttributeName = "opacity"; if (materialDependencyNode.hasAttribute(opacityAttributeName)) { float opacityAttributeValue = materialDependencyNode.findPlug(opacityAttributeName).asFloatProperty; babylonMaterial.alpha = 1.0f - opacityAttributeValue; } // Metallic & roughness babylonMaterial.metallic = materialDependencyNode.findPlug("metallic").asFloatProperty; babylonMaterial.roughness = materialDependencyNode.findPlug("roughness").asFloatProperty; // Emissive float emissiveIntensity = materialDependencyNode.findPlug("emissive_intensity").asFloatProperty; // Factor emissive color with emissive intensity emissiveIntensity = Tools.Clamp(emissiveIntensity, 0f, 1f); babylonMaterial.emissive = materialDependencyNode.findPlug("emissive").asFloatArray().Multiply(emissiveIntensity); // --- Textures --- // Base color & alpha bool useColorMap = materialDependencyNode.findPlug("use_color_map").asBoolProperty; bool useOpacityMap = false; string useOpacityMapAttributeName = "use_opacity_map"; if (materialDependencyNode.hasAttribute(useOpacityMapAttributeName)) { useOpacityMap = materialDependencyNode.findPlug(useOpacityMapAttributeName).asBoolProperty; } if (useColorMap || useOpacityMap) { // TODO - Force non use map to default value ? // Ex: if useOpacityMap == false, force alpha = 255 for all pixels. //babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(materialDependencyNode, useColorMap, useOpacityMap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene); babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "TEX_color_map", babylonScene, false, useOpacityMap); } // Metallic, roughness, ambient occlusion bool useMetallicMap = materialDependencyNode.findPlug("use_metallic_map").asBoolProperty; bool useRoughnessMap = materialDependencyNode.findPlug("use_roughness_map").asBoolProperty; string useAOMapAttributeName = "use_ao_map"; bool useAOMap = materialDependencyNode.hasAttribute(useAOMapAttributeName) && materialDependencyNode.findPlug(useAOMapAttributeName).asBoolProperty; MFnDependencyNode metallicTextureDependencyNode = useMetallicMap ? getTextureDependencyNode(materialDependencyNode, "TEX_metallic_map") : null; MFnDependencyNode roughnessTextureDependencyNode = useRoughnessMap ? getTextureDependencyNode(materialDependencyNode, "TEX_roughness_map") : null; MFnDependencyNode ambientOcclusionTextureDependencyNode = useAOMap ? getTextureDependencyNode(materialDependencyNode, "TEX_ao_map") : null; // Check if MR or ORM textures are already merged bool areTexturesAlreadyMerged = false; if (metallicTextureDependencyNode != null && roughnessTextureDependencyNode != null) { string sourcePathMetallic = getSourcePathFromFileTexture(metallicTextureDependencyNode); string sourcePathRoughness = getSourcePathFromFileTexture(roughnessTextureDependencyNode); if (sourcePathMetallic == sourcePathRoughness) { if (ambientOcclusionTextureDependencyNode != null) { string sourcePathAmbientOcclusion = getSourcePathFromFileTexture(ambientOcclusionTextureDependencyNode); if (sourcePathMetallic == sourcePathAmbientOcclusion) { // Metallic, roughness and ambient occlusion are already merged RaiseVerbose("Metallic, roughness and ambient occlusion are already merged", 2); BabylonTexture ormTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); babylonMaterial.metallicRoughnessTexture = ormTexture; babylonMaterial.occlusionTexture = ormTexture; areTexturesAlreadyMerged = true; } } else { // Metallic and roughness are already merged RaiseVerbose("Metallic and roughness are already merged", 2); BabylonTexture ormTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); babylonMaterial.metallicRoughnessTexture = ormTexture; areTexturesAlreadyMerged = true; } } } if (areTexturesAlreadyMerged == false) { if (metallicTextureDependencyNode != null || roughnessTextureDependencyNode != null) { // Merge metallic, roughness and ambient occlusion RaiseVerbose("Merge metallic, roughness and ambient occlusion", 2); BabylonTexture ormTexture = ExportORMTexture(babylonScene, metallicTextureDependencyNode, roughnessTextureDependencyNode, ambientOcclusionTextureDependencyNode, babylonMaterial.metallic, babylonMaterial.roughness); babylonMaterial.metallicRoughnessTexture = ormTexture; if (ambientOcclusionTextureDependencyNode != null) { babylonMaterial.occlusionTexture = ormTexture; } } else if (ambientOcclusionTextureDependencyNode != null) { // Simply export occlusion texture RaiseVerbose("Simply export occlusion texture", 2); babylonMaterial.occlusionTexture = ExportTexture(ambientOcclusionTextureDependencyNode, babylonScene); } } // Normal if (materialDependencyNode.findPlug("use_normal_map").asBoolProperty) { babylonMaterial.normalTexture = ExportTexture(materialDependencyNode, "TEX_normal_map", babylonScene); } // Emissive bool useEmissiveMap = materialDependencyNode.findPlug("use_emissive_map").asBoolProperty; if (useEmissiveMap) { babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "TEX_emissive_map", babylonScene, false, false, false, emissiveIntensity); } // Constraints if (useColorMap) { babylonMaterial.baseColor = new[] { 1.0f, 1.0f, 1.0f }; } if (useOpacityMap) { babylonMaterial.alpha = 1.0f; } if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; } if (useMetallicMap) { babylonMaterial.metallic = 1.0f; } if (useRoughnessMap) { babylonMaterial.roughness = 1.0f; } if (useEmissiveMap) { babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f }; } babylonScene.MaterialsList.Add(babylonMaterial); } // Arnold Ai Standard Surface else if (isAiStandardSurface(materialDependencyNode)) { RaiseMessage("Ai Standard Surface shader", 2); var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial { name = name, id = id }; // --- Global --- // Color3 float baseWeight = materialDependencyNode.findPlug("base").asFloatProperty; float[] baseColor = materialDependencyNode.findPlug("baseColor").asFloatArray(); babylonMaterial.baseColor = baseColor.Multiply(baseWeight); // Alpha MaterialDuplicationData materialDuplicationData = materialDuplicationDatas[id]; // If at least one mesh is Transparent and is using this material either directly or as a sub material if (materialDuplicationData.isArnoldTransparent()) { float[] opacityAttributeValue = materialDependencyNode.findPlug("opacity").asFloatArray(); babylonMaterial.alpha = opacityAttributeValue[0]; } else { // Do not bother about alpha babylonMaterial.alpha = 1.0f; } // Metallic & roughness babylonMaterial.metallic = materialDependencyNode.findPlug("metalness").asFloatProperty; babylonMaterial.roughness = materialDependencyNode.findPlug("specularRoughness").asFloatProperty; // Emissive float emissionWeight = materialDependencyNode.findPlug("emission").asFloatProperty; babylonMaterial.emissive = materialDependencyNode.findPlug("emissionColor").asFloatArray().Multiply(emissionWeight); // --- Textures --- // Base color & alpha if (materialDuplicationData.isArnoldTransparent()) { MFnDependencyNode baseColorTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "baseColor"); MFnDependencyNode opacityTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "opacity"); if (baseColorTextureDependencyNode != null && opacityTextureDependencyNode != null && getSourcePathFromFileTexture(baseColorTextureDependencyNode) == getSourcePathFromFileTexture(opacityTextureDependencyNode)) { // If the same file is used for base color and opacity // Base color and alpha are already merged into a single file babylonMaterial.baseTexture = ExportTexture(baseColorTextureDependencyNode, babylonScene, false, true); } else { // Base color and alpha files need to be merged into a single file Color _baseColor = Color.FromArgb((int)baseColor[0] * 255, (int)baseColor[1] * 255, (int)baseColor[2] * 255); babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(baseColorTextureDependencyNode, opacityTextureDependencyNode, babylonScene, name, _baseColor, babylonMaterial.alpha); } } else { // Base color only // Do not bother about alpha babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "baseColor", babylonScene); } // Metallic & roughness MFnDependencyNode metallicTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "metalness"); MFnDependencyNode roughnessTextureDependencyNode = getTextureDependencyNode(materialDependencyNode, "specularRoughness"); if (metallicTextureDependencyNode != null && roughnessTextureDependencyNode != null && getSourcePathFromFileTexture(metallicTextureDependencyNode) == getSourcePathFromFileTexture(roughnessTextureDependencyNode)) { // If the same file is used for metallic and roughness // Then we assume it's an ORM file (Red=Occlusion, Green=Roughness, Blue=Metallic) // Metallic and roughness are already merged into a single file babylonMaterial.metallicRoughnessTexture = ExportTexture(metallicTextureDependencyNode, babylonScene); // Use same file for Ambient occlusion babylonMaterial.occlusionTexture = babylonMaterial.metallicRoughnessTexture; } else { // Metallic and roughness files need to be merged into a single file // Occlusion texture is not exported since aiStandardSurface material doesn't provide input for it babylonMaterial.metallicRoughnessTexture = ExportORMTexture(babylonScene, metallicTextureDependencyNode, roughnessTextureDependencyNode, null, babylonMaterial.metallic, babylonMaterial.roughness); } // Normal babylonMaterial.normalTexture = ExportTexture(materialDependencyNode, "normalCamera", babylonScene); // Emissive babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "emissionColor", babylonScene); // Constraints if (babylonMaterial.baseTexture != null) { babylonMaterial.baseColor = new[] { baseWeight, baseWeight, baseWeight }; babylonMaterial.alpha = 1.0f; } if (babylonMaterial.metallicRoughnessTexture != null) { babylonMaterial.metallic = 1.0f; babylonMaterial.roughness = 1.0f; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new[] { emissionWeight, emissionWeight, emissionWeight }; } // If this material is containing alpha data if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; // If this material is assigned to both Transparent and Opaque meshes (either directly or as a sub material) if (materialDuplicationData.isDuplicationRequired()) { // Duplicate material BabylonPBRMetallicRoughnessMaterial babylonMaterialCloned = DuplicateMaterial(babylonMaterial, materialDuplicationData); // Store duplicated material too babylonScene.MaterialsList.Add(babylonMaterialCloned); } } babylonScene.MaterialsList.Add(babylonMaterial); } else { RaiseWarning("Unsupported material type '" + materialObject.apiType + "' for material named '" + materialDependencyNode.name + "'", 2); } }
private void ExportMaterial(MFnDependencyNode materialDependencyNode, BabylonScene babylonScene) { MObject materialObject = materialDependencyNode.objectProperty; var name = materialDependencyNode.name; var id = materialDependencyNode.uuid().asString(); RaiseMessage(name, 1); RaiseVerbose("materialObject.hasFn(MFn.Type.kBlinn)=" + materialObject.hasFn(MFn.Type.kBlinn), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhong)=" + materialObject.hasFn(MFn.Type.kPhong), 2); RaiseVerbose("materialObject.hasFn(MFn.Type.kPhongExplorer)=" + materialObject.hasFn(MFn.Type.kPhongExplorer), 2); Print(materialDependencyNode, 2, "Print ExportMaterial materialDependencyNode"); // Standard material if (materialObject.hasFn(MFn.Type.kLambert)) { RaiseMessage("Lambert shader", 2); var lambertShader = new MFnLambertShader(materialObject); RaiseVerbose("typeId=" + lambertShader.typeId, 2); RaiseVerbose("typeName=" + lambertShader.typeName, 2); RaiseVerbose("color=" + lambertShader.color.toString(), 2); RaiseVerbose("transparency=" + lambertShader.transparency.toString(), 2); RaiseVerbose("ambientColor=" + lambertShader.ambientColor.toString(), 2); RaiseVerbose("incandescence=" + lambertShader.incandescence.toString(), 2); RaiseVerbose("diffuseCoeff=" + lambertShader.diffuseCoeff, 2); RaiseVerbose("translucenceCoeff=" + lambertShader.translucenceCoeff, 2); var babylonMaterial = new BabylonStandardMaterial { name = name, id = id, ambient = lambertShader.ambientColor.toArrayRGB(), diffuse = lambertShader.color.toArrayRGB(), emissive = lambertShader.incandescence.toArrayRGB(), alpha = 1.0f - lambertShader.transparency[0] }; // If transparency is not a shade of grey (shade of grey <=> R=G=B) if (lambertShader.transparency[0] != lambertShader.transparency[1] || lambertShader.transparency[0] != lambertShader.transparency[2]) { RaiseWarning("Transparency color is not a shade of grey. Only it's R channel is used.", 2); } // Convert transparency to opacity babylonMaterial.alpha = 1.0f - lambertShader.transparency[0]; // Specular power if (materialObject.hasFn(MFn.Type.kReflect)) { var reflectShader = new MFnReflectShader(materialObject); RaiseVerbose("specularColor=" + reflectShader.specularColor.toString(), 2); RaiseVerbose("reflectivity=" + reflectShader.reflectivity, 2); RaiseVerbose("reflectedColor=" + reflectShader.reflectedColor.toString(), 2); babylonMaterial.specular = reflectShader.specularColor.toArrayRGB(); if (materialObject.hasFn(MFn.Type.kBlinn)) { MFnBlinnShader blinnShader = new MFnBlinnShader(materialObject); babylonMaterial.specularPower = (1.0f - blinnShader.eccentricity) * 256; } else if (materialObject.hasFn(MFn.Type.kPhong)) { MFnPhongShader phongShader = new MFnPhongShader(materialObject); float glossiness = (float)Math.Log(phongShader.cosPower, 2) * 10; babylonMaterial.specularPower = glossiness / 100 * 256; } else if (materialObject.hasFn(MFn.Type.kPhongExplorer)) { MFnPhongEShader phongEShader = new MFnPhongEShader(materialObject); // No use of phongE.whiteness and phongE.highlightSize babylonMaterial.specularPower = (1.0f - phongEShader.roughness) * 256; } else { RaiseWarning("Unknown reflect shader type: " + reflectShader.typeName + ". Specular power is default 64. Consider using a Blinn or Phong shader instead.", 2); } } // TODO //babylonMaterial.backFaceCulling = !stdMat.TwoSided; //babylonMaterial.wireframe = stdMat.Wire; // Textures babylonMaterial.diffuseTexture = ExportTexture(materialDependencyNode, "color", babylonScene); babylonMaterial.ambientTexture = ExportTexture(materialDependencyNode, "ambientColor", babylonScene); babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "incandescence", babylonScene); babylonMaterial.bumpTexture = ExportTexture(materialDependencyNode, "normalCamera", babylonScene); // TODO - Convert transparency to opacity? babylonMaterial.opacityTexture = ExportTexture(materialDependencyNode, "transparency", babylonScene, false, true); if (materialObject.hasFn(MFn.Type.kReflect)) { babylonMaterial.specularTexture = ExportTexture(materialDependencyNode, "specularColor", babylonScene); babylonMaterial.reflectionTexture = ExportTexture(materialDependencyNode, "reflectedColor", babylonScene, true, false, true); } // Constraints if (babylonMaterial.diffuseTexture != null) { babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f }; } if (babylonMaterial.emissiveTexture != null) { babylonMaterial.emissive = new float[] { 0, 0, 0 }; } babylonScene.MaterialsList.Add(babylonMaterial); } // PBR material else if (isPBRMaterial(materialDependencyNode)) { RaiseMessage("Stingray shader", 2); var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial { name = name, id = id }; // --- Global --- // Color3 babylonMaterial.baseColor = materialDependencyNode.findPlug("base_color").asFloatArray(); // Alpha string opacityAttributeName = "opacity"; if (materialDependencyNode.hasAttribute(opacityAttributeName)) { float opacityAttributeValue = materialDependencyNode.findPlug(opacityAttributeName).asFloatProperty; babylonMaterial.alpha = 1.0f - opacityAttributeValue; } // Metallic & roughness babylonMaterial.metallic = materialDependencyNode.findPlug("metallic").asFloatProperty; babylonMaterial.roughness = materialDependencyNode.findPlug("roughness").asFloatProperty; // Emissive float emissiveIntensity = materialDependencyNode.findPlug("emissive_intensity").asFloatProperty; // Factor emissive color with emissive intensity emissiveIntensity = Tools.Clamp(emissiveIntensity, 0f, 1f); babylonMaterial.emissive = materialDependencyNode.findPlug("emissive").asFloatArray(); for (int i = 0; i < babylonMaterial.emissive.Length; i++) { babylonMaterial.emissive[i] *= emissiveIntensity; } // --- Textures --- // Base color & alpha bool useColorMap = materialDependencyNode.findPlug("use_color_map").asBoolProperty; bool useOpacityMap = false; string useOpacityMapAttributeName = "use_opacity_map"; if (materialDependencyNode.hasAttribute(useOpacityMapAttributeName)) { useOpacityMap = materialDependencyNode.findPlug(useOpacityMapAttributeName).asBoolProperty; } if (useColorMap || useOpacityMap) { // TODO - Force non use map to default value ? // Ex: if useOpacityMap == false, force alpha = 255 for all pixels. //babylonMaterial.baseTexture = ExportBaseColorAlphaTexture(materialDependencyNode, useColorMap, useOpacityMap, babylonMaterial.baseColor, babylonMaterial.alpha, babylonScene); babylonMaterial.baseTexture = ExportTexture(materialDependencyNode, "TEX_color_map", babylonScene, false, useOpacityMap); } // Metallic & roughness bool useMetallicMap = materialDependencyNode.findPlug("use_metallic_map").asBoolProperty; bool useRoughnessMap = materialDependencyNode.findPlug("use_roughness_map").asBoolProperty; babylonMaterial.metallicRoughnessTexture = ExportMetallicRoughnessTexture(materialDependencyNode, useMetallicMap, useRoughnessMap, babylonScene, name); if (materialDependencyNode.findPlug("use_normal_map").asBoolProperty) { babylonMaterial.normalTexture = ExportTexture(materialDependencyNode, "TEX_normal_map", babylonScene); } // Emissive bool useEmissiveMap = materialDependencyNode.findPlug("use_emissive_map").asBoolProperty; if (useEmissiveMap) { babylonMaterial.emissiveTexture = ExportTexture(materialDependencyNode, "TEX_emissive_map", babylonScene, false, false, false, emissiveIntensity); } // Ambient occlusion string useAOMapAttributeName = "use_ao_map"; if (materialDependencyNode.hasAttribute(useAOMapAttributeName) && materialDependencyNode.findPlug(useAOMapAttributeName).asBoolProperty) { babylonMaterial.occlusionTexture = ExportTexture(materialDependencyNode, "TEX_ao_map", babylonScene); } // Constraints if (useColorMap) { babylonMaterial.baseColor = new[] { 1.0f, 1.0f, 1.0f }; } if (useOpacityMap) { babylonMaterial.alpha = 1.0f; } if (babylonMaterial.alpha != 1.0f || (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)) { babylonMaterial.transparencyMode = (int)BabylonPBRMetallicRoughnessMaterial.TransparencyMode.ALPHABLEND; } if (useMetallicMap) { babylonMaterial.metallic = 1.0f; } if (useRoughnessMap) { babylonMaterial.roughness = 1.0f; } if (useEmissiveMap) { babylonMaterial.emissive = new[] { 1.0f, 1.0f, 1.0f }; } babylonScene.MaterialsList.Add(babylonMaterial); } else { RaiseWarning("Unsupported material type '" + materialObject.apiType + "' for material named '" + materialDependencyNode.name + "'", 2); } }