private void ConvertMeshes(List <Mesh> meshes, VertexPositionBuffer positionBuffer, VertexNormalBuffer normalBuffer, VertexColorBuffer colorBuffer, VertexUVBuffer uvBuffer) { var state = new MeshRenderState(); for (var i = 0; i < meshes.Count; i++) { var mesh = meshes[i]; if (mesh.Parameters != null && mesh.Parameters.Count > 0) { ProcessMeshParameters(mesh.Parameters, ref state); } var stateCopy = state; stateCopy.TextureId = 0; stateCopy.TileMode = 0; //stateCopy.IndexFlags = 0; stateCopy.AmbientColor = new Color(); sUniqueStates.Add(stateCopy); var aiMesh = new Assimp.Mesh(); var vertexCache = new List <Vertex>(); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition) ? positionBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal) ? normalBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor) ? colorBuffer != null : true); Debug.Assert(state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV) ? uvBuffer != null : true); // Extract all vertices used by the triangles, and build a new vertex list // with each vertex attribute clumped together var aiFace = new Assimp.Face(); foreach (var index in mesh.DisplayLists.SelectMany(x => x.ToTriangles())) { var vertex = new Vertex(); if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasPosition)) { vertex.Position = positionBuffer.Elements[index.PositionIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal)) { vertex.Normal = normalBuffer.Elements[index.NormalIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor)) { vertex.Color = colorBuffer.Elements[index.ColorIndex]; } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV)) { vertex.UV = uvBuffer.Elements[index.UVIndex]; } // Find index of this vertex in the list in case it already exists var vertexIndex = vertexCache.IndexOf(vertex); if (vertexIndex == -1) { vertexIndex = vertexCache.Count; vertexCache.Add(vertex); } aiFace.Indices.Add(vertexIndex); if (aiFace.IndexCount == 3) { // Done with this face, move on to the next one aiMesh.Faces.Add(aiFace); aiFace = new Assimp.Face(); } } // Convert vertices aiMesh.Vertices.AddRange(vertexCache.Select(x => ToAssimp(x.Position))); if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasNormal)) { aiMesh.Normals.AddRange(vertexCache.Select(x => ToAssimp(x.Normal))); } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasUV)) { aiMesh.TextureCoordinateChannels[0].AddRange(vertexCache.Select(x => ToAssimp(UVCodec.Decode1023(x.UV)))); } if (state.IndexFlags.HasFlag(IndexAttributeFlags.HasColor)) { aiMesh.VertexColorChannels[0].AddRange(vertexCache.Select(x => ToAssimp(x.Color))); } // Convert material if (!mConvertedMaterialCache.TryGetValue(state, out var aiMaterialIndex)) { // Not in cache, so create a new one and add it aiMaterialIndex = Scene.MaterialCount; Scene.Materials.Add(CreateMaterial(Color.Gray, Color.Gray, Color.Gray, FormatTextureName(state.TextureId), false, false, state.TileMode.HasFlag(TileMode.MirrorU), state.TileMode.HasFlag(TileMode.MirrorV), state.BlendAlphaFlags.HasFlag(BlendAlphaFlags.UseAlpha))); mConvertedMaterialCache[state] = aiMaterialIndex; } aiMesh.MaterialIndex = aiMaterialIndex; // Add mesh to scene. Scene.Meshes.Add(aiMesh); } }
private void ReadVertexAttributes(EndianBinaryReader reader) { VertexBuffers = new List <VertexAttributeBuffer>(); while (true) { var type = ( VertexAttributeType )reader.ReadByte(); if (type == VertexAttributeType.End) { break; } var elementSize = reader.ReadByte(); var elementCount = reader.ReadUInt16(); var field04 = reader.ReadInt32(); var dataOffset = reader.ReadUInt32(); var dataSize = reader.ReadUInt32(); VertexAttributeBuffer buffer; switch (type) { case VertexAttributeType.Position: case VertexAttributeType.Normal: { Vector3[] elements = null; reader.ReadAtOffset(dataOffset, () => elements = reader.ReadVector3s(elementCount)); if (type == VertexAttributeType.Position) { buffer = new VertexPositionBuffer(elements); } else { buffer = new VertexNormalBuffer(elements); } } break; case VertexAttributeType.Color: { Color[] elements = null; reader.ReadAtOffset(dataOffset, () => { var endianness = reader.Endianness; reader.Endianness = Endianness.Big; elements = reader.ReadColors(elementCount); reader.Endianness = endianness; }); buffer = new VertexColorBuffer(elements); } break; case VertexAttributeType.UV: { Vector2 <short>[] elements = null; reader.ReadAtOffset(dataOffset, () => elements = reader.ReadVector2Int16s(elementCount)); buffer = new VertexUVBuffer(elements); } break; default: throw new InvalidGeometryDataException($"Attempted to read invalid/unknown vertex attribute: {type}"); } Debug.Assert(elementSize == buffer.ElementSize); Debug.Assert(elementCount == buffer.ElementCount); Debug.Assert(field04 == buffer.Field04); Debug.Assert(dataSize == buffer.DataSize); VertexBuffers.Add(buffer); } }