UNPKG

@google/model-viewer

Version:

Easily display interactive 3D models on the web and in AR!

128 lines 5.97 kB
/* @license * Copyright 2020 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { FrontSide, Sphere } from 'three'; import { $clone, $prepare, $preparedGLTF, GLTFInstance } from '../GLTFInstance.js'; import { CorrelatedSceneGraph } from './correlated-scene-graph.js'; const $correlatedSceneGraph = Symbol('correlatedSceneGraph'); /** * This specialization of GLTFInstance collects all of the processing needed * to prepare a model and to clone it making special considerations for * <model-viewer> use cases. */ export class ModelViewerGLTFInstance extends GLTFInstance { /** * @override */ static [$prepare](source) { const prepared = super[$prepare](source); if (prepared[$correlatedSceneGraph] == null) { prepared[$correlatedSceneGraph] = CorrelatedSceneGraph.from(prepared); } const { scene } = prepared; const nullSphere = new Sphere(undefined, Infinity); scene.traverse((node) => { // Set a high renderOrder while we're here to ensure the model // always renders on top of the sky sphere node.renderOrder = 1000; // Three.js seems to cull some animated models incorrectly. Since we // expect to view our whole scene anyway, we turn off the frustum // culling optimization here. node.frustumCulled = false; // Animations for objects without names target their UUID instead. When // objects are cloned, they get new UUIDs which the animation can't // find. To fix this, we assign their UUID as their name. if (!node.name) { node.name = node.uuid; } const mesh = node; if (mesh.material) { const { geometry } = mesh; mesh.castShadow = true; if (mesh.isSkinnedMesh) { // Akin to disabling frustum culling above, we have to also manually // disable the bounds to make raycasting correct for skinned meshes. geometry.boundingSphere = nullSphere; // The bounding box is set in GLTFLoader by the accessor bounds, which // are not updated with animation. geometry.boundingBox = null; } const material = mesh.material; if (material.isMeshBasicMaterial === true) { material.toneMapped = false; } // This makes shadows better for non-manifold meshes material.shadowSide = FrontSide; // Fixes an edge case with unused extra UV-coords being incorrectly // referenced by three.js; remove when // https://github.com/mrdoob/three.js/pull/23974 is merged. if (material.aoMap) { const { gltf, threeObjectMap } = prepared[$correlatedSceneGraph]; const gltfRef = threeObjectMap.get(material); if (gltf.materials != null && gltfRef != null && gltfRef.materials != null) { const gltfMaterial = gltf.materials[gltfRef.materials]; if (gltfMaterial.occlusionTexture && gltfMaterial.occlusionTexture.texCoord === 0 && geometry.attributes.uv != null) { geometry.setAttribute('uv2', geometry.attributes.uv); } } } } }); return prepared; } get correlatedSceneGraph() { return this[$preparedGLTF][$correlatedSceneGraph]; } /** * @override */ [$clone]() { const clone = super[$clone](); const sourceUUIDToClonedMaterial = new Map(); clone.scene.traverse((node) => { // Materials aren't cloned when cloning meshes; geometry // and materials are copied by reference. This is necessary // for the same model to be used twice with different // scene-graph operations. const mesh = node; if (mesh.material) { const material = mesh.material; if (material != null) { if (sourceUUIDToClonedMaterial.has(material.uuid)) { mesh.material = sourceUUIDToClonedMaterial.get(material.uuid); return; } mesh.material = material.clone(); sourceUUIDToClonedMaterial.set(material.uuid, mesh.material); } } const light = node; if (light.target !== undefined) { // The target's parent is lost in the cloning process, but in // GLTFLoader, all light targets are children of their light. light.add(light.target); } }); // Cross-correlate the scene graph by relying on information in the // current scene graph; without this step, relationships between the // Three.js object graph and the glTF scene graph will be lost. clone[$correlatedSceneGraph] = CorrelatedSceneGraph.from(clone, this.correlatedSceneGraph); return clone; } } //# sourceMappingURL=ModelViewerGLTFInstance.js.map