Browse Source

Merge pull request #8412 from Popov72/gltf-minmax-extents

GLTF: use min/max values from position accessor to set the bounding box of meshes
sebavan 5 years ago
parent
commit
9c0ef39182

+ 1 - 0
dist/preview release/what's new.md

@@ -100,6 +100,7 @@
 - Added support for KHR_materials_variants for glTF loader. ([MiiBond](https://github.com/MiiBond/))
 - Added support for KHR_materials_transmission for glTF loader. ([MiiBond](https://github.com/MiiBond/))
 - Improved progress handling in glTF loader. ([bghgary](https://github.com/bghgary))
+- Use min/max values from position accessors (when available) to set the bounding box of meshes ([Popov72](https://github.com/Popov72))
 - Added missing "pluginExtension" parameter to SceneLoader.ImportAnimations. ([phenry20](https://github.com/phenry20))
 
 ### Navigation

+ 18 - 1
loaders/src/glTF/2.0/glTFLoader.ts

@@ -33,6 +33,8 @@ import { IDataBuffer } from 'babylonjs/Misc/dataReader';
 import { LoadFileError } from 'babylonjs/Misc/fileTools';
 import { Logger } from 'babylonjs/Misc/logger';
 import { Light } from 'babylonjs/Lights/light';
+import { TmpVectors } from 'babylonjs/Maths/math.vector';
+import { BoundingInfo } from 'babylonjs/Culling/boundingInfo';
 
 interface TypedArrayLike extends ArrayBufferView {
     readonly length: number;
@@ -687,7 +689,12 @@ export class GLTFLoader implements IGLTFLoader {
 
         return Promise.all(promises).then(() => {
             this._forEachPrimitive(node, (babylonMesh) => {
-                babylonMesh.refreshBoundingInfo(true);
+                if ((babylonMesh as Mesh).geometry && (babylonMesh as Mesh).geometry!.useBoundingInfoFromGeometry) {
+                    // simply apply the world matrices to the bounding info - the extends are already ok
+                    babylonMesh._updateBoundingInfo();
+                } else {
+                    babylonMesh.refreshBoundingInfo(true);
+                }
             });
 
             return node._babylonTransformNode!;
@@ -863,6 +870,16 @@ export class GLTFLoader implements IGLTFLoader {
 
             const accessor = ArrayItem.Get(`${context}/attributes/${attribute}`, this._gltf.accessors, attributes[attribute]);
             promises.push(this._loadVertexAccessorAsync(`/accessors/${accessor.index}`, accessor, kind).then((babylonVertexBuffer) => {
+                if (babylonVertexBuffer.getKind() === VertexBuffer.PositionKind && !this.parent.alwaysComputeBoundingBox && !babylonMesh.skeleton) {
+                    const mmin = accessor.min as [number, number, number], mmax = accessor.max as [number, number, number];
+                    if (mmin !== undefined && mmax !== undefined) {
+                        const min = TmpVectors.Vector3[0], max = TmpVectors.Vector3[1];
+                        min.copyFromFloats(...mmin);
+                        max.copyFromFloats(...mmax);
+                        babylonGeometry._boundingInfo = new BoundingInfo(min, max);
+                        babylonGeometry.useBoundingInfoFromGeometry = true;
+                    }
+                }
                 babylonGeometry.setVerticesBuffer(babylonVertexBuffer, accessor.count);
             }));
 

+ 5 - 0
loaders/src/glTF/glTFFileLoader.ts

@@ -234,6 +234,11 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
     public createInstances = true;
 
     /**
+     * Defines if the loader should always compute the bounding boxes of meshes and not use the min/max values from the position accessor. Defaults to false.
+     */
+    public alwaysComputeBoundingBox = false;
+
+    /**
      * Function called before loading a url referenced by the asset.
      */
     public preprocessUrlAsync = (url: string) => Promise.resolve(url);

+ 17 - 4
src/Meshes/geometry.ts

@@ -113,6 +113,12 @@ export class Geometry implements IGetSetVerticesData {
     }
 
     /**
+     * If set to true (false by defaut), the bounding info applied to the meshes sharing this geometry will be the bounding info defined at the class level
+     * and won't be computed based on the vertex positions (which is what we get when useBoundingInfoFromGeometry = false)
+     */
+    public useBoundingInfoFromGeometry = false;
+
+    /**
      * Creates a new geometry
      * @param id defines the unique ID
      * @param scene defines the hosting scene
@@ -696,11 +702,18 @@ export class Geometry implements IGetSetVerticesData {
     }
 
     private _updateExtend(data: Nullable<FloatArray> = null) {
-        if (!data) {
-            data = this.getVerticesData(VertexBuffer.PositionKind)!;
-        }
+        if (this.useBoundingInfoFromGeometry && this._boundingInfo) {
+            this._extend = {
+                minimum: this._boundingInfo.minimum.clone(),
+                maximum: this._boundingInfo.maximum.clone()
+            };
+        } else {
+            if (!data) {
+                data = this.getVerticesData(VertexBuffer.PositionKind)!;
+            }
 
-        this._extend = extractMinAndMax(data, 0, this._totalVertices, this.boundingBias, 3);
+            this._extend = extractMinAndMax(data, 0, this._totalVertices, this.boundingBias, 3);
+        }
     }
 
     private _applyToMesh(mesh: Mesh): void {