/// <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); }