diff --git a/Importer.cs b/Importer.cs index 883b143..0a36596 100644 --- a/Importer.cs +++ b/Importer.cs @@ -7,9 +7,306 @@ namespace Smuggler { public static class Importer { - public static Model ImportGLTF(GraphicsDevice graphicsDevice, Stream stream) + private static System.Type InferVertexType(SharpGLTF.Schema2.ModelRoot model) + { + bool hasColor = false; + bool hasNormal = false; + bool hasTexture = false; + + if (model.LogicalMeshes.Count == 0) { return null; } + if (model.LogicalMeshes[0].Primitives.Count == 0) { return null; } + + var samplePrimitive = model.LogicalMeshes[0].Primitives[0]; + + if (samplePrimitive.GetVertexAccessor("POSITION") == null) + { + System.Console.WriteLine("There is no Position attribute on this model's vertices. That seems weird!"); + return null; + } + + if (samplePrimitive.GetVertexAccessor("COLOR") != null) + { + hasColor = true; + } + + if (samplePrimitive.GetVertexAccessor("NORMAL") != null) + { + hasNormal = true; + } + + if (samplePrimitive.GetVertexAccessor("TEXCOORD_0") != null) + { + hasTexture = true; + } + + if (hasColor && hasNormal && hasTexture) + { + // FIXME: Implement VertexPositionColorNormalTexture + return null; + } + + if (hasColor && hasTexture) + { + return typeof(VertexPositionColorTexture); + } + + if (hasNormal && hasTexture) + { + return typeof(VertexPositionNormalTexture); + } + + if (hasColor) + { + return typeof(VertexPositionColor); + } + + if (hasTexture) + { + return typeof(VertexPositionTexture); + } + + System.Console.WriteLine("Could not infer vertex type"); + + return null; + } + + private static Vector3[] Positions(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var positionAccessor = primitive.GetVertexAccessor("POSITION").AsVector3Array(); + var positions = new Vector3[positionAccessor.Count]; + + for (int i = 0; i < positions.Length; i++) + { + var position = positionAccessor[i]; + positions[i] = new Vector3(-position.X, -position.Z, position.Y); + } + + return positions; + } + + private static Color[] Colors(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var colorAccessor = primitive.GetVertexAccessor("COLOR").AsColorArray(); + var colors = new Color[colorAccessor.Count]; + + for (int i = 0; i < colors.Length; i++) + { + var color = colorAccessor[i]; + colors[i] = new Color(color.X, color.Y, color.Z, color.W); + } + + return colors; + } + + private static Vector3[] Normals(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var normalAccessor = primitive.GetVertexAccessor("NORMAL").AsVector3Array(); + var normals = new Vector3[normalAccessor.Count]; + + for (int i = 0; i < normals.Length; i++) + { + var normal = normalAccessor[i]; + normals[i] = -new Vector3(normal.X, normal.Z, normal.Y); + } + + return normals; + } + + private static Vector2[] TexCoords(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var texcoordAccessor = primitive.GetVertexAccessor("TEXCOORD_0").AsVector2Array(); + var texcoords = new Vector2[texcoordAccessor.Count]; + + for (int i = 0; i < texcoords.Length; i++) + { + var texcoord = texcoordAccessor[i]; + texcoords[i] = new Vector2(texcoord.X, texcoord.Y); + } + + return texcoords; + } + + private static Triangle[] Triangles(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var triangles = new List(); + + foreach (var (a, b, c) in primitive.GetTriangleIndices()) + { + triangles.Add(new Triangle(a, b, c)); + } + + return triangles.ToArray(); + } + + private static uint[] Indices(SharpGLTF.Schema2.MeshPrimitive primitive) + { + var indexAccessor = primitive.GetIndexAccessor().AsIndicesArray(); + var indices = new uint[indexAccessor.Count]; + + for (int i = 0; i < indices.Length; i++) + { + indices[i] = indexAccessor[i]; + } + + return indices; + } + + private static void ImportVertexPositionColor( + SharpGLTF.Schema2.MeshPrimitive primitive, + VertexBuffer vertexBuffer, + uint[] indices, + Vector3[] positions + ) { + var colors = Colors(primitive); + + var vertices = new VertexPositionColor[positions.Length]; + + foreach (var index in indices) + { + var position = positions[index]; + var color = colors[index]; + + vertices[index] = new VertexPositionColor( + position, + color + ); + } + + vertexBuffer.SetData(vertices); + } + + private static void ImportVertexPositionColorTexture( + SharpGLTF.Schema2.MeshPrimitive primitive, + VertexBuffer vertexBuffer, + uint[] indices, + Vector3[] positions + ) { + var colors = Colors(primitive); + var texcoords = TexCoords(primitive); + + var vertices = new VertexPositionColorTexture[positions.Length]; + + foreach (var index in indices) + { + var position = positions[index]; + var color = colors[index]; + var texcoord = texcoords[index]; + + vertices[index] = new VertexPositionColorTexture( + position, + color, + texcoord + ); + } + + vertexBuffer.SetData(vertices); + } + + private static void ImportVertexPositionNormalTexture( + SharpGLTF.Schema2.MeshPrimitive primitive, + VertexBuffer vertexBuffer, + uint[] indices, + Vector3[] positions + ) { + var normals = Normals(primitive); + var texcoords = TexCoords(primitive); + + var vertices = new VertexPositionNormalTexture[positions.Length]; + + foreach (var index in indices) + { + var position = positions[index]; + var normal = normals[index]; + var texcoord = texcoords[index]; + + vertices[index] = new VertexPositionNormalTexture( + position, + normal, + texcoord + ); + } + + vertexBuffer.SetData(vertices); + } + + private static void ImportVertexPositionTexture( + SharpGLTF.Schema2.MeshPrimitive primitive, + VertexBuffer vertexBuffer, + uint[] indices, + Vector3[] positions + ) { + var texcoords = TexCoords(primitive); + + var vertices = new VertexPositionTexture[positions.Length]; + + foreach (var index in indices) + { + var position = positions[index]; + var texcoord = texcoords[index]; + + vertices[index] = new VertexPositionTexture( + position, + texcoord + ); + } + + vertexBuffer.SetData(vertices); + } + + private static MeshPart ImportMeshPart(GraphicsDevice graphicsDevice, System.Type vertexType, SharpGLTF.Schema2.MeshPrimitive primitive) + { + var indices = Indices(primitive); + var positions = Positions(primitive); + var triangles = Triangles(primitive); + + var vertexBuffer = new VertexBuffer( + graphicsDevice, + vertexType, + positions.Length, + BufferUsage.None + ); + + var indexBuffer = new IndexBuffer( + graphicsDevice, + IndexElementSize.ThirtyTwoBits, + indices.Length, + BufferUsage.None + ); + + indexBuffer.SetData(indices); + + if (vertexType == typeof(VertexPositionColor)) + { + ImportVertexPositionColor(primitive, vertexBuffer, indices, positions); + } + else if (vertexType == typeof(VertexPositionColorTexture)) + { + ImportVertexPositionColorTexture(primitive, vertexBuffer, indices, positions); + } + else if (vertexType == typeof(VertexPositionNormalTexture)) + { + ImportVertexPositionNormalTexture(primitive, vertexBuffer, indices, positions); + } + else if (vertexType == typeof(VertexPositionTexture)) + { + ImportVertexPositionTexture(primitive, vertexBuffer, indices, positions); + } + + return new MeshPart( + vertexBuffer, + indexBuffer, + positions, + triangles, + new BasicEffect(graphicsDevice) + ); + } + + public static Model ImportGLB(GraphicsDevice graphicsDevice, Stream stream) { var sharpModel = SharpGLTF.Schema2.ModelRoot.ReadGLB(stream); + var vertexType = InferVertexType(sharpModel); + + if (vertexType == null) { return null; } var meshes = new List(); @@ -19,84 +316,8 @@ namespace Smuggler foreach (var primitive in mesh.Primitives) { - var positionAccessor = primitive.GetVertexAccessor("POSITION").AsVector3Array(); - var normalAccessor = primitive.GetVertexAccessor("NORMAL").AsVector3Array(); - var texcoordAccessor = primitive.GetVertexAccessor("TEXCOORD_0").AsVector2Array(); - var indexAccessor = primitive.GetIndexAccessor().AsIndicesArray(); - - var positions = new Vector3[positionAccessor.Count]; - var normals = new Vector3[normalAccessor.Count]; - var texcoords = new Vector2[texcoordAccessor.Count]; - var triangles = new List(); - - for (int i = 0; i < positions.Length; i++) - { - var position = positionAccessor[i]; - positions[i] = new Vector3(-position.X, -position.Z, position.Y); - } - - for (int i = 0; i < normals.Length; i++) - { - var normal = normalAccessor[i]; - normals[i] = -new Vector3(normal.X, normal.Z, normal.Y); - } - - for (int i = 0; i < texcoords.Length; i++) - { - var texcoord = texcoordAccessor[i]; - texcoords[i] = new Vector2(texcoord.X, texcoord.Y); - } - - foreach (var (a, b, c) in primitive.GetTriangleIndices()) - { - triangles.Add(new Triangle(a, b, c)); - } - - var vertexBuffer = new VertexBuffer( - graphicsDevice, - typeof(VertexPositionNormalTexture), - positions.Length, - BufferUsage.WriteOnly - ); - - var indexBuffer = new IndexBuffer( - graphicsDevice, - IndexElementSize.ThirtyTwoBits, - indexAccessor.Count, - BufferUsage.WriteOnly - ); - - var vertices = new VertexPositionNormalTexture[positions.Length]; - var indices = new uint[primitive.IndexAccessor.Count]; - var indexCounter = 0; - - foreach (var index in primitive.GetIndices()) - { - var position = positions[index]; - var normal = normals[index]; - var texcoord = texcoords[index]; - - indices[indexCounter] = index; - vertices[index] = new VertexPositionNormalTexture( - new Vector3(position.X, position.Y, position.Z), - new Vector3(normal.X, normal.Y, normal.Z), - new Vector2(texcoord.X, texcoord.Y) - ); - - indexCounter++; - } - - indexBuffer.SetData(indices); - vertexBuffer.SetData(vertices); - meshParts.Add( - new MeshPart( - vertexBuffer, - indexBuffer, - vertices, - triangles.ToArray(), - new BasicEffect(graphicsDevice) - ) + ImportMeshPart(graphicsDevice, vertexType, primitive) ); } diff --git a/MeshPart.cs b/MeshPart.cs index ba3e1cc..b68bfab 100644 --- a/MeshPart.cs +++ b/MeshPart.cs @@ -7,15 +7,15 @@ namespace Smuggler { public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } - public VertexPositionNormalTexture[] Vertices { get; } /* should we parameterize this by vertex type? */ public Triangle[] Triangles { get; } public BasicEffect Effect { get; } + public Vector3[] Positions { get; } - public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, VertexPositionNormalTexture[] vertices, Triangle[] triangles, BasicEffect effect) + public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, BasicEffect effect) { VertexBuffer = vertexBuffer; IndexBuffer = indexBuffer; - Vertices = vertices; + Positions = positions; Triangles = triangles; Effect = effect; }