Example #1
0
        private void AddComponentsToMesh(gltf.Mesh targetMesh, ShapeComponentIds osgGeom, int materialIndex)
        {
            gltf.MeshPrimitive       thisPrimitive = new gltf.MeshPrimitive();
            Dictionary <string, int> att           = new Dictionary <string, int>();

            att.Add("NORMAL", osgGeom.NormalsAccessorId);
            att.Add("POSITION", osgGeom.VerticesAccessorId);
            thisPrimitive.Attributes = att;
            thisPrimitive.Indices    = osgGeom.IndicesAccessorId;
            thisPrimitive.Material   = materialIndex;
            thisPrimitive.Mode       = gltf.MeshPrimitive.ModeEnum.TRIANGLES;


            int initSize = targetMesh.Primitives != null
                ? targetMesh.Primitives.Length
                : 0;

            if (initSize == 0)
            {
                targetMesh.Primitives = new gltf.MeshPrimitive[] { thisPrimitive };
            }
            else
            {
                var concat = targetMesh.Primitives.ToList();
                concat.Add(thisPrimitive);
                targetMesh.Primitives = concat.ToArray();
            }
        }
    private void LoadMesh(glTFLoader.Schema.Mesh mesh, Matrix4x4 matrix)
    {
        string name = mesh.Name;

        foreach (Primitive primitive in mesh.Primitives)
        {
            LoadPrimitive(primitive, name, matrix);
        }
    }
Example #3
0
        private static Gltf.Accessor getAccessor(Gltf.Gltf gltfModel, Gltf.Mesh gltfMesh, string key)
        {
            if (gltfMesh.Primitives[0].Attributes.TryGetValue(key, out var index))
            {
                return(gltfModel.Accessors[index]);
            }

            return(null);
        }
Example #4
0
        public static ushort[] readIndices(string rootPath, Gltf.Gltf model, Gltf.Mesh mesh)
        {
            var accessor = model.Accessors[(int)mesh.Primitives[0].Indices];
            var buffer   = readBuffer(rootPath, model, accessor);

            var indexArray = new ushort[accessor.Count];

            System.Buffer.BlockCopy(buffer, 0, indexArray, 0, buffer.Length);

            return(indexArray);
        }
Example #5
0
        public Mesh(string rootPath, Gltf.Gltf model, Gltf.Mesh mesh)
        {
            var vertices  = BufferReader.readVec3(rootPath, model, mesh, "POSITION");
            var normals   = BufferReader.readVec3(rootPath, model, mesh, "NORMAL");
            var tangents  = BufferReader.readVec4(rootPath, model, mesh, "TANGENT");
            var texCoords = BufferReader.readVec2(rootPath, model, mesh, "TEXCOORD_0");
            var indices   = BufferReader.readIndices(rootPath, model, mesh);

            IndexCount = indices.Length;
            Material   = new Material(rootPath, model, mesh);

            VaoId = GL.GenVertexArray();

            GL.BindVertexArray(VaoId);

            VertexBuffer = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ArrayBuffer, VertexBuffer);
            GL.BufferData <Vector3>(BufferTarget.ArrayBuffer, vertices.Length * Vector3.SizeInBytes, vertices, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);

            TexCoordBuffer = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ArrayBuffer, TexCoordBuffer);
            GL.BufferData <Vector2>(BufferTarget.ArrayBuffer, texCoords.Length * Vector2.SizeInBytes, texCoords, BufferUsageHint.StaticDraw);
            GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, Vector2.SizeInBytes, 0);

            if (normals.Length > 0)
            {
                NormalBuffer = GL.GenBuffer();
                GL.BindBuffer(BufferTarget.ArrayBuffer, NormalBuffer);
                GL.BufferData <Vector3>(BufferTarget.ArrayBuffer, normals.Length * Vector3.SizeInBytes, normals, BufferUsageHint.StaticDraw);
                GL.VertexAttribPointer(2, 3, VertexAttribPointerType.Float, false, Vector3.SizeInBytes, 0);
            }

            if (tangents.Length > 0)
            {
                TangentBuffer = GL.GenBuffer();
                GL.BindBuffer(BufferTarget.ArrayBuffer, TangentBuffer);
                GL.BufferData <Vector4>(BufferTarget.ArrayBuffer, tangents.Length * Vector4.SizeInBytes, tangents, BufferUsageHint.StaticDraw);
                GL.VertexAttribPointer(3, 4, VertexAttribPointerType.Float, false, Vector4.SizeInBytes, 0);
            }

            IndexBuffer = GL.GenBuffer();
            GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexBuffer);
            GL.BufferData <ushort>(BufferTarget.ElementArrayBuffer, IndexCount * sizeof(ushort), indices, BufferUsageHint.StaticDraw);
            GL.BindVertexArray(0);
        }
Example #6
0
        public static Vector2[] readVec2(string rootPath, Gltf.Gltf model, Gltf.Mesh mesh, string key)
        {
            var result   = new List <Vector2>();
            var accessor = getAccessor(model, mesh, key);

            if (accessor == null)
            {
                return new Vector2[] { }
            }
            ;

            var buffer     = readBuffer(rootPath, model, accessor);
            var floatArray = new float[accessor.Count * 2];

            System.Buffer.BlockCopy(buffer, 0, floatArray, 0, buffer.Length);

            for (var i = 0; i < accessor.Count * 2; i += 2)
            {
                result.Add(new Vector2(floatArray[i], floatArray[i + 1]));
            }

            return(result.ToArray());
        }
