From b56cc3bd04c451a0f7f05649be895d7fd83eb7ea Mon Sep 17 00:00:00 2001 From: Takahiro Date: Mon, 12 Sep 2022 17:24:27 -0700 Subject: [PATCH] glTF MSFT_lod extension support --- package-lock.json | 11 ++++++ package.json | 1 + src/components/gltf-model-plus.js | 64 +++++++++++++++++++++++++++++-- src/utils/three-utils.js | 2 + 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88f6587545d..36f6b461f5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,6 +78,7 @@ "semver": "^7.3.2", "three": "github:mozillareality/three.js#d96f3cf69c7303db807cabaa2acba09d648e5e96", "three-ammo": "github:mozillareality/three-ammo", + "three-gltf-extensions": "^0.0.5", "three-mesh-bvh": "^0.3.7", "three-pathfinding": "^1.1.0", "three-to-ammo": "github:infinitelee/three-to-ammo", @@ -29090,6 +29091,11 @@ "three": "*" } }, + "node_modules/three-gltf-extensions": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/three-gltf-extensions/-/three-gltf-extensions-0.0.5.tgz", + "integrity": "sha512-Al7brZoNhN+j/W8TYrvbc4U2bIGtA+ai0hDO1LkPlK3MePUN/dbYufsUlzqY1N55yJUW+mIh18tRpntM2GBs6w==" + }, "node_modules/three-mesh-bvh": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.3.7.tgz", @@ -54238,6 +54244,11 @@ "from": "three-ammo@github:mozillareality/three-ammo", "requires": {} }, + "three-gltf-extensions": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/three-gltf-extensions/-/three-gltf-extensions-0.0.5.tgz", + "integrity": "sha512-Al7brZoNhN+j/W8TYrvbc4U2bIGtA+ai0hDO1LkPlK3MePUN/dbYufsUlzqY1N55yJUW+mIh18tRpntM2GBs6w==" + }, "three-mesh-bvh": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.3.7.tgz", diff --git a/package.json b/package.json index 2822f848522..91e9c0f9243 100644 --- a/package.json +++ b/package.json @@ -133,6 +133,7 @@ "semver": "^7.3.2", "three": "github:mozillareality/three.js#d96f3cf69c7303db807cabaa2acba09d648e5e96", "three-ammo": "github:mozillareality/three-ammo", + "three-gltf-extensions": "^0.0.5", "three-mesh-bvh": "^0.3.7", "three-pathfinding": "^1.1.0", "three-to-ammo": "github:infinitelee/three-to-ammo", diff --git a/src/components/gltf-model-plus.js b/src/components/gltf-model-plus.js index 5e93e16c831..e1f2247a864 100644 --- a/src/components/gltf-model-plus.js +++ b/src/components/gltf-model-plus.js @@ -11,6 +11,7 @@ import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader"; import { BasisTextureLoader } from "three/examples/jsm/loaders/BasisTextureLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; +import GLTFLodExtension from "three-gltf-extensions/loaders/MSFT_lod/MSFT_lod"; THREE.Mesh.prototype.raycast = acceleratedRaycast; @@ -376,6 +377,12 @@ function runMigration(version, json) { } } +const convertStandardMaterialsIfNeeded = (object) => { + const materialQuality = window.APP.store.state.preferences.materialQualitySetting; + updateMaterials(object, material => convertStandardMaterial(material, materialQuality)); + return object; +}; + let ktxLoader; let dracoLoader; @@ -441,8 +448,7 @@ class GLTFHubsPlugin { // GLTFLoader sets matrixAutoUpdate on animated objects, we want to keep the defaults // @TODO: Should this be fixed in the gltf loader? object.matrixAutoUpdate = THREE.Object3D.DefaultMatrixAutoUpdate; - const materialQuality = window.APP.store.state.preferences.materialQualitySetting; - updateMaterials(object, material => convertStandardMaterial(material, materialQuality)); + convertStandardMaterialsIfNeeded(object); }); // Replace animation target node name with the node uuid. @@ -656,7 +662,59 @@ export async function loadGLTF(src, contentType, onProgress, jsonPreprocessor) { .register(parser => new GLTFHubsPlugin(parser, jsonPreprocessor)) .register(parser => new GLTFHubsLightMapExtension(parser)) .register(parser => new GLTFHubsTextureBasisExtension(parser)) - .register(parser => new GLTFMozTextureRGBE(parser, new RGBELoader().setDataType(THREE.HalfFloatType))); + .register(parser => new GLTFMozTextureRGBE(parser, new RGBELoader().setDataType(THREE.HalfFloatType))) + .register(parser => new GLTFLodExtension(parser, { + loadingMode: 'progressive', + calculateDistance: (level) => { + // @TODO: Fix me. Calculate distance more appropriately. + return level; + }, + onLoadMesh: (lod, mesh, level, lowestLevel) => { + // Higher levels are progressively loaded on demand. + // So some post-loading processings done in gltf-model-plus and media-loader + // need to be done here now. + + // Nothing to do if this is the lowest level mesh. + if (level === lowestLevel || lod.levels.length === 0) { + return mesh; + } + + let lowestMeshLevel = null; + for (let index = lowestLevel; index > level; index--) { + if (lod.levels[index].object.type !== 'Object3D') { + lowestMeshLevel = index; + break; + } + } + + if (lowestMeshLevel === null) { + return mesh; + } + + // Create a mesh clone. Otherwise if an lod instance is cloned before higher + // levels are loaded the lods instance can refer to the same mesh instance, + // therefore the lods can be broken because an object can't be placed + // at multiple places in a Three.js scene tree. + mesh = mesh.clone(); + + convertStandardMaterialsIfNeeded(mesh); + + // A hacky solution. media-loader and media-utils make a material clone + // and inject shader code chunk for hover effects on before compile hook + // as a post-loading process. Here simulates them. + // @TODO: Check if this always works. Replace with a better and simpler solution. + const currentOnBeforeRender = mesh.material.onBeforeRender; + mesh.material = mesh.material.clone(); + mesh.material.currentOnBeforeRender = currentOnBeforeRender; + + // onBeforeCompile of the material of the lowest level mesh should be + // already set up because the lowest level should be loaded first. + mesh.material.onBeforeCompile = + lod.levels[lowestMeshLevel].object.material.onBeforeCompile; + + return mesh; + } + })); // TODO some models are loaded before the renderer exists. This is likely things like the camera tool and loading cube. // They don't currently use KTX textures but if they did this would be an issue. Fixing this is hard but is part of diff --git a/src/utils/three-utils.js b/src/utils/three-utils.js index 4f47f18e878..5df6a7c3627 100644 --- a/src/utils/three-utils.js +++ b/src/utils/three-utils.js @@ -165,6 +165,8 @@ export function cloneObject3D(source, preserveUUIDs) { return; } + clonedNode.onBeforeRender = sourceNode.onBeforeRender; + if (sourceNode.animations) { clonedNode.animations = sourceNode.animations.map(animationClip => cloneAnimationClip(animationClip, cloneUUIDLookup)