/// <summary> /// Reads the index buffer data and converts it into a triangle list if necessary. /// </summary> /// <param name="reader">The mesh reader to use.</param> /// <param name="part">The mesh part to read.</param> /// <param name="resourceStream">A stream open on the resource data.</param> /// <returns>The index buffer converted into a triangle list.</returns> private static ushort[] ReadIndices(MeshReader reader, Mesh.Part part, Stream resourceStream) { // Use index buffer 0 var indexBuffer = reader.IndexBuffers[0]; if (indexBuffer == null) { throw new InvalidOperationException("Index buffer 0 is null"); } // Read the indices var indexStream = reader.OpenIndexBufferStream(indexBuffer, resourceStream); indexStream.Position = part.FirstIndexOld; switch (indexBuffer.Format) { case IndexBufferFormat.TriangleList: return(indexStream.ReadIndices(part.IndexCountOld)); case IndexBufferFormat.TriangleStrip: return(indexStream.ReadTriangleStrip(part.IndexCountOld)); default: throw new InvalidOperationException("Unsupported index buffer type: " + indexBuffer.Format); } }
private static List <GenericVertex> ReadVertices(MeshReader reader, Stream resourceStream) { // Open a vertex reader on stream 0 (main vertex data) var mainBuffer = reader.VertexStreams[0]; if (mainBuffer == null) { return(new List <GenericVertex>()); } var vertexReader = reader.OpenVertexStream(mainBuffer, resourceStream); switch (reader.Mesh.Type) { case VertexType.Rigid: return(ReadRigidVertices(vertexReader, mainBuffer.Count)); case VertexType.Skinned: return(ReadSkinnedVertices(vertexReader, mainBuffer.Count)); case VertexType.DualQuat: return(ReadDualQuatVertices(vertexReader, mainBuffer.Count)); case VertexType.World: return(ReadWorldVertices(vertexReader, mainBuffer.Count)); default: throw new InvalidOperationException("Only Rigid, Skinned, DualQuat and World meshes are supported"); } }
/// <summary> /// Writes mesh data to the .obj. /// </summary> /// <param name="reader">The mesh reader to use.</param> /// <param name="compressor">The vertex compressor to use.</param> /// <param name="resourceStream">A stream open on the resource data.</param> public void ExtractMesh(MeshReader reader, VertexCompressor compressor, Stream resourceStream) { // Read the vertex buffer and decompress each vertex var vertices = ReadVertices(reader, resourceStream); DecompressVertices(vertices, compressor); // Write out the vertices WriteVertices(vertices); // Read and write out the triangles for each part foreach (var part in reader.Mesh.Parts) { var indexes = ReadIndexes(reader, part, resourceStream); WriteTriangles(indexes); } _baseIndex += (uint)vertices.Count; }
private Assimp.Mesh ExtractMeshPartGeometry(int meshIndex, int partIndex) { // create new assimp mesh Assimp.Mesh mesh = new Assimp.Mesh(); // Add support for multiple UV layers var textureCoordinateIndex = 0; mesh.UVComponentCount[textureCoordinateIndex] = 2; // prepare vertex extraction var meshReader = new MeshReader(CacheContext.Version, RenderModel.Geometry.Meshes[meshIndex], RenderModelResourceDefinition); var vertexCompressor = new VertexCompressor(RenderModel.Geometry.Compression[0]); var geometryMesh = RenderModel.Geometry.Meshes[meshIndex]; var geometryPart = geometryMesh.Parts[partIndex]; mesh.MaterialIndex = geometryPart.MaterialIndex; // optimize this part to not load and decompress all mesh vertices everytime var vertices = ReadVertices(meshReader, RenderModelResourceStream); DecompressVertices(vertices, vertexCompressor); // get offset in the list of all vertices for the mesh var vertexOffset = GetPartVertexOffset(meshIndex, partIndex); //vertices = vertices.GetRange(vertexOffset, geometryPart.VertexCount); var indices = ReadIndices(meshReader, geometryPart, RenderModelResourceStream); var int_indices = indices.Select(b => (int)b).ToArray(); var indexCount = indices.Length; if (indexCount == 0) { Console.WriteLine($"Failed to extract mesh, no indices."); return(null); } // set index list, maybe require adjustment for vertex buffer offset mesh.SetIndices(int_indices, 3); // build skeleton for each mesh (meh) // create a list of all the mesh bones available in the scene foreach (var node in RenderModel.Nodes) { Bone bone = new Bone(); bone.Name = CacheContext.GetString(node.Name); bone.OffsetMatrix = new Matrix4x4(); mesh.Bones.Add(bone); } for (int i = vertexOffset; i < vertexOffset + geometryPart.VertexCount; i++) { var vertex = vertices[i]; mesh.Vertices.Add(vertex.Position); if (vertex.Normal != null) { mesh.Normals.Add(vertex.Normal); } if (vertex.TexCoords != null) { mesh.TextureCoordinateChannels[textureCoordinateIndex].Add(vertex.TexCoords); } if (vertex.Tangents != null) { mesh.Tangents.Add(vertex.Tangents); } if (vertex.Binormals != null) { mesh.BiTangents.Add(vertex.Binormals); } if (vertex.Indices != null) { for (int j = 0; j < vertex.Indices.Length; j++) { var index = vertex.Indices[j]; var bone = mesh.Bones[index]; Matrix4x4 inverseTransform = new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); var currentNode = BoneNodes[index]; while (currentNode != null) { Matrix4x4 inverse = (currentNode.Transform.DeepClone()); inverse.Inverse(); inverseTransform = inverse * inverseTransform; currentNode = currentNode.Parent; } bone.OffsetMatrix = inverseTransform; bone.VertexWeights.Add(new VertexWeight(i - vertexOffset, vertex.Weights[j])); } } // Add skinned mesh support and more } // create faces mesh.Faces.Clear(); GenerateFaces(int_indices, vertexOffset, mesh.Faces); return(mesh); }
/// <summary> /// Writes mesh data to the .obj. /// </summary> /// <param name="reader">The mesh reader to use.</param> /// <param name="compressor">The vertex compressor to use.</param> /// <param name="resourceStream">A stream open on the resource data.</param> /// <param name="name">The name of the mesh.</param> public void ExtractMesh(MeshReader reader, VertexCompressor compressor, Stream resourceStream, string name = null) { var vertices = ReadVertices(reader, resourceStream); DecompressVertices(vertices, compressor); var indicesList = new List <ushort[]>(); var indexCount = 0; for (var i = 0; i < (reader?.Mesh?.Parts?.Count ?? -1); i++) { var part = reader.Mesh.Parts[i]; var indices = ReadIndices(reader, part, resourceStream); indicesList.Add(indices); if (part.IndexCountOld > 0) { indexCount += indices.Length; } } if (indexCount == 0) { return; } foreach (var vertex in vertices) { _writer.WriteLine("v {0} {1} {2}", vertex.Position.I, vertex.Position.J, vertex.Position.K); } foreach (var vertex in vertices) { _writer.WriteLine("vn {0} {1} {2}", vertex.Normal.I, vertex.Normal.J, vertex.Normal.K); } foreach (var vertex in vertices) { _writer.WriteLine("vt {0} {1}", vertex.TexCoords.I, 1 - vertex.TexCoords.J); } var partIndex = 0; foreach (var indices in indicesList) { var triangles = GenerateTriangles(indices); if (triangles.Count() != 0) { _writer.WriteLine($"g {name}_part_{partIndex++}"); } foreach (var triangle in triangles) { _writer.WriteLine(triangle); } } _baseIndex += (uint)vertices.Count; }