Example #7
0
        public Material(string rootPath, Gltf.Gltf model, Gltf.Mesh mesh)
        {
            var materialId = mesh.Primitives[0].Material;

            if (materialId == null)
            {
                throw new Exception("Mesh does not have a material!");
            }

            var material = model.Materials[(int)materialId];


            var baseColorTextureIndex = material.PbrMetallicRoughness.BaseColorTexture.Index;
            var baseColorTextureName  = model.Images[(int)model.Textures[baseColorTextureIndex].Source].Uri;

            BaseColorTexture = new Texture();
            BaseColorTexture.LoadTexture(Path.Combine(rootPath, baseColorTextureName), true);

            if (material.NormalTexture != null)
            {
                var normalTextureIndex = material.NormalTexture.Index;
                var normalTextureName  = model.Images[(int)model.Textures[normalTextureIndex].Source].Uri;
                NormalTexture = new Texture();
                NormalTexture.LoadTexture(Path.Combine(rootPath, normalTextureName), true);
            }

            if (material.PbrMetallicRoughness.MetallicRoughnessTexture != null)
            {
                var roughnessTextureIndex = material.NormalTexture.Index;
                var roughnessTextureName  = model.Images[(int)model.Textures[roughnessTextureIndex].Source].Uri;
                RoughnessTexture = new Texture();
                RoughnessTexture.LoadTexture(Path.Combine(rootPath, roughnessTextureName), true);
            }

            DoubleSided = material.DoubleSided;
            Roughness   = material.PbrMetallicRoughness.RoughnessFactor;
        }
Example #8
0
        internal static int AddLineLoop(this Gltf gltf, string name, List <byte> buffer, double[] vertices, ushort[] indices, double[] vMin, double[] vMax, ushort iMin, ushort iMax, int materialId, MeshPrimitive.ModeEnum mode, Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;
            var vBuff = gltf.AddBufferView(0, buffer.Count, vertices.Length * sizeof(float), null, null);
            var iBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float), indices.Length * sizeof(ushort), null, null);

            foreach (var v in vertices)
            {
                buffer.AddRange(BitConverter.GetBytes((float)v));
            }
            foreach (var i in indices)
            {
                buffer.AddRange(BitConverter.GetBytes(i));
            }

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = gltf.AddAccessor(vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = gltf.AddAccessor(iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length, new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = mode;
            prim.Attributes = new Dictionary <string, int> {
                { "POSITION", vAccess }
            };

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            if (gltf.Meshes != null)
            {
                // TODO: Get rid of this resizing.
                var meshes = gltf.Meshes.ToList();
                meshes.Add(m);
                gltf.Meshes = meshes.ToArray();
            }
            else
            {
                gltf.Meshes = new[] { m };
            }

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(transNode, 0);
            }

            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = gltf.Meshes.Length - 1;
            gltf.AddNode(node, parentId);

            return(gltf.Meshes.Length - 1);
        }
