private void InitScene() { _scene = new gltf.Scene(); _scene.Nodes = new[] { 0 }; _topNode = new gltf.Node(); _topNode.Name = "Z_UP"; _topNode.Matrix = new[] { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; _nodes.Add(_topNode); }
void loadNode (Node parentNode, GL.Node gltfNode) { Debug.WriteLine ("Loading node {0}", gltfNode.Name); Vector3 translation = new Vector3 (); Quaternion rotation = Quaternion.Identity; Vector3 scale = new Vector3 (1); Matrix4x4 localTransform = Matrix4x4.Identity; if (gltfNode.Matrix != null) { float[] M = gltfNode.Matrix; localTransform = new Matrix4x4 ( M[0], M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9],M[10],M[11], M[12],M[13],M[14],M[15]); } if (gltfNode.Translation != null) FromFloatArray (ref translation, gltfNode.Translation); if (gltfNode.Translation != null) FromFloatArray (ref rotation, gltfNode.Rotation); if (gltfNode.Translation != null) FromFloatArray (ref scale, gltfNode.Scale); localTransform *= Matrix4x4.CreateScale (scale) * Matrix4x4.CreateFromQuaternion (rotation) * Matrix4x4.CreateTranslation (translation); //localTransform = Matrix4x4.Identity; Node node = new Node { localMatrix = localTransform, Parent = parentNode, Name = gltfNode.Name }; parentNode.Children.Add (node); if (gltfNode.Children != null) { node.Children = new List<Node> (); for (int i = 0; i < gltfNode.Children.Length; i++) loadNode (node, gltf.Nodes[gltfNode.Children[i]]); } if (gltfNode.Mesh != null) node.Mesh = meshes[(int)gltfNode.Mesh]; }
/// <summary> /// We construct a new, recursively-structured 'ProtoNode' from the flat gltf node, and mutate its mesh indices to /// point to the correct mesh in the merged gltf. /// </summary> private static ProtoNode RecursivelyModifyMeshIndices(glTFLoader.Schema.Node node, List <int> meshIndices, glTFLoader.Schema.Node[] loadedNodes) { var protoNode = new ProtoNode(); protoNode.Matrix = node.Matrix; if (node.Mesh != null) { protoNode.Mesh = meshIndices[node.Mesh.Value]; } if (node.Children != null && node.Children.Count() > 0) { foreach (var child in node.Children) { protoNode.Children.Add(RecursivelyModifyMeshIndices(loadedNodes[child], meshIndices, loadedNodes)); } } return(protoNode); }
internal static void AddInstanceAsCopyOfNode( List <glTFLoader.Schema.Node> nodes, ProtoNode nodeToCopy, Transform transform, System.Guid instanceElementId) { // Two new nodes are created: a top-level node, which has the // element's Transform, and one just below that, which handles // flipping the orientation of the glb to have Z up. That node has // the node to copy as its only child. // We use the node to copy exactly as is, with an unmodified // transform. // We need the outermost node to be "purely" the element's // transform, so that the transform can be modified in explore at // runtime (e.g. by a transform override) and have the expected effect. float[] elementTransform = TransformToMatrix(transform); var newNode = new glTFLoader.Schema.Node(); newNode.Name = $"{instanceElementId}"; newNode.Matrix = elementTransform; nodes.Add(newNode); newNode.Children = new[] { nodes.Count }; var rootTransform = new Transform(); // glb has Y up. transform it to have Z up so we // can create instances of it in a Z up world. It will get switched // back to Y up further up in the node hierarchy. rootTransform.Rotate(new Vector3(1, 0, 0), 90.0); float[] glbOrientationTransform = TransformToMatrix(rootTransform); var elementOrientationNode = new glTFLoader.Schema.Node(); elementOrientationNode.Matrix = glbOrientationTransform; nodes.Add(elementOrientationNode); elementOrientationNode.Children = new[] { nodes.Count }; nodes[0].Children = (nodes[0].Children ?? Array.Empty <int>()).Concat(new[] { nodes.Count - 2 }).ToArray(); RecursivelyCopyNode(nodes, nodeToCopy); }
/// <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()); }
public Gltf ConvertToGltf() { dummy.Scene = 0; dummy.Scenes.Add(new gltfSchemaSceneDummy()); dummy.Asset = new Asset() { Version = "2.0", }; dummy.Samplers.Add(new Sampler() { MinFilter = Sampler.MinFilterEnum.LINEAR, MagFilter = Sampler.MagFilterEnum.LINEAR, WrapS = Sampler.WrapSEnum.REPEAT, WrapT = Sampler.WrapTEnum.REPEAT, }); if (options.UseDracoCompression) { dummy.ExtensionsUsed.Add(glTFExtensions.KHR_draco_mesh_compression.Tag); dummy.ExtensionsRequired.Add(glTFExtensions.KHR_draco_mesh_compression.Tag); } dummy.ExtensionsUsed.Add(glTFExtensions.KHR_materials_transmission.Tag); dummy.ExtensionsUsed.Add(glTFExtensions.KHR_materials_clearcoat.Tag); dummy.ExtensionsUsed.Add(glTFExtensions.KHR_materials_ior.Tag); dummy.ExtensionsUsed.Add(glTFExtensions.KHR_materials_specular.Tag); var sanitized = SanitizeRhinoObjects(objects); foreach (ObjectExportData exportData in sanitized) { int?materialIndex = GetMaterial(exportData.RenderMaterial, exportData.Object); RhinoMeshGltfConverter meshConverter = new RhinoMeshGltfConverter(exportData, materialIndex, options, binary, dummy, binaryBuffer); int meshIndex = meshConverter.AddMesh(); glTFLoader.Schema.Node node = new glTFLoader.Schema.Node() { Mesh = meshIndex, Name = GetObjectName(exportData.Object), }; int nodeIndex = dummy.Nodes.AddAndReturnIndex(node); if (options.ExportLayers) { AddToLayer(doc.Layers[exportData.Object.Attributes.LayerIndex], nodeIndex); } else { dummy.Scenes[dummy.Scene].Nodes.Add(nodeIndex); } } if (binary && binaryBuffer.Count > 0) { //have to add the empty buffer for the binary file header dummy.Buffers.Add(new glTFLoader.Schema.Buffer() { ByteLength = (int)binaryBuffer.Count, Uri = null, }); } return(dummy.ToSchemaGltf()); }