Example #1
0
        /// <summary>
        /// Runs once at end of export. Serializes the gltf
        /// properties and wites out the *.gltf and *.bin files.
        /// </summary>
        public void Finish()
        {
            Debug.WriteLine("Finishing...");

            glTFContainer container = manager.Finish();

            if (_cfgs.IncludeNonStdElements)
            {
                // TODO: [RM] Standardize what non glTF spec elements will go into
                // this "BIM glTF superset" and write a spec for it. Gridlines below
                // are an example.

                // Add gridlines as gltf nodes in the format:
                // Origin {Vec3<double>}, Direction {Vec3<double>}, Length {double}
                FilteredElementCollector col = new FilteredElementCollector(_doc)
                                               .OfClass(typeof(Grid));

                var grids = col.ToElements();
                foreach (Grid g in grids)
                {
                    Line l = g.Curve as Line;

                    var origin    = l.Origin;
                    var direction = l.Direction;
                    var length    = l.Length;

                    var xtras = new glTFExtras();
                    var grid  = new GridParameters();
                    grid.origin = new List <double>()
                    {
                        origin.X, origin.Y, origin.Z
                    };
                    grid.direction = new List <double>()
                    {
                        direction.X, direction.Y, direction.Z
                    };
                    grid.length          = length;
                    xtras.GridParameters = grid;
                    xtras.UniqueId       = g.UniqueId;
                    xtras.Properties     = Util.GetElementProperties(g, true);

                    var gridNode = new glTFNode();
                    gridNode.name   = g.Name;
                    gridNode.extras = xtras;

                    container.glTF.nodes.Add(gridNode);
                    container.glTF.nodes[0].children.Add(container.glTF.nodes.Count - 1);
                }
            }

            if (_cfgs.SingleBinary)
            {
                int bytePosition  = 0;
                int currentBuffer = 0;
                foreach (var view in container.glTF.bufferViews)
                {
                    if (view.buffer == 0)
                    {
                        bytePosition += view.byteLength;
                        continue;
                    }

                    if (view.buffer != currentBuffer)
                    {
                        view.buffer     = 0;
                        view.byteOffset = bytePosition;
                        bytePosition   += view.byteLength;
                    }
                }

                glTFBuffer buffer = new glTFBuffer();
                buffer.uri        = _filename + ".bin";
                buffer.byteLength = bytePosition;
                container.glTF.buffers.Clear();
                container.glTF.buffers.Add(buffer);

                using (FileStream f = File.Create(Path.Combine(_directory, buffer.uri)))
                {
                    using (BinaryWriter writer = new BinaryWriter(f))
                    {
                        foreach (var bin in container.binaries)
                        {
                            foreach (var coord in bin.contents.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.contents.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }
            else
            {
                // Write the *.bin files
                foreach (var bin in container.binaries)
                {
                    using (FileStream f = File.Create(Path.Combine(_directory, bin.name)))
                    {
                        using (BinaryWriter writer = new BinaryWriter(f))
                        {
                            foreach (var coord in bin.contents.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.contents.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }

            // Write the *.gltf file
            string serializedModel = JsonConvert.SerializeObject(container.glTF, new JsonSerializerSettings {
                NullValueHandling = NullValueHandling.Ignore
            });

            File.WriteAllText(Path.Combine(_directory, _filename + ".gltf"), serializedModel);
        }
Example #2
0
        /// <summary>
        /// Takes the intermediate geometry data and performs the calculations
        /// to convert that into glTF buffers, views, and accessors.
        /// </summary>
        /// <param name="geomData"></param>
        /// <param name="name">Unique name for the .bin file that will be produced.</param>
        /// <returns></returns>
        private glTFBinaryData processGeometry(GeometryData geom, string name)
        {
            // TODO: rename this type to glTFBufferMeta ?
            glTFBinaryData           bufferData     = new glTFBinaryData();
            glTFBinaryBufferContents bufferContents = new glTFBinaryBufferContents();

            foreach (var coord in geom.vertices)
            {
                float vFloat = Convert.ToSingle(coord);
                bufferContents.vertexBuffer.Add(vFloat);
            }
            foreach (var index in geom.faces)
            {
                bufferContents.indexBuffer.Add(index);
            }

            // Prevent buffer duplication by hash checking
            string calculatedHash = ManagerUtils.GenerateSHA256Hash(bufferContents);

            ManagerUtils.HashSearch hs = new ManagerUtils.HashSearch(calculatedHash);
            var match = binaryFileData.Find(hs.EqualTo);

            if (match != null)
            {
                // return previously created buffer metadata
                bufferData.vertexAccessorIndex = match.vertexAccessorIndex;
                bufferData.indexAccessorIndex  = match.indexAccessorIndex;
                return(bufferData);
            }
            else
            {
                // add a buffer
                glTFBuffer buffer = new glTFBuffer();
                buffer.uri = name + ".bin";
                buffers.Add(buffer);
                int bufferIdx = buffers.Count - 1;

                /**
                 * Buffer Data
                 **/
                bufferData.name     = buffer.uri;
                bufferData.contents = bufferContents;
                // TODO: Uncomment for normals
                //foreach (var normal in geomData.normals)
                //{
                //    bufferData.normalBuffer.Add((float)normal);
                //}

                // Get max and min for vertex data
                float[] vertexMinMax = Util.GetVec3MinMax(bufferContents.vertexBuffer);
                // Get max and min for index data
                int[] faceMinMax = Util.GetScalarMinMax(bufferContents.indexBuffer);
                // TODO: Uncomment for normals
                // Get max and min for normal data
                //float[] normalMinMax = getVec3MinMax(bufferData.normalBuffer);

                /**
                 * BufferViews
                 **/
                // Add a vec3 buffer view
                int            elementsPerVertex = 3;
                int            bytesPerElement   = 4;
                int            bytesPerVertex    = elementsPerVertex * bytesPerElement;
                int            numVec3           = (geom.vertices.Count) / elementsPerVertex;
                int            sizeOfVec3View    = numVec3 * bytesPerVertex;
                glTFBufferView vec3View          = new glTFBufferView();
                vec3View.buffer     = bufferIdx;
                vec3View.byteOffset = 0;
                vec3View.byteLength = sizeOfVec3View;
                vec3View.target     = Targets.ARRAY_BUFFER;
                bufferViews.Add(vec3View);
                int vec3ViewIdx = bufferViews.Count - 1;

                // TODO: Add a normals (vec3) buffer view

                // Add a faces / indexes buffer view
                int            elementsPerIndex     = 1;
                int            bytesPerIndexElement = 4;
                int            bytesPerIndex        = elementsPerIndex * bytesPerIndexElement;
                int            numIndexes           = geom.faces.Count;
                int            sizeOfIndexView      = numIndexes * bytesPerIndex;
                glTFBufferView facesView            = new glTFBufferView();
                facesView.buffer     = bufferIdx;
                facesView.byteOffset = vec3View.byteLength;
                facesView.byteLength = sizeOfIndexView;
                facesView.target     = Targets.ELEMENT_ARRAY_BUFFER;
                bufferViews.Add(facesView);
                int facesViewIdx = bufferViews.Count - 1;

                buffers[bufferIdx].byteLength = vec3View.byteLength + facesView.byteLength;

                /**
                 * Accessors
                 **/
                // add a position accessor
                glTFAccessor positionAccessor = new glTFAccessor();
                positionAccessor.bufferView    = vec3ViewIdx;
                positionAccessor.byteOffset    = 0;
                positionAccessor.componentType = ComponentType.FLOAT;
                positionAccessor.count         = geom.vertices.Count / elementsPerVertex;
                positionAccessor.type          = "VEC3";
                positionAccessor.max           = new List <float>()
                {
                    vertexMinMax[1], vertexMinMax[3], vertexMinMax[5]
                };
                positionAccessor.min = new List <float>()
                {
                    vertexMinMax[0], vertexMinMax[2], vertexMinMax[4]
                };
                accessors.Add(positionAccessor);
                bufferData.vertexAccessorIndex = accessors.Count - 1;

                // TODO: Uncomment for normals
                // add a normals accessor
                //glTFAccessor normalsAccessor = new glTFAccessor();
                //normalsAccessor.bufferView = vec3ViewIdx;
                //normalsAccessor.byteOffset = (positionAccessor.count) * bytesPerVertex;
                //normalsAccessor.componentType = ComponentType.FLOAT;
                //normalsAccessor.count = geom.data.normals.Count / elementsPerVertex;
                //normalsAccessor.type = "VEC3";
                //normalsAccessor.max = new List<float>() { normalMinMax[1], normalMinMax[3], normalMinMax[5] };
                //normalsAccessor.min = new List<float>() { normalMinMax[0], normalMinMax[2], normalMinMax[4] };
                //this.accessors.Add(normalsAccessor);
                //bufferData.normalsAccessorIndex = this.accessors.Count - 1;

                // add a face accessor
                glTFAccessor faceAccessor = new glTFAccessor();
                faceAccessor.bufferView    = facesViewIdx;
                faceAccessor.byteOffset    = 0;
                faceAccessor.componentType = ComponentType.UNSIGNED_INT;
                faceAccessor.count         = numIndexes;
                faceAccessor.type          = "SCALAR";
                faceAccessor.max           = new List <float>()
                {
                    faceMinMax[1]
                };
                faceAccessor.min = new List <float>()
                {
                    faceMinMax[0]
                };
                accessors.Add(faceAccessor);
                bufferData.indexAccessorIndex = accessors.Count - 1;

                bufferData.hashcode = calculatedHash;

                return(bufferData);
            }
        }
        /// <summary>
        /// Takes the intermediate geometry data and performs the calculations
        /// to convert that into glTF buffers, views, and accessors.
        /// </summary>
        /// <param name="geomData"></param>
        /// <param name="name">Unique name for the .bin file that will be produced.</param>
        /// <returns></returns>
        public glTFBinaryData AddGeometryMeta(GeometryData geomData, string name)
        {
            // add a buffer
            glTFBuffer buffer = new glTFBuffer();

            buffer.uri = name + ".bin";
            Buffers.Add(buffer);
            int bufferIdx = Buffers.Count - 1;

            /**
             * Buffer Data
             **/
            glTFBinaryData bufferData = new glTFBinaryData();

            bufferData.name = buffer.uri;
            foreach (var coord in geomData.vertices)
            {
                float vFloat = Convert.ToSingle(coord);
                bufferData.vertexBuffer.Add(vFloat);
            }
            foreach (var index in geomData.faces)
            {
                bufferData.indexBuffer.Add(index);
            }
            // TODO: Uncomment for normals
            //foreach (var normal in geomData.normals)
            //{
            //    bufferData.normalBuffer.Add((float)normal);
            //}

            // Get max and min for vertex data
            float[] vertexMinMax = Util.GetVec3MinMax(bufferData.vertexBuffer);
            // Get max and min for index data
            int[] faceMinMax = Util.GetScalarMinMax(bufferData.indexBuffer);
            // TODO: Uncomment for normals
            // Get max and min for normal data
            //float[] normalMinMax = getVec3MinMax(bufferData.normalBuffer);

            /**
             * BufferViews
             **/
            // Add a vec3 buffer view
            int            elementsPerVertex = 3;
            int            bytesPerElement   = 4;
            int            bytesPerVertex    = elementsPerVertex * bytesPerElement;
            int            numVec3           = (geomData.vertices.Count) / elementsPerVertex;
            int            sizeOfVec3View    = numVec3 * bytesPerVertex;
            glTFBufferView vec3View          = new glTFBufferView();

            vec3View.buffer     = bufferIdx;
            vec3View.byteOffset = 0;
            vec3View.byteLength = sizeOfVec3View;
            vec3View.target     = Targets.ARRAY_BUFFER;
            BufferViews.Add(vec3View);
            int vec3ViewIdx = BufferViews.Count - 1;

            // TODO: Add a normals (vec3) buffer view

            // Add a faces / indexes buffer view
            int            elementsPerIndex     = 1;
            int            bytesPerIndexElement = 4;
            int            bytesPerIndex        = elementsPerIndex * bytesPerIndexElement;
            int            numIndexes           = geomData.faces.Count;
            int            sizeOfIndexView      = numIndexes * bytesPerIndex;
            glTFBufferView facesView            = new glTFBufferView();

            facesView.buffer     = bufferIdx;
            facesView.byteOffset = vec3View.byteLength;
            facesView.byteLength = sizeOfIndexView;
            facesView.target     = Targets.ELEMENT_ARRAY_BUFFER;
            BufferViews.Add(facesView);
            int facesViewIdx = BufferViews.Count - 1;

            Buffers[bufferIdx].byteLength = vec3View.byteLength + facesView.byteLength;

            /**
             * Accessors
             **/
            // add a position accessor
            glTFAccessor positionAccessor = new glTFAccessor();

            positionAccessor.bufferView    = vec3ViewIdx;
            positionAccessor.byteOffset    = 0;
            positionAccessor.componentType = ComponentType.FLOAT;
            positionAccessor.count         = geomData.vertices.Count / elementsPerVertex;
            positionAccessor.type          = "VEC3";
            positionAccessor.max           = new List <float>()
            {
                vertexMinMax[1], vertexMinMax[3], vertexMinMax[5]
            };
            positionAccessor.min = new List <float>()
            {
                vertexMinMax[0], vertexMinMax[2], vertexMinMax[4]
            };
            Accessors.Add(positionAccessor);
            bufferData.vertexAccessorIndex = Accessors.Count - 1;

            // TODO: Uncomment for normals
            // add a normals accessor
            //glTFAccessor normalsAccessor = new glTFAccessor();
            //normalsAccessor.bufferView = vec3ViewIdx;
            //normalsAccessor.byteOffset = (positionAccessor.count) * bytesPerVertex;
            //normalsAccessor.componentType = ComponentType.FLOAT;
            //normalsAccessor.count = geom.data.normals.Count / elementsPerVertex;
            //normalsAccessor.type = "VEC3";
            //normalsAccessor.max = new List<float>() { normalMinMax[1], normalMinMax[3], normalMinMax[5] };
            //normalsAccessor.min = new List<float>() { normalMinMax[0], normalMinMax[2], normalMinMax[4] };
            //this.accessors.Add(normalsAccessor);
            //bufferData.normalsAccessorIndex = this.accessors.Count - 1;

            // add a face accessor
            glTFAccessor faceAccessor = new glTFAccessor();

            faceAccessor.bufferView    = facesViewIdx;
            faceAccessor.byteOffset    = 0;
            faceAccessor.componentType = ComponentType.UNSIGNED_INT;
            faceAccessor.count         = numIndexes;
            faceAccessor.type          = "SCALAR";
            faceAccessor.max           = new List <float>()
            {
                faceMinMax[1]
            };
            faceAccessor.min = new List <float>()
            {
                faceMinMax[0]
            };
            Accessors.Add(faceAccessor);
            bufferData.indexAccessorIndex = Accessors.Count - 1;

            return(bufferData);
        }
Example #4
0
        /// <summary>
        /// Runs once at end of export. Serializes the gltf
        /// properties and wites out the *.gltf and *.bin files.
        /// </summary>
        public void Finish()
        {
            Debug.WriteLine("Finishing...");

            gltfContainer = manager.Finish();

            if (_cfgs.IncludeNonStdElements)
            {
                // TODO: [RM] Standardize what non glTF spec elements will go into
                // this "BIM glTF superset" and write a spec for it. Gridlines below
                // are an example.

                // Add gridlines as gltf nodes in the format:
                // Origin {Vec3<double>}, Direction {Vec3<double>}, Length {double}
                FilteredElementCollector col = new FilteredElementCollector(_doc)
                                               .OfClass(typeof(Grid));

                var grids = col.ToElements();
                foreach (Grid g in grids)
                {
                    Line l = g.Curve as Line;

                    var origin    = l.Origin;
                    var direction = l.Direction;
                    var length    = l.Length;

                    var xtras = new glTFExtras();
                    var grid  = new GridParameters();
                    grid.origin = new List <double>()
                    {
                        origin.X, origin.Y, origin.Z
                    };
                    grid.direction = new List <double>()
                    {
                        direction.X, direction.Y, direction.Z
                    };
                    grid.length          = length;
                    xtras.GridParameters = grid;
                    xtras.UniqueId       = g.UniqueId;
                    xtras.Properties     = Util.GetElementProperties(g, true);

                    var gridNode = new glTFNode();
                    gridNode.name   = g.Name;
                    gridNode.extras = xtras;

                    gltfContainer.glTF.nodes.Add(gridNode);
                    gltfContainer.glTF.nodes[0].children.Add(gltfContainer.glTF.nodes.Count - 1);
                }
            }

            if (_cfgs.SingleBinary)
            {
                int bytePosition  = 0;
                int currentBuffer = 0;
                foreach (var view in gltfContainer.glTF.bufferViews)
                {
                    if (view.buffer == 0)
                    {
                        bytePosition += view.byteLength;
                        continue;
                    }

                    if (view.buffer != currentBuffer)
                    {
                        view.buffer     = 0;
                        view.byteOffset = bytePosition;
                        bytePosition   += view.byteLength;
                    }
                }

                glTFBuffer buffer = new glTFBuffer();
                buffer.uri        = _filename + ".bin";
                buffer.byteLength = bytePosition;
                gltfContainer.glTF.buffers.Clear();
                gltfContainer.glTF.buffers.Add(buffer);

                using (FileStream f = File.Create(Path.Combine(_directory, buffer.uri)))
                {
                    using (BinaryWriter writer = new BinaryWriter(f))
                    {
                        foreach (var bin in gltfContainer.binaries)
                        {
                            foreach (var coord in bin.contents.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.contents.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }
            else
            {
                // Write the *.bin files
                foreach (var bin in gltfContainer.binaries)
                {
                    using (FileStream f = File.Create(Path.Combine(_directory, bin.name)))
                    {
                        using (BinaryWriter writer = new BinaryWriter(f))
                        {
                            foreach (var coord in bin.contents.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.contents.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }

            try
            {
                // Write the *.gltf file
                string pgltf           = Path.Combine(_directory, _filename + ".gltf");
                string serializedModel = JsonConvert.SerializeObject(gltfContainer.glTF, new JsonSerializerSettings {
                    NullValueHandling = NullValueHandling.Ignore
                });
                File.WriteAllText(pgltf, serializedModel);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.GetType().Name + "\n" + ex.Message);
            }

            // FIXME convert to glb.
            // problem: can't load file or assembly System.Runtime.CompilerServices.Unsafe v4.0.6
            // see possible cause here https://stackoverflow.com/a/62769681
            // var mglb = SharpGLTF.Schema2.ModelRoot.Load(pgltf);
            // mglb.SaveGLB(Path.Combine(_directory, _filename + ".glb"));
        }
        /// <summary>
        /// Runs once at end of export. Serializes the gltf
        /// properties and wites out the *.gltf and *.bin files.
        /// </summary>
        public void Finish()
        {
            Debug.WriteLine("Finishing...");

            // TODO: [RM] Standardize what non glTF spec elements will go into
            // this "BIM glTF superset" and write a spec for it. Gridlines below
            // are an example.

            // Add gridlines as gltf nodes in the format:
            // Origin {Vec3<double>}, Direction {Vec3<double>}, Length {double}
            FilteredElementCollector col = new FilteredElementCollector(_doc)
                                           .OfClass(typeof(Grid));

            var grids = col.ToElements();

            foreach (Grid g in grids)
            {
                Line l = g.Curve as Line;

                var origin    = l.Origin;
                var direction = l.Direction;
                var length    = l.Length;

                var xtras = new glTFExtras();
                var grid  = new GridParameters();
                grid.origin = new List <double>()
                {
                    origin.X, origin.Y, origin.Z
                };
                grid.direction = new List <double>()
                {
                    direction.X, direction.Y, direction.Z
                };
                grid.length          = length;
                xtras.GridParameters = grid;
                xtras.UniqueId       = g.UniqueId;
                xtras.Properties     = Util.GetElementProperties(g, true);

                var gridNode = new glTFNode();
                gridNode.name   = g.Name;
                gridNode.extras = xtras;

                Nodes.AddOrUpdateCurrent(g.UniqueId, gridNode);
                rootNode.children.Add(Nodes.CurrentIndex);
            }

            if (_singleBinary)
            {
                int bytePosition  = 0;
                int currentBuffer = 0;
                foreach (var view in BufferViews)
                {
                    if (view.buffer == 0)
                    {
                        bytePosition += view.byteLength;
                        continue;
                    }

                    if (view.buffer != currentBuffer)
                    {
                        view.buffer     = 0;
                        view.byteOffset = bytePosition;
                        bytePosition   += view.byteLength;
                    }
                }

                glTFBuffer buffer = new glTFBuffer();
                buffer.uri        = "monobuffer.bin";
                buffer.byteLength = bytePosition;
                Buffers.Clear();
                Buffers.Add(buffer);

                using (FileStream f = File.Create(_directory + "monobuffer.bin"))
                {
                    using (BinaryWriter writer = new BinaryWriter(f))
                    {
                        foreach (var bin in binaryFileData)
                        {
                            foreach (var coord in bin.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }

            // Package the properties into a serializable container
            glTF model = new glTF();

            model.asset       = new glTFVersion();
            model.scenes      = Scenes;
            model.nodes       = Nodes.List;
            model.meshes      = Meshes.List;
            model.materials   = Materials.List;
            model.buffers     = Buffers;
            model.bufferViews = BufferViews;
            model.accessors   = Accessors;

            // Write the *.gltf file
            string serializedModel = JsonConvert.SerializeObject(model, new JsonSerializerSettings {
                NullValueHandling = NullValueHandling.Ignore
            });

            File.WriteAllText(_filename, serializedModel);

            if (!_singleBinary)
            {
                // Write the *.bin files
                foreach (var bin in binaryFileData)
                {
                    using (FileStream f = File.Create(_directory + bin.name))
                    {
                        using (BinaryWriter writer = new BinaryWriter(f))
                        {
                            foreach (var coord in bin.vertexBuffer)
                            {
                                writer.Write((float)coord);
                            }
                            // TODO: add writer for normals buffer
                            foreach (var index in bin.indexBuffer)
                            {
                                writer.Write((int)index);
                            }
                        }
                    }
                }
            }
        }