Example #9
0
        internal static int AddTriangleMesh(this Gltf gltf, string name, List <byte> buffer, double[] vertices, double[] normals, ushort[] indices, float[] colors,
                                            double[] vMin, double[] vMax, double[] nMin, double[] nMax, ushort iMin, ushort iMax, int materialId, float[] cMin, float[] cMax, int?parent_index, Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;

            var vBuff = gltf.AddBufferView(0, buffer.Count, vertices.Length * sizeof(float), null, null);
            var nBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float), normals.Length * sizeof(float), null, null);
            var iBuff = gltf.AddBufferView(0, buffer.Count + vertices.Length * sizeof(float) + normals.Length * sizeof(float), indices.Length * sizeof(ushort), null, null);

            foreach (var v in vertices)
            {
                buffer.AddRange(BitConverter.GetBytes((float)v));
            }
            foreach (var n in normals)
            {
                buffer.AddRange(BitConverter.GetBytes((float)n));
            }
            foreach (var i in indices)
            {
                buffer.AddRange(BitConverter.GetBytes(i));
            }

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = gltf.AddAccessor(vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var nAccess = gltf.AddAccessor(nBuff, 0, Accessor.ComponentTypeEnum.FLOAT, normals.Length / 3, new[] { (float)nMin[0], (float)nMin[1], (float)nMin[2] }, new[] { (float)nMax[0], (float)nMax[1], (float)nMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = gltf.AddAccessor(iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length, new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = MeshPrimitive.ModeEnum.TRIANGLES;
            prim.Attributes = new Dictionary <string, int> {
                { "NORMAL", nAccess },
                { "POSITION", vAccess }
            };

            // TODO: Add to the buffer above instead of inside this block.
            // There's a chance the padding operation will put padding before
            // the color information.
            if (colors.Length > 0)
            {
                var cBuff = gltf.AddBufferView(0, buffer.Count, colors.Length * sizeof(float), null, null);

                foreach (var c in colors)
                {
                    buffer.AddRange(BitConverter.GetBytes((float)c));
                }

                var cAccess = gltf.AddAccessor(cBuff, 0, Accessor.ComponentTypeEnum.FLOAT, colors.Length / 3, cMin, cMax, Accessor.TypeEnum.VEC3);
                prim.Attributes.Add("COLOR_0", cAccess);
            }

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            if (gltf.Meshes != null)
            {
                // TODO: Get rid of this resizing.
                var meshes = gltf.Meshes.ToList();
                meshes.Add(m);
                gltf.Meshes = meshes.ToArray();
            }
            else
            {
                gltf.Meshes = new[] { m };
            }

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(transNode, 0);
            }
            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = gltf.Meshes.Length - 1;
            gltf.AddNode(node, parentId);

            return(gltf.Meshes.Length - 1);
        }
Example #10
0
        internal static int AddLineLoop(this Gltf gltf,
                                        string name,
                                        List <byte> buffer,
                                        List <BufferView> bufferViews,
                                        List <Accessor> accessors,
                                        byte[] vertices,
                                        byte[] indices,
                                        double[] vMin,
                                        double[] vMax,
                                        ushort iMin,
                                        ushort iMax,
                                        int materialId,
                                        MeshPrimitive.ModeEnum mode,
                                        List <glTFLoader.Schema.Mesh> meshes,
                                        List <glTFLoader.Schema.Node> nodes,
                                        Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;
            var vBuff = AddBufferView(bufferViews, 0, buffer.Count, vertices.Length, null, null);
            var iBuff = AddBufferView(bufferViews, 0, buffer.Count + vertices.Length, indices.Length, null, null);

            buffer.AddRange(vertices);
            buffer.AddRange(indices);

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = AddAccessor(accessors, vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / sizeof(float) / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = AddAccessor(accessors, iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length / sizeof(ushort), new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = mode;
            prim.Attributes = new Dictionary <string, int> {
                { "POSITION", vAccess }
            };

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            meshes.Add(m);

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(nodes, transNode, 0);
            }

            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = meshes.Count - 1;
            gltf.AddNode(nodes, node, parentId);

            return(meshes.Count - 1);
        }
Example #11
0
        internal static int AddTriangleMesh(this Gltf gltf,
                                            string name,
                                            List <byte> buffer,
                                            List <BufferView> bufferViews,
                                            List <Accessor> accessors,
                                            byte[] vertices,
                                            byte[] normals,
                                            byte[] indices,
                                            byte[] colors,
                                            byte[] uvs,
                                            double[] vMin,
                                            double[] vMax,
                                            double[] nMin,
                                            double[] nMax,
                                            ushort iMin,
                                            ushort iMax,
                                            double[] uvMin,
                                            double[] uvMax,
                                            int materialId,
                                            float[] cMin,
                                            float[] cMax,
                                            int?parent_index,
                                            List <glTFLoader.Schema.Mesh> meshes)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;

            var vBuff = AddBufferView(bufferViews, 0, buffer.Count, vertices.Length, null, null);

            buffer.AddRange(vertices);

            var nBuff = AddBufferView(bufferViews, 0, buffer.Count, normals.Length, null, null);

            buffer.AddRange(normals);

            var iBuff = AddBufferView(bufferViews, 0, buffer.Count, indices.Length, null, null);

            buffer.AddRange(indices);

            while (buffer.Count % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = AddAccessor(accessors, vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / sizeof(float) / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var nAccess = AddAccessor(accessors, nBuff, 0, Accessor.ComponentTypeEnum.FLOAT, normals.Length / sizeof(float) / 3, new[] { (float)nMin[0], (float)nMin[1], (float)nMin[2] }, new[] { (float)nMax[0], (float)nMax[1], (float)nMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = AddAccessor(accessors, iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length / sizeof(ushort), new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = MeshPrimitive.ModeEnum.TRIANGLES;
            prim.Attributes = new Dictionary <string, int> {
                { "NORMAL", nAccess },
                { "POSITION", vAccess }
            };

            if (uvs.Length > 0)
            {
                var uvBuff = AddBufferView(bufferViews, 0, buffer.Count, uvs.Length, null, null);
                buffer.AddRange(uvs);
                var uvAccess = AddAccessor(accessors, uvBuff, 0, Accessor.ComponentTypeEnum.FLOAT, uvs.Length / sizeof(float) / 2, new[] { (float)uvMin[0], (float)uvMin[1] }, new[] { (float)uvMax[0], (float)uvMax[1] }, Accessor.TypeEnum.VEC2);
                prim.Attributes.Add("TEXCOORD_0", uvAccess);
            }

            // TODO: Add to the buffer above instead of inside this block.
            // There's a chance the padding operation will put padding before
            // the color information.
            if (colors.Length > 0)
            {
                var cBuff = AddBufferView(bufferViews, 0, buffer.Count, colors.Length, null, null);
                buffer.AddRange(colors);
                var cAccess = AddAccessor(accessors, cBuff, 0, Accessor.ComponentTypeEnum.FLOAT, colors.Length / sizeof(float) / 3, cMin, cMax, Accessor.TypeEnum.VEC3);
                prim.Attributes.Add("COLOR_0", cAccess);
            }

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            meshes.Add(m);

            return(meshes.Count - 1);
        }
Example #12
0
        private MgOptimizedStorageContainer GenerateMesh(
            glTFLoader.Schema.Gltf model,
            glTFLoader.Schema.Mesh mesh,
            IEffect effect,
            List <byte[]> buffers,
            BufferViewInfo[] bufferViews
            )
        {
            var  shaderLocations = effect.GetShaderAttributeLocations();
            var  accessors       = new List <GltfMeshAccessor>();
            uint primitiveIndex  = 0U;

            foreach (var primitive in mesh.Primitives)
            {
                if (primitive.Indices.HasValue)
                {
                    var accessor = ExtractAccessor(model, primitive.Indices.Value);
                    accessor.PrimitiveIndex = primitiveIndex;
                    accessor.Usage          = MgBufferUsageFlagBits.INDEX_BUFFER_BIT;
                    accessors.Add(accessor);
                }

                foreach (var attr in primitive.Attributes)
                {
                    var locationName  = attr.Key;
                    var accessorIndex = attr.Value;

                    var accessor = ExtractAccessor(model, accessorIndex);
                    accessor.PrimitiveIndex = primitiveIndex;
                    accessor.Usage          = MgBufferUsageFlagBits.VERTEX_BUFFER_BIT;
                    accessor.LocationIndex  = shaderLocations[locationName];
                    accessor.LocationName   = locationName;

                    accessors.Add(accessor);
                }
                primitiveIndex += 1;
            }

            var usedBufferViews  = new bool[bufferViews.Length];
            var blockAllocations = new List <MgStorageBlockAllocationInfo>();

            foreach (var attr in accessors)
            {
                var allocation = new MgStorageBlockAllocationInfo
                {
                    MemoryPropertyFlags = MgMemoryPropertyFlagBits.HOST_COHERENT_BIT,
                    Usage           = attr.Usage,
                    ElementByteSize = attr.ElementByteSize,
                    Size            = (ulong)(attr.NoOfComponents * attr.ElementCount * attr.ElementByteSize),
                };

                if (attr.BufferViewIndex.HasValue)
                {
                    usedBufferViews[attr.BufferViewIndex.Value] = true;
                }

                blockAllocations.Add(allocation);
            }

            var createInfo = new MgOptimizedStorageCreateInfo
            {
                Allocations = blockAllocations.ToArray(),
            };

            var meshData = mBuilder.Build(createInfo);

            var metaData = InitializeMetaData(meshData, usedBufferViews, bufferViews, accessors);

            // copy buffer data into device memory
            CopyBuffersInto(meshData, buffers, bufferViews, accessors);

            return(meshData);
        }
Example #13
0
        public Gltf FromBrg(BrgFile brg, Stream bufferStream)
        {
            // TODO clear class fields

            gltf.Asset         = new Asset();
            gltf.Asset.Version = "2.0";

            Scene scene = new Scene();

            scene.Nodes = new int[] { 0 };

            gltf.Scenes = new[] { scene };
            gltf.Scene  = 0;

            Node node = new Node();

            node.Mesh = 0;
            node.Name = "node";

            gltf.Nodes = new[] { node };

            //FromBrgMesh(brg.Meshes[0]);

            // Create materials / textures

            // Create primitives from first brg mesh
            // TODO: check if there is at least 1 mesh, and 1 face
            var primitives = (from face in brg.Meshes[0].Faces
                              group face by face.MaterialIndex into faceGroup
                              select new BrgMeshPrimitive(faceGroup.ToList())).ToList();

            // Load mesh data
            glTFLoader.Schema.Mesh mesh = new glTFLoader.Schema.Mesh();
            mesh.Primitives = new MeshPrimitive[primitives.Count];
            for (int i = 0; i < mesh.Primitives.Length; ++i)
            {
                mesh.Primitives[i] = new MeshPrimitive();
            }
            for (int j = 0; j < primitives.Count; ++j)
            {
                primitives[j].Serialize(mesh.Primitives[j], brg.Meshes[0], this, bufferStream);
            }
            for (int i = 0; i < brg.Meshes[0].MeshAnimations.Count; ++i)
            {
                for (int j = 0; j < primitives.Count; ++j)
                {
                    primitives[j].Serialize(mesh.Primitives[j], (BrgMesh)brg.Meshes[0].MeshAnimations[i], this, bufferStream);
                }
            }
            gltf.Meshes = new[] { mesh };

            // Create Animation
            if (brg.Meshes[0].MeshAnimations.Count > 0)
            {
                for (int i = 0; i < mesh.Primitives.Length; ++i)
                {
                    mesh.Primitives[i].Targets = primitives[i].Targets.ToArray();
                }

                mesh.Weights = new float[brg.Meshes[0].MeshAnimations.Count];

                gltf.Animations = new[] { CreateAnimation(brg.Animation, mesh.Weights.Length, bufferStream) };
            }

            // Create buffer stream
            gltf.BufferViews = bufferViews.ToArray();
            gltf.Accessors   = accessors.ToArray();
            var buffer = new glTFLoader.Schema.Buffer();

            gltf.Buffers      = new[] { buffer };
            buffer.ByteLength = (int)bufferStream.Length;
            buffer.Uri        = "dataBuffer.bin";

            return(gltf);
        }
Example #14
0
        private void AddRhinoObjectText(ObjectExportData data)
        {
            var materialIndex = GetMaterial(data.RenderMaterial, data.Object);

            var primitives = new List <MeshPrimitive>();

            foreach (var rhinoMesh in data.Meshes)
            {
                if (options.MapRhinoZToGltfY)
                {
                    rhinoMesh.Transform(ZtoYUp);
                }
                rhinoMesh.TextureCoordinates.ReverseTextureCoordinates(1);

                rhinoMesh.Faces.ConvertQuadsToTriangles();

                var vtxBuffer    = CreateVerticesBuffer(rhinoMesh.Vertices, out Point3d vtxMin, out Point3d vtxMax);
                int vtxBufferIdx = dummy.Buffers.AddAndReturnIndex(vtxBuffer);

                var idsBuffer    = CreateIndicesBuffer(rhinoMesh.Faces, out int indicesCount);
                int idsBufferIdx = dummy.Buffers.AddAndReturnIndex(idsBuffer);

                var normalsBuffer    = CreateNormalsBuffer(rhinoMesh.Normals, out Vector3f normalsMin, out Vector3f normalsMax);
                int normalsBufferIdx = dummy.Buffers.AddAndReturnIndex(normalsBuffer);

                var vtxBufferView = new BufferView()
                {
                    Buffer     = vtxBufferIdx,
                    ByteOffset = 0,
                    ByteLength = vtxBuffer.ByteLength,
                    Target     = BufferView.TargetEnum.ARRAY_BUFFER,
                };

                int vtxBufferViewIdx = dummy.BufferViews.AddAndReturnIndex(vtxBufferView);

                var idsBufferView = new BufferView()
                {
                    Buffer     = idsBufferIdx,
                    ByteOffset = 0,
                    ByteLength = idsBuffer.ByteLength,
                    Target     = BufferView.TargetEnum.ELEMENT_ARRAY_BUFFER,
                };

                int idsBufferViewIdx = dummy.BufferViews.AddAndReturnIndex(idsBufferView);

                BufferView normalsBufferView = new BufferView()
                {
                    Buffer     = normalsBufferIdx,
                    ByteOffset = 0,
                    ByteLength = normalsBuffer.ByteLength,
                    Target     = BufferView.TargetEnum.ARRAY_BUFFER,
                };

                int normalsBufferViewIdx = dummy.BufferViews.AddAndReturnIndex(normalsBufferView);

                // Create accessors
                Accessor vtxAccessor = new Accessor()
                {
                    BufferView    = vtxBufferViewIdx,
                    Count         = rhinoMesh.Vertices.Count,
                    Min           = new float[] { (float)vtxMin.X, (float)vtxMin.Y, (float)vtxMin.Z },
                    Max           = new float[] { (float)vtxMax.X, (float)vtxMax.Y, (float)vtxMax.Z },
                    Type          = Accessor.TypeEnum.VEC3,
                    ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                    ByteOffset    = 0,
                };

                int vtxAccessorIdx = dummy.Accessors.AddAndReturnIndex(vtxAccessor);

                Accessor idsAccessor = new Accessor()
                {
                    BufferView    = idsBufferViewIdx,
                    Count         = indicesCount,
                    Min           = new float[] { 0 },
                    Max           = new float[] { rhinoMesh.Vertices.Count - 1 },
                    Type          = Accessor.TypeEnum.SCALAR,
                    ComponentType = Accessor.ComponentTypeEnum.UNSIGNED_INT,
                    ByteOffset    = 0,
                };

                int idsAccessorIdx = dummy.Accessors.AddAndReturnIndex(idsAccessor);

                Accessor normalsAccessor = new Accessor()
                {
                    BufferView    = normalsBufferViewIdx,
                    Count         = rhinoMesh.Normals.Count,
                    Min           = new float[] { normalsMin.X, normalsMin.Y, normalsMin.Z },
                    Max           = new float[] { normalsMax.X, normalsMax.Y, normalsMax.Z },
                    Type          = Accessor.TypeEnum.VEC3,
                    ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                    ByteOffset    = 0,
                };

                int normalsAccessorIdx = dummy.Accessors.AddAndReturnIndex(normalsAccessor);

                var primitive = new MeshPrimitive()
                {
                    Attributes = new Dictionary <string, int>()
                    {
                        { Constants.PositionAttributeTag, vtxAccessorIdx },
                        { Constants.NormalAttributeTag, normalsAccessorIdx },
                    },
                    Indices  = idsAccessorIdx,
                    Material = materialIndex,
                };

                if (rhinoMesh.TextureCoordinates.Count > 0)
                {
                    var texCoordsBuffer    = CreateTextureCoordinatesBuffer(rhinoMesh.TextureCoordinates, out Point2f texCoordsMin, out Point2f texCoordsMax);
                    int texCoordsBufferIdx = dummy.Buffers.AddAndReturnIndex(texCoordsBuffer);

                    BufferView texCoordsBufferView = new BufferView()
                    {
                        Buffer     = texCoordsBufferIdx,
                        ByteOffset = 0,
                        ByteLength = texCoordsBuffer.ByteLength,
                        Target     = BufferView.TargetEnum.ARRAY_BUFFER,
                    };

                    int texCoordsBufferViewIdx = dummy.BufferViews.AddAndReturnIndex(texCoordsBufferView);

                    Accessor texCoordsAccessor = new Accessor()
                    {
                        BufferView    = texCoordsBufferViewIdx,
                        Count         = rhinoMesh.TextureCoordinates.Count,
                        Min           = new float[] { texCoordsMin.X, texCoordsMin.Y },
                        Max           = new float[] { texCoordsMax.X, texCoordsMax.Y },
                        Type          = Accessor.TypeEnum.VEC2,
                        ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                        ByteOffset    = 0,
                    };

                    int texCoordsAccessorIdx = dummy.Accessors.AddAndReturnIndex(texCoordsAccessor);

                    primitive.Attributes.Add(Constants.TexCoord0AttributeTag, texCoordsAccessorIdx);
                }

                // Create mesh
                primitives.Add(primitive);
            }

            var mesh = new glTFLoader.Schema.Mesh()
            {
                Primitives = primitives.ToArray(),
            };
            int idxMesh = dummy.Meshes.AddAndReturnIndex(mesh);

            var node = new Node()
            {
                Mesh = idxMesh,
                Name = string.IsNullOrEmpty(data.Object.Name) ? null : data.Object.Name,
            };

            int idxNode = dummy.Nodes.AddAndReturnIndex(node);

            dummy.Scenes[dummy.Scene].Nodes.Add(idxNode);
        }
Example #15
0
        private void AddRhinoObjectDraco(ObjectExportData data)
        {
            var materialIndex = GetMaterial(data.RenderMaterial, data.Object);

            var primitives = new List <MeshPrimitive>();

            // For each rhino mesh, create gl-buffers, gl-meshes, etc.
            foreach (var rhinoMesh in data.Meshes)
            {
                if (options.MapRhinoZToGltfY)
                {
                    rhinoMesh.Transform(ZtoYUp);
                }
                rhinoMesh.TextureCoordinates.ReverseTextureCoordinates(1);

                var dracoComp = DracoCompression.Compress(
                    rhinoMesh,
                    new DracoCompressionOptions()
                {
                    CompressionLevel                   = options.DracoCompressionLevel,
                    IncludeNormals                     = true,
                    IncludeTextureCoordinates          = true,
                    IncludeVertexColors                = false,
                    PositionQuantizationBits           = options.DracoQuantizationBitsPosition,
                    NormalQuantizationBits             = options.DracoQuantizationBitsNormal,
                    TextureCoordintateQuantizationBits = options.DracoQuantizationBitsTexture
                }
                    );

                DracoGeometryInfo dracoGeoInfo = AddDracoGeometry(dracoComp);

                var compMeshBufferView = new BufferView()
                {
                    Buffer     = dracoGeoInfo.bufferIndex,
                    ByteOffset = dracoGeoInfo.byteOffset,
                    ByteLength = dracoGeoInfo.byteLength,
                };

                int compMeshBufferViewIdx = dummy.BufferViews.AddAndReturnIndex(compMeshBufferView);

                var vtxAccessor = new Accessor
                {
                    Type          = Accessor.TypeEnum.VEC3,
                    ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                    Count         = dracoGeoInfo.verticesNum,
                    Min           = dracoGeoInfo.verticesMin,
                    Max           = dracoGeoInfo.verticesMax,
                    ByteOffset    = 0,
                };

                int vtxAccessorIdx = dummy.Accessors.AddAndReturnIndex(vtxAccessor);

                // // Accessor Triangles Vertex IDs
                var idsAccessor = new Accessor
                {
                    Type          = Accessor.TypeEnum.SCALAR,
                    ComponentType = Accessor.ComponentTypeEnum.UNSIGNED_INT,
                    Count         = dracoGeoInfo.trianglesNum,
                    Min           = new float[] { dracoGeoInfo.trianglesMin },
                    Max           = new float[] { dracoGeoInfo.trianglesMax },
                    ByteOffset    = 0,
                };

                int idsAccessorIdx = dummy.Accessors.AddAndReturnIndex(idsAccessor);

                // Accessor Normals
                var normalsAccessor = new Accessor
                {
                    Type          = Accessor.TypeEnum.VEC3,
                    ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                    Count         = dracoGeoInfo.normalsNum,
                    Min           = dracoGeoInfo.normalsMin,
                    Max           = dracoGeoInfo.normalsMax,
                    ByteOffset    = 0,
                };

                int normalsAccessorIdx = dummy.Accessors.AddAndReturnIndex(normalsAccessor);

                var primitive = new MeshPrimitive()
                {
                    Attributes = new Dictionary <string, int>()
                    {
                        { Constants.PositionAttributeTag, vtxAccessorIdx },
                        { Constants.NormalAttributeTag, normalsAccessorIdx },
                    },
                    Indices  = idsAccessorIdx,
                    Material = materialIndex,
                };

                if (dracoGeoInfo.texCoordsNum > 0)
                {
                    // Accessor TexCoords
                    var texCoordsAccessor = new Accessor
                    {
                        Type          = Accessor.TypeEnum.VEC2,
                        ComponentType = Accessor.ComponentTypeEnum.FLOAT,
                        Count         = dracoGeoInfo.texCoordsNum,
                        Min           = dracoGeoInfo.texCoordsMin,
                        Max           = dracoGeoInfo.texCoordsMax,
                        ByteOffset    = 0,
                    };

                    int texCoordsAccessorIdx = dummy.Accessors.AddAndReturnIndex(texCoordsAccessor);

                    primitive.Attributes.Add(Constants.TexCoord0AttributeTag, texCoordsAccessorIdx);

                    primitive.Extensions = new Dictionary <string, object>()
                    {
                        {
                            Constants.DracoMeshCompressionExtensionTag,
                            new
                            {
                                bufferView = compMeshBufferViewIdx,
                                attributes = new
                                {
                                    POSITION   = 0,
                                    NORMAL     = 1,
                                    TEXCOORD_0 = 2
                                }
                            }
                        }
                    };
                }
                else
                {
                    primitive.Extensions = new Dictionary <string, object>()
                    {
                        {
                            Constants.DracoMeshCompressionExtensionTag,
                            new
                            {
                                bufferView = compMeshBufferViewIdx,
                                attributes = new
                                {
                                    POSITION = 0,
                                    NORMAL   = 1,
                                }
                            }
                        }
                    };
                }

                // Create mesh
                primitives.Add(primitive);
            }

            var mesh = new glTFLoader.Schema.Mesh()
            {
                Primitives = primitives.ToArray(),
            };

            int meshIndex = dummy.Meshes.AddAndReturnIndex(mesh);

            var node = new Node()
            {
                Mesh = meshIndex,
            };
            int nodeIndex = dummy.Nodes.AddAndReturnIndex(node);

            dummy.Scenes[dummy.Scene].Nodes.Add(nodeIndex);
        }
Example #16
0
        /// <summary>
        /// Exports a gltf file from a meshed model
        /// </summary>
        /// <param name="model">The model needs to have the geometry meshes already cached</param>
        /// <param name="exclude">The types of elements that are going to be omitted (e.g. ifcSpaces).</param>
        /// <param name="EntityLebels">Only entities in the collection are exported; if null exports the whole model</param>
        /// <returns></returns>
        public gltf.Gltf BuildInstancedScene(IModel model, List <Type> exclude = null, HashSet <int> EntityLebels = null)
        {
            Init();
            Dictionary <int, ShapeComponentIds> geometries = new Dictionary <int, ShapeComponentIds>();

            // this needs a previously meshed xbim file.
            //
            var s = new Stopwatch();

            s.Start();
            int    iCnt          = 0;
            Random r             = new Random();
            var    excludedTypes = DefaultExclusions(model, exclude);

            using (var geomStore = model.GeometryStore)
                using (var geomReader = geomStore.BeginRead())
                {
                    // process the materials and styles
                    var sstyleIds = geomReader.StyleIds;
                    foreach (var styleId in sstyleIds)
                    {
                        PrepareStyleMaterial(model, styleId);
                    }
                    int productLabel   = 0;
                    var shapeInstances = GetShapeInstancesToRender(geomReader, excludedTypes, EntityLebels);
                    // foreach (var shapeInstance in shapeInstances.OrderBy(x=>x.IfcProductLabel))
                    gltf.Mesh targetMesh = null;
                    foreach (var shapeInstance in shapeInstances.OrderBy(x => x.IfcProductLabel))
                    {
                        if (CustomFilter != null)
                        {
                            var skip = CustomFilter(shapeInstance.IfcProductLabel, model);
                            if (skip)
                            {
                                continue;
                            }
                        }

                        // we start with a shape instance and then load its geometry.

                        // a product (e.g. wall or window) in the scene returns:
                        // - a node
                        //   - pointing to a mesh, with a transform
                        // - 1 mesh
                        //   - with as many mesh primitives as needed to render the different parts
                        //   - pointers to the a material and accessors as needed
                        // - 3 accessors per primitive
                        //   - vertices, normals, indices
                        // - bufferviews can be reused by different accessors
                        // - data in the buffer, of course

                        if (productLabel != shapeInstance.IfcProductLabel)
                        {
                            // need new product

                            // create node
                            var nodeIndex = _nodes.Count;
                            var entity    = model.Instances[shapeInstance.IfcProductLabel] as IIfcProduct;
                            if (entity == null)
                            { // fire error here.
                            }
                            var tnode = new gltf.Node();
                            tnode.Name   = entity.Name + $" #{entity.EntityLabel}";
                            tnode.Matrix = GetTransformInMeters(model, shapeInstance);

                            // create mesh
                            var meshIndex = _meshes.Count;
                            targetMesh = new gltf.Mesh
                            {
                                Name = $"Instance {productLabel}"
                            };

                            // link node to mesh
                            tnode.Mesh = meshIndex;

                            // add all to lists
                            _nodes.Add(tnode);
                            _meshes.Add(targetMesh);
                        }

                        // now the geometry
                        //
                        IXbimShapeGeometryData shapeGeom = geomReader.ShapeGeometry(shapeInstance.ShapeGeometryLabel);
                        if (shapeGeom.Format != (byte)XbimGeometryType.PolyhedronBinary)
                        {
                            continue;
                        }

                        // work out colour id;
                        // the colour is associated with the instance, not the geometry.
                        // positives are styles, negatives are types
                        var colId = shapeInstance.StyleLabel > 0
                        ? shapeInstance.StyleLabel
                        : shapeInstance.IfcTypeId * -1;

                        int materialIndex;
                        if (!styleDic.TryGetValue(colId, out materialIndex))
                        {
                            // if the style is not available we build one by ExpressType
                            materialIndex = PrepareTypeMaterial(model, shapeInstance.IfcTypeId);
                            styleDic.Add(colId, materialIndex);
                        }

                        // note: at a first investigation it looks like the shapeInstance.Transformation is the same for all shapes of the same product

                        if (shapeGeom.ReferenceCount > 1)
                        {
                            // retain the information to reuse the map multiple times
                            //

                            // if g is not found in the dictionary then build it and add it
                            ShapeComponentIds components;
                            if (!geometries.TryGetValue(shapeGeom.ShapeLabel, out components))
                            {
                                // mesh
                                var xbimMesher = new XbimMesher();
                                xbimMesher.AddMesh(shapeGeom.ShapeData);

                                components = AddGeom(
                                    xbimMesher.PositionsAsSingleList(model.ModelFactors.OneMeter),
                                    xbimMesher.Indices,
                                    xbimMesher.NormalsAsSingleList()
                                    );
                                geometries.Add(shapeGeom.ShapeLabel, components);
                            }

                            if (components != null)
                            {
                                var arr = GetTransformInMeters(model, shapeInstance);
                                AddComponentsToMesh(targetMesh, components, materialIndex);
                            }
                        }
                        else
                        {
                            // repeat the geometry only once
                            //
                            var xbimMesher = new XbimMesher();
                            xbimMesher.AddMesh(shapeGeom.ShapeData);
                            var trsf       = GetTransformInMeters(model, shapeInstance);
                            var components = AddGeom(
                                xbimMesher.PositionsAsSingleList(model.ModelFactors.OneMeter),
                                xbimMesher.Indices,
                                xbimMesher.NormalsAsSingleList()
                                );
                            AddComponentsToMesh(targetMesh, components, materialIndex);
                        }
                        iCnt++;
                        if (iCnt % 100 == 0)
                        {
                            Debug.WriteLine($"added {iCnt} elements in {s.ElapsedMilliseconds}ms.");
                        }
                    }
                }
            Debug.WriteLine($"added {iCnt} elements in {s.ElapsedMilliseconds}ms.");

            return(Build());
        }
Example #17
0
        private void FromBrgMesh(BrgMesh brgMesh)
        {
            Vector3 max = new Vector3(float.MinValue);
            Vector3 min = new Vector3(float.MaxValue);

            using (FileStream fs = File.Open("posBuffer.bin", FileMode.Create, FileAccess.Write, FileShare.Read))
                using (BinaryWriter writer = new BinaryWriter(fs))
                {
                    foreach (Vector3 vec in brgMesh.Vertices)
                    {
                        max.X = Math.Max(max.X, vec.X);
                        max.Y = Math.Max(max.Y, vec.Y);
                        max.Z = Math.Max(max.Z, vec.Z);

                        min.X = Math.Min(min.X, vec.X);
                        min.Y = Math.Min(min.Y, vec.Y);
                        min.Z = Math.Min(min.Z, vec.Z);

                        writer.Write(vec.X);
                        writer.Write(vec.Y);
                        writer.Write(vec.Z);
                    }
                }

            glTFLoader.Schema.Buffer posBuffer = new glTFLoader.Schema.Buffer();
            posBuffer.ByteLength = brgMesh.Vertices.Count * 12;
            posBuffer.Uri        = "posBuffer.bin";

            BufferView posBufferView = new BufferView();

            posBufferView.Buffer     = 0;
            posBufferView.ByteLength = posBuffer.ByteLength;
            posBufferView.ByteOffset = 0;
            posBufferView.ByteStride = 12;
            posBufferView.Name       = "posBufferView";
            posBufferView.Target     = BufferView.TargetEnum.ARRAY_BUFFER;

            Accessor posAccessor = new Accessor();

            posAccessor.BufferView    = 0;
            posAccessor.ByteOffset    = 0;
            posAccessor.ComponentType = Accessor.ComponentTypeEnum.FLOAT;
            posAccessor.Count         = brgMesh.Vertices.Count;
            posAccessor.Max           = new[] { max.X, max.Y, max.Z };
            posAccessor.Min           = new[] { min.X, min.Y, min.Z };
            posAccessor.Name          = "posBufferViewAccessor";
            posAccessor.Type          = Accessor.TypeEnum.VEC3;

            short faceMin = short.MaxValue;
            short faceMax = short.MinValue;

            using (FileStream fs = File.Open("indexBuffer.bin", FileMode.Create, FileAccess.Write, FileShare.Read))
                using (BinaryWriter writer = new BinaryWriter(fs))
                {
                    foreach (var face in brgMesh.Faces)
                    {
                        faceMin = Math.Min(faceMin, face.Indices[0]);
                        faceMin = Math.Min(faceMin, face.Indices[1]);
                        faceMin = Math.Min(faceMin, face.Indices[2]);

                        faceMax = Math.Max(faceMax, face.Indices[0]);
                        faceMax = Math.Max(faceMax, face.Indices[1]);
                        faceMax = Math.Max(faceMax, face.Indices[2]);

                        writer.Write(face.Indices[0]);
                        writer.Write(face.Indices[1]);
                        writer.Write(face.Indices[2]);
                    }
                }

            glTFLoader.Schema.Buffer indexBuffer = new glTFLoader.Schema.Buffer();
            indexBuffer.ByteLength = brgMesh.Faces.Count * 6;
            indexBuffer.Uri        = "indexBuffer.bin";

            BufferView indexBufferView = new BufferView();

            indexBufferView.Buffer     = 1;
            indexBufferView.ByteLength = indexBuffer.ByteLength;
            indexBufferView.ByteOffset = 0;
            indexBufferView.Name       = "indexBufferView";
            indexBufferView.Target     = BufferView.TargetEnum.ELEMENT_ARRAY_BUFFER;

            Accessor indexAccessor = new Accessor();

            indexAccessor.BufferView    = 1;
            indexAccessor.ByteOffset    = 0;
            indexAccessor.ComponentType = Accessor.ComponentTypeEnum.UNSIGNED_SHORT;
            indexAccessor.Count         = brgMesh.Faces.Count * 3;
            indexAccessor.Max           = new[] { (float)faceMax };
            indexAccessor.Min           = new[] { (float)faceMin };
            indexAccessor.Name          = "indexBufferViewAccessor";
            indexAccessor.Type          = Accessor.TypeEnum.SCALAR;

            gltf.Buffers     = new[] { posBuffer, indexBuffer };
            gltf.BufferViews = new[] { posBufferView, indexBufferView };
            gltf.Accessors   = new[] { posAccessor, indexAccessor };

            MeshPrimitive meshPrimitive = new MeshPrimitive();

            meshPrimitive.Attributes = new Dictionary <string, int>();
            meshPrimitive.Attributes.Add("POSITION", 0);
            meshPrimitive.Indices = 1;
            meshPrimitive.Mode    = MeshPrimitive.ModeEnum.TRIANGLES;

            var mesh = new glTFLoader.Schema.Mesh();

            mesh.Name       = "mesh";
            mesh.Primitives = new[] { meshPrimitive };

            gltf.Meshes = new[] { mesh };

            Node node = new Node();

            node.Mesh = 0;
            node.Name = "node";

            gltf.Nodes = new[] { node };
        }
Example #18
0
        internal static int AddTriangleMesh(this Gltf gltf, string name, List <byte> buffer, double[] vertices, double[] normals, ushort[] indices,
                                            float[] colors, double[] vMin, double[] vMax, double[] nMin, double[] nMax, double[] cMin, double[] cMax, ushort iMin, ushort iMax, int materialId, int?parent_index, Transform transform = null)
        {
            var m = new glTFLoader.Schema.Mesh();

            m.Name = name;

            var vBuff = gltf.AddBufferView(0, buffer.Count(), vertices.Length * sizeof(float), null, null);
            var nBuff = gltf.AddBufferView(0, buffer.Count() + vertices.Length * sizeof(float), normals.Length * sizeof(float), null, null);
            var iBuff = gltf.AddBufferView(0, buffer.Count() + vertices.Length * sizeof(float) + normals.Length * sizeof(float), indices.Length * sizeof(ushort), null, null);

            buffer.AddRange(vertices.SelectMany(v => BitConverter.GetBytes((float)v)));
            buffer.AddRange(normals.SelectMany(v => BitConverter.GetBytes((float)v)));
            buffer.AddRange(indices.SelectMany(v => BitConverter.GetBytes(v)));

            while (buffer.Count() % 4 != 0)
            {
                // Console.WriteLine("Padding...");
                buffer.Add(0);
            }

            var vAccess = gltf.AddAccessor(vBuff, 0, Accessor.ComponentTypeEnum.FLOAT, vertices.Length / 3, new[] { (float)vMin[0], (float)vMin[1], (float)vMin[2] }, new[] { (float)vMax[0], (float)vMax[1], (float)vMax[2] }, Accessor.TypeEnum.VEC3);
            var nAccess = gltf.AddAccessor(nBuff, 0, Accessor.ComponentTypeEnum.FLOAT, normals.Length / 3, new[] { (float)nMin[0], (float)nMin[1], (float)nMin[2] }, new[] { (float)nMax[0], (float)nMax[1], (float)nMax[2] }, Accessor.TypeEnum.VEC3);
            var iAccess = gltf.AddAccessor(iBuff, 0, Accessor.ComponentTypeEnum.UNSIGNED_SHORT, indices.Length, new[] { (float)iMin }, new[] { (float)iMax }, Accessor.TypeEnum.SCALAR);

            var prim = new MeshPrimitive();

            prim.Indices    = iAccess;
            prim.Material   = materialId;
            prim.Mode       = MeshPrimitive.ModeEnum.TRIANGLES;
            prim.Attributes = new Dictionary <string, int> {
                { "NORMAL", nAccess },
                { "POSITION", vAccess }
            };

            m.Primitives = new[] { prim };

            // Add mesh to gltf
            if (gltf.Meshes != null)
            {
                var meshes = gltf.Meshes.ToList();
                meshes.Add(m);
                gltf.Meshes = meshes.ToArray();
            }
            else
            {
                gltf.Meshes = new[] { m };
            }

            var parentId = 0;

            if (transform != null)
            {
                var a = transform.XAxis;
                var b = transform.YAxis;
                var c = transform.ZAxis;

                var transNode = new Node();

                transNode.Matrix = new[] {
                    (float)a.X, (float)a.Y, (float)a.Z, 0.0f,
                    (float)b.X, (float)b.Y, (float)b.Z, 0.0f,
                    (float)c.X, (float)c.Y, (float)c.Z, 0.0f,
                    (float)transform.Origin.X, (float)transform.Origin.Y, (float)transform.Origin.Z, 1.0f
                };

                parentId = gltf.AddNode(transNode, 0);
            }
            // Add mesh node to gltf
            var node = new Node();

            node.Mesh = gltf.Meshes.Length - 1;
            gltf.AddNode(node, parentId);

            return(gltf.Meshes.Length - 1);
        }