protected bool CreateTextureParameter(FBXImporter.Material _Material, string _PropertyName, Scene.Materials.MaterialParameters _MaterialParameters, string _ParameterName, string _OpacityPropertyName) { FBXImporter.ObjectProperty Property = _Material.FindProperty(_PropertyName); if (Property == null) { return(false); // No such property... } if (Property.Textures.Length == 0) { return(false); // That property has no texture... } // Check for opacity string OpacityTextureRelativeFileName = null; if (_OpacityPropertyName != null) { FBXImporter.ObjectProperty OpacityProperty = _Material.FindProperty(_OpacityPropertyName); if (OpacityProperty != null && OpacityProperty.Textures.Length != 0) { OpacityTextureRelativeFileName = OpacityProperty.Textures[0].RelativeFileName; } } // Create the parameter with that texture Scene.Materials.Texture2D Tex = m_Scene.CreateTexture(Property.Textures[0].RelativeFileName, OpacityTextureRelativeFileName, Property.Textures[0].UseMipMap); _MaterialParameters.CreateParameter(_ParameterName, Scene.Materials.MaterialParameters.PARAMETER_TYPE.TEXTURE2D).AsTexture2D.Value = Tex; return(true); }
/// <summary> /// Creates a texture parameter from a material property that contains a texture (e.g. DiffuseColor, SpecularColor, etc.) /// </summary> /// <param name="_Material"></param> /// <param name="_PropertyName"></param> /// <param name="_MaterialParameters"></param> /// <param name="_ParameterName"></param> /// <returns>True if a texture is available</returns> protected bool CreateTextureParameter(FBXImporter.Material _Material, string _PropertyName, Scene.Materials.MaterialParameters _MaterialParameters, string _ParameterName) { return(CreateTextureParameter(_Material, _PropertyName, _MaterialParameters, _ParameterName, null)); }
/// <summary> /// Attempts to map FBX materials to render techniques /// </summary> /// <param name="_Materials">The list of materials to process</param> protected void ProcessMaterials(FBXImporter.Material[] _Materials) { m_Material2Parameters.Clear(); foreach (FBXImporter.Material Mat in _Materials) { Scene.Materials.MaterialParameters MatParams = null; // DEBUG // if ( Mat.Name == "sp_00_svod" ) // MatParams = null; // DEBUG if (m_MaterialsDatabase != null) { // Handle the special case of scenes that were exported as OBJ format and whos material informations lie in the diffuse color "texture" FBXImporter.ObjectProperty DiffuseColorProperty = Mat.FindProperty("DiffuseColor"); if (DiffuseColorProperty != null && DiffuseColorProperty.Textures.Length > 0) { string PseudoTextureName = DiffuseColorProperty.Textures[0].AbsoluteFileName; // Actually a material name! MaterialsDatabase.Material MatOverride = m_MaterialsDatabase.FindByName(PseudoTextureName); if (MatOverride != null) { // Replace this material's textures by the actual material's textures (does it make sense? ^^) if (MatOverride.TextureDiffuse != null) { FBXImporter.ObjectProperty TextureProperty = Mat.FindProperty("DiffuseColor"); if (TextureProperty != null) { TextureProperty.Textures = new FBXImporter.Texture[] { new FBXImporter.Texture(Mat.ParentScene, MatOverride.TextureDiffuse, MatOverride.TextureDiffuse, MatOverride.TextureDiffuse) }; } } if (MatOverride.TextureNormal != null) { FBXImporter.ObjectProperty TextureProperty = Mat.FindProperty("NormalMap"); if (TextureProperty != null) { TextureProperty.Textures = new FBXImporter.Texture[] { new FBXImporter.Texture(Mat.ParentScene, MatOverride.TextureNormal, MatOverride.TextureNormal, MatOverride.TextureNormal) }; } } if (MatOverride.TextureSpecular != null) { FBXImporter.ObjectProperty TextureProperty = Mat.FindProperty("SpecularColor"); if (TextureProperty != null) { TextureProperty.Textures = new FBXImporter.Texture[] { new FBXImporter.Texture(Mat.ParentScene, MatOverride.TextureSpecular, MatOverride.TextureSpecular, MatOverride.TextureSpecular) }; } } } } } // Specialize the material if (Mat is FBXImporter.MaterialHardwareShader) { FBXImporter.MaterialHardwareShader HardwareMaterial = Mat as FBXImporter.MaterialHardwareShader; MatParams = m_Scene.CreateMaterialParameters(Mat.Name, HardwareMaterial.RelativeURL); foreach (FBXImporter.MaterialHardwareShader.TableEntry Entry in HardwareMaterial.ShaderEntries) { switch (Entry.TypeName) { case "Boolean": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL).AsBool.Value = (bool)Entry.Value; break; case "Integer": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.INT).AsInt.Value = (int)Entry.Value; break; case "Float": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = (float)Entry.Value; break; case "Float2": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT2).AsFloat2.Value = Entry.Value as Vector2D; break; case "Float3": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = Entry.Value as Vector; break; case "Float4": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT4).AsFloat4.Value = Entry.Value as Vector4D; break; case "Matrix": MatParams.CreateParameter(Entry.Name, Scene.Materials.MaterialParameters.PARAMETER_TYPE.MATRIX4).AsMatrix4.Value = Entry.Value as Matrix4x4; break; case "Texture": CreateTextureParameter(Mat, Entry.Name, MatParams, Entry.Name); break; } } m_Material2Parameters[Mat] = MatParams; continue; } FBXImporter.Material SpecificMaterial = null; if (Mat is FBXImporter.MaterialPhong) { SpecificMaterial = Mat as FBXImporter.MaterialPhong; MatParams = m_Scene.CreateMaterialParameters(Mat.Name, "Phong"); } else if (Mat is FBXImporter.MaterialLambert) { SpecificMaterial = Mat as FBXImporter.MaterialLambert; MatParams = m_Scene.CreateMaterialParameters(Mat.Name, "Lambert"); } else { continue; // Unrecognized hence unsupported material type... } // // Lambert parameters // MatParams.CreateParameter( "AmbientColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3 ).AsFloat3.Value = SpecificMaterial.AmbientColor; // CreateTextureParameter( Mat, "AmbientColor", MatParams, "AmbientTexture" ); // MatParams.CreateParameter( "AmbientFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT ).AsFloat.Value = SpecificMaterial.AmbientFactor; // // MatParams.CreateParameter( "DiffuseColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3 ).AsFloat3.Value = SpecificMaterial.DiffuseColor; // MatParams.CreateParameter( "DiffuseFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT ).AsFloat.Value = SpecificMaterial.DiffuseFactor; // bool bHasDiffuseTexture = CreateTextureParameter( Mat, "DiffuseColor", MatParams, "DiffuseTexture", "TransparentColor" ); // MatParams.CreateParameter( "HasDiffuseTexture", Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL ).AsBool.Value = bHasDiffuseTexture; // // MatParams.CreateParameter( "EmissiveColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3 ).AsFloat3.Value = SpecificMaterial.EmissiveColor; // MatParams.CreateParameter( "EmissiveFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT ).AsFloat.Value = SpecificMaterial.EmissiveFactor; // CreateTextureParameter( Mat, "EmissiveColor", MatParams, "EmissiveTexture" ); // // FBXImporter.ObjectProperty OpacityProp = SpecificMaterial.FindProperty( "Opacity" ); // float fOpacity = OpacityProp != null ? (float) OpacityProp.Value : 1.0f; // MatParams.CreateParameter( "Opacity", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT ).AsFloat.Value = fOpacity; // // MatParams.IsOpaque = fOpacity >= 1.0f; // // bool bHasNormalTexture = CreateTextureParameter( Mat, "Bump", MatParams, "NormalTexture" ); // MatParams.CreateParameter( "HasNormalTexture", Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL ).AsBool.Value = bHasNormalTexture; // Lambert parameters MatParams.CreateParameter("AmbientColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = SpecificMaterial.FindProperty("AmbientColor").AsVector3; CreateTextureParameter(Mat, "AmbientColor", MatParams, "AmbientTexture"); MatParams.CreateParameter("AmbientFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("AmbientFactor").AsFloat; MatParams.CreateParameter("DiffuseColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = SpecificMaterial.FindProperty("DiffuseColor").AsVector3; MatParams.CreateParameter("DiffuseFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("DiffuseFactor").AsFloat; bool bHasDiffuseTexture = CreateTextureParameter(Mat, "DiffuseColor", MatParams, "DiffuseTexture", "TransparentColor"); MatParams.CreateParameter("HasDiffuseTexture", Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL).AsBool.Value = bHasDiffuseTexture; MatParams.CreateParameter("EmissiveColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = SpecificMaterial.FindProperty("EmissiveColor").AsVector3; MatParams.CreateParameter("EmissiveFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("EmissiveFactor").AsFloat; bool bHasEmissiveTexture = CreateTextureParameter(Mat, "EmissiveColor", MatParams, "EmissiveTexture"); float fOpacity = SpecificMaterial.FindProperty("Opacity").AsFloat; MatParams.CreateParameter("Opacity", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = fOpacity; // MatParams.IsOpaque = fOpacity >= 1.0f; bool bHasNormalTexture = false; if (Mat.FindProperty("Bump").Textures.Length > 0) { bHasNormalTexture = CreateTextureParameter(Mat, "Bump", MatParams, "NormalTexture"); } else if (Mat.FindProperty("NormalMap").Textures.Length > 0) { bHasNormalTexture = CreateTextureParameter(Mat, "NormalMap", MatParams, "NormalTexture"); } MatParams.CreateParameter("HasNormalTexture", Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL).AsBool.Value = bHasNormalTexture; // Phong parameters try { MatParams.CreateParameter("ReflectionColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = SpecificMaterial.FindProperty("ReflectionColor").AsVector3; CreateTextureParameter(Mat, "ReflectionColor", MatParams, "ReflectionTexture"); MatParams.CreateParameter("ReflectionFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("ReflectionFactor").AsFloat; MatParams.CreateParameter("Shininess", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("Shininess").AsFloat; MatParams.CreateParameter("SpecularColor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT3).AsFloat3.Value = SpecificMaterial.FindProperty("SpecularColor").AsVector3; MatParams.CreateParameter("SpecularFactor", Scene.Materials.MaterialParameters.PARAMETER_TYPE.FLOAT).AsFloat.Value = SpecificMaterial.FindProperty("SpecularFactor").AsFloat; bool bHasSpecularTexture = CreateTextureParameter(Mat, "SpecularColor", MatParams, "SpecularTexture"); MatParams.CreateParameter("HasSpecularTexture", Scene.Materials.MaterialParameters.PARAMETER_TYPE.BOOL).AsBool.Value = bHasSpecularTexture; } catch (Exception) { } // Register the material m_Material2Parameters[Mat] = MatParams; } }
/// <summary> /// Optimizes the existing meshes and build the primitives necessary for runtime display /// This will attempt to compact identical meshes and also consolidate mesh primitives /// </summary> protected void BuildConsolidatedMeshes() { // 1] Retrieve all existing meshes and compact identical instances List <LoaderTempMesh> CompactedMeshes = new List <LoaderTempMesh>(); foreach (LoaderTempMesh M in m_TempMesh2FinalMesh.Keys) { // Check the existing meshes to see if they might be a master to this mesh if (m_bCompactIdenticalMeshes) { foreach (LoaderTempMesh MasterMesh in CompactedMeshes) { if (M.MergeWithMasterMesh(MasterMesh)) { break; // We found this mesh's master! } } } CompactedMeshes.Add(M); } // 2] Consolidate master meshes // WMath.Global.PushEpsilon( 1e-3f ); // Use this new epsilon for float comparisons in the Math library... foreach (LoaderTempMesh M in CompactedMeshes) { M.PerformConsolidation(); } // WMath.Global.PopEpsilon(); // 3] Rebuild slave meshes from consolidated meshes foreach (LoaderTempMesh M in CompactedMeshes) { M.RebuildFromMasterMesh(); } // 4] Convert the mesh into a clean consolidated mesh PrimitiveBuilder Builder = new PrimitiveBuilder(); foreach (LoaderTempMesh M in CompactedMeshes) { Scene.Nodes.Mesh TargetMesh = m_TempMesh2FinalMesh[M]; // Setup basic mesh infos TargetMesh.BBox = M.BoundingBox; // I know it's a bit of a lousy approximation for the b-sphere but we can always refine it later... TargetMesh.BSphere = new BoundingSphere(M.BoundingBox.Center, 0.5f * M.BoundingBox.Dim.Magnitude()); // Build primitives int PrimitiveIndex = 0; foreach (LoaderTempMesh.Primitive P in M.ConsolidatedPrimitives) { if (P.Material == null) { throw new Exception("Primitive \"" + P.Name + "\" has no assigned material!"); } Scene.Materials.MaterialParameters MatParams = m_Material2Parameters[P.Material]; // if ( !m_Material2Technique.ContainsKey( P.Material ) ) // continue; // Un-supported... // Create the temporary builder that will handle the primitive conversion Builder.CreatePrimitive(P, TargetMesh, M.Name + "." + PrimitiveIndex++, MatParams); } } }
public Scene.Nodes.Mesh.Primitive CreatePrimitive(LoaderTempMesh.Primitive _SourcePrimitive, Scene.Nodes.Mesh _ParentMesh, string _Name, Scene.Materials.MaterialParameters _MatParams) { m_SourcePrimitive = _SourcePrimitive; Scene.Nodes.Mesh.Primitive Target = _ParentMesh.AddPrimitive(_Name, _MatParams, _SourcePrimitive.VerticesCount, _SourcePrimitive.FacesCount); // Build the primitive's triangles for (int FaceIndex = 0; FaceIndex < _SourcePrimitive.FacesCount; FaceIndex++) { Target.Faces[FaceIndex].V0 = _SourcePrimitive.Faces[FaceIndex].V0.m_Index; Target.Faces[FaceIndex].V1 = _SourcePrimitive.Faces[FaceIndex].V1.m_Index; Target.Faces[FaceIndex].V2 = _SourcePrimitive.Faces[FaceIndex].V2.m_Index; } // Build the primitive's vertex streams int[] StreamIndices = new int[8]; foreach (LoaderTempMesh.Primitive.VertexStream Stream in m_SourcePrimitive.VertexStreams) { Scene.Nodes.Mesh.Primitive.VertexStream.USAGE Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.UNKNOWN; Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.UNKNOWN; object Content = null; switch (Stream.StreamType) { case LoaderTempMesh.VERTEX_INFO_TYPE.POSITION: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.POSITION; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = (Vector)(Stream.Stream[i] as WMath.Point); } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.NORMAL: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.NORMAL; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TANGENT: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TANGENT; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.BINORMAL: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.BITANGENT; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD1D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT; float[] T = new float[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = (float)Stream.Stream[i]; } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD2D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT2; Vector2D[] T = new Vector2D[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector2D; T[i].Y = 1.0f - T[i].Y; // Here we must complement the V coordinate as MAX has the bad habit of inverting the Y axis of images! } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.TEXCOORD3D: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.TEXCOORDS; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT3; Vector[] T = new Vector[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector; T[i].Y = 1.0f - T[i].Y; // Here we must complement the V coordinate as MAX has the bad habit of inverting the Y axis of images! } } break; case LoaderTempMesh.VERTEX_INFO_TYPE.COLOR_HDR: { Usage = Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.COLOR_HDR; FieldType = Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.FLOAT4; Vector4D[] T = new Vector4D[_SourcePrimitive.VerticesCount]; Content = T; for (int i = 0; i < _SourcePrimitive.VerticesCount; i++) { T[i] = Stream.Stream[i] as WMath.Vector4D; } } break; } if (Usage == Scene.Nodes.Mesh.Primitive.VertexStream.USAGE.UNKNOWN || FieldType == Scene.Nodes.Mesh.Primitive.VertexStream.FIELD_TYPE.UNKNOWN) { continue; // Unsupported... Should we throw? } if (Content == null) { throw new Exception("Invalid content!"); } int StreamIndexIndex = (int)Usage - 1; // Skip UNKNOWN usage and use the value as "stream type" int StreamIndex = StreamIndices[StreamIndexIndex]; StreamIndices[StreamIndexIndex]++; // Increase stream index Target.AddVertexStream(Usage, FieldType, StreamIndex, Content); StreamIndex++; } return(Target); }