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