From 80c21d91973eb7c81f98d03e50beb85a9c516fbb Mon Sep 17 00:00:00 2001 From: Starryi Date: Fri, 22 Nov 2024 17:57:18 +0800 Subject: [PATCH 1/2] fix: Load boundingInfo from position accessor when use KHR_draco_mesh_compression --- .../Meshes/Compression/dracoCompression.ts | 8 ++- .../Extensions/KHR_draco_mesh_compression.ts | 13 +++-- .../dev/loaders/src/glTF/2.0/glTFLoader.ts | 57 +++++++++++-------- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/packages/dev/core/src/Meshes/Compression/dracoCompression.ts b/packages/dev/core/src/Meshes/Compression/dracoCompression.ts index 0cd16c6aef2..4116b6d7698 100644 --- a/packages/dev/core/src/Meshes/Compression/dracoCompression.ts +++ b/packages/dev/core/src/Meshes/Compression/dracoCompression.ts @@ -1,4 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ +import type { BoundingInfo } from "../../Culling/boundingInfo"; import { Tools } from "../../Misc/tools"; import { AutoReleaseWorkerPool } from "../../Misc/workerPool"; import type { Nullable } from "../../types"; @@ -428,10 +429,15 @@ export class DracoCompression implements IDisposable { scene: Scene, data: ArrayBuffer | ArrayBufferView, attributes: { [kind: string]: number }, - gltfNormalizedOverride: { [kind: string]: boolean } + gltfNormalizedOverride: { [kind: string]: boolean }, + boundingInfo: Nullable ): Promise { const meshData = await this.decodeMeshToMeshDataAsync(data, attributes, gltfNormalizedOverride); const geometry = new Geometry(name, scene); + if (boundingInfo) { + geometry._boundingInfo = boundingInfo; + geometry.useBoundingInfoFromGeometry = true; + } if (meshData.indices) { geometry.setIndices(meshData.indices); } diff --git a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts index 267a446db64..db5d97831e5 100644 --- a/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts +++ b/packages/dev/loaders/src/glTF/2.0/Extensions/KHR_draco_mesh_compression.ts @@ -8,7 +8,7 @@ import { MeshPrimitiveMode } from "babylonjs-gltf2interface"; import type { IKHRDracoMeshCompression } from "babylonjs-gltf2interface"; import type { IMeshPrimitive, IBufferView } from "../glTFLoaderInterfaces"; import type { IGLTFLoaderExtension } from "../glTFLoaderExtension"; -import { GLTFLoader, ArrayItem } from "../glTFLoader"; +import { GLTFLoader, ArrayItem, LoadBoundingInfoFromPositionAccessor } from "../glTFLoader"; import { registerGLTFExtension, unregisterGLTFExtension } from "../glTFLoaderExtensionRegistry"; const NAME = "KHR_draco_mesh_compression"; @@ -120,9 +120,14 @@ export class KHR_draco_mesh_compression implements IGLTFLoaderExtension { if (!bufferView._dracoBabylonGeometry) { bufferView._dracoBabylonGeometry = this._loader.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => { const dracoCompression = this.dracoCompression || DracoCompression.Default; - return dracoCompression._decodeMeshToGeometryForGltfAsync(babylonMesh.name, this._loader.babylonScene, data, attributes, normalized).catch((error) => { - throw new Error(`${context}: ${error.message}`); - }); + const positionAccessor = ArrayItem.TryGet(this._loader.gltf.accessors, primitive.attributes["POSITION"]); + const babylonBoundingInfo = + !this._loader.parent.alwaysComputeBoundingBox && !babylonMesh.skeleton && positionAccessor ? LoadBoundingInfoFromPositionAccessor(positionAccessor) : null; + return dracoCompression + ._decodeMeshToGeometryForGltfAsync(babylonMesh.name, this._loader.babylonScene, data, attributes, normalized, babylonBoundingInfo) + .catch((error) => { + throw new Error(`${context}: ${error.message}`); + }); }); } diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index 151685b3420..c1589463d15 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -178,6 +178,36 @@ export interface IAnimationTargetInfo { properties: Array; } +/** @internal */ +export function LoadBoundingInfoFromPositionAccessor(accessor: IAccessor): Nullable { + if (accessor.min && accessor.max) { + const min = TmpVectors.Vector3[0].copyFromFloats(...(accessor.min as [number, number, number])); + const max = TmpVectors.Vector3[1].copyFromFloats(...(accessor.max as [number, number, number])); + if (accessor.normalized && accessor.componentType !== AccessorComponentType.FLOAT) { + let divider = 1; + switch (accessor.componentType) { + case AccessorComponentType.BYTE: + divider = 127.0; + break; + case AccessorComponentType.UNSIGNED_BYTE: + divider = 255.0; + break; + case AccessorComponentType.SHORT: + divider = 32767.0; + break; + case AccessorComponentType.UNSIGNED_SHORT: + divider = 65535.0; + break; + } + const oneOverDivider = 1 / divider; + min.scaleInPlace(oneOverDivider); + max.scaleInPlace(oneOverDivider); + } + return new BoundingInfo(min, max); + } + return null; +} + /** * The glTF 2.0 loader */ @@ -1118,30 +1148,9 @@ export class GLTFLoader implements IGLTFLoader { promises.push( this._loadVertexAccessorAsync(`/accessors/${accessor.index}`, accessor, kind).then((babylonVertexBuffer) => { if (babylonVertexBuffer.getKind() === VertexBuffer.PositionKind && !this.parent.alwaysComputeBoundingBox && !babylonMesh.skeleton) { - if (accessor.min && accessor.max) { - const min = TmpVectors.Vector3[0].copyFromFloats(...(accessor.min as [number, number, number])); - const max = TmpVectors.Vector3[1].copyFromFloats(...(accessor.max as [number, number, number])); - if (accessor.normalized && accessor.componentType !== AccessorComponentType.FLOAT) { - let divider = 1; - switch (accessor.componentType) { - case AccessorComponentType.BYTE: - divider = 127.0; - break; - case AccessorComponentType.UNSIGNED_BYTE: - divider = 255.0; - break; - case AccessorComponentType.SHORT: - divider = 32767.0; - break; - case AccessorComponentType.UNSIGNED_SHORT: - divider = 65535.0; - break; - } - const oneOverDivider = 1 / divider; - min.scaleInPlace(oneOverDivider); - max.scaleInPlace(oneOverDivider); - } - babylonGeometry._boundingInfo = new BoundingInfo(min, max); + const babylonBoundingInfo = LoadBoundingInfoFromPositionAccessor(accessor); + if (babylonBoundingInfo) { + babylonGeometry._boundingInfo = babylonBoundingInfo; babylonGeometry.useBoundingInfoFromGeometry = true; } } From 070cc4787430f043f832ccb5228245a59cd4f785 Mon Sep 17 00:00:00 2001 From: Starryi Date: Tue, 26 Nov 2024 16:15:58 +0800 Subject: [PATCH 2/2] Avoid generating extra arrays --- packages/dev/loaders/src/glTF/2.0/glTFLoader.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts index c1589463d15..cd303f4201f 100644 --- a/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts +++ b/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts @@ -181,8 +181,10 @@ export interface IAnimationTargetInfo { /** @internal */ export function LoadBoundingInfoFromPositionAccessor(accessor: IAccessor): Nullable { if (accessor.min && accessor.max) { - const min = TmpVectors.Vector3[0].copyFromFloats(...(accessor.min as [number, number, number])); - const max = TmpVectors.Vector3[1].copyFromFloats(...(accessor.max as [number, number, number])); + const minArray = accessor.min as [number, number, number]; + const maxArray = accessor.max as [number, number, number]; + const minVector = TmpVectors.Vector3[0].copyFromFloats(minArray[0], minArray[1], minArray[2]); + const maxVector = TmpVectors.Vector3[1].copyFromFloats(maxArray[0], maxArray[1], maxArray[2]); if (accessor.normalized && accessor.componentType !== AccessorComponentType.FLOAT) { let divider = 1; switch (accessor.componentType) { @@ -200,10 +202,10 @@ export function LoadBoundingInfoFromPositionAccessor(accessor: IAccessor): Nulla break; } const oneOverDivider = 1 / divider; - min.scaleInPlace(oneOverDivider); - max.scaleInPlace(oneOverDivider); + minVector.scaleInPlace(oneOverDivider); + maxVector.scaleInPlace(oneOverDivider); } - return new BoundingInfo(min, max); + return new BoundingInfo(minVector, maxVector); } return null; }