Esempio n. 1
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, XbimMatrix3D overallTransform, 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}";

                            // instance transformation needs to be expressed in meters
                            //
                            var inModelTransf = XbimMatrix3D.Copy(shapeInstance.Transformation);
                            inModelTransf.OffsetX /= model.ModelFactors.OneMeter;
                            inModelTransf.OffsetY /= model.ModelFactors.OneMeter;
                            inModelTransf.OffsetZ /= model.ModelFactors.OneMeter;

                            // overalltransform is already expressed in meters
                            var tMat = XbimMatrix3D.Multiply(inModelTransf, overallTransform);

                            tnode.Matrix = tMat.ToFloatArray();

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