Skip to content

Commit 90a0822

Browse files
Updates to multiple-associations changes in Three.js mrdoob/three.js#21737
1 parent 973b427 commit 90a0822

File tree

3 files changed

+36
-81
lines changed

3 files changed

+36
-81
lines changed

packages/model-viewer/src/features/scene-graph/nodes/primitive-node.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* See the License for the specific language governing permissions and
1313
* limitations under the License.
1414
*/
15-
import {Material as ThreeMaterial, Mesh, MeshStandardMaterial} from 'three';
15+
import {Material as ThreeMaterial, Mesh} from 'three';
1616

1717
import {CorrelatedSceneGraph} from '../../../three-components/gltf-instance/correlated-scene-graph.js';
1818
import {KHRMaterialsVariants, Primitive} from '../../../three-components/gltf-instance/gltf-2.0.js';
@@ -54,19 +54,21 @@ export class PrimitiveNode extends Node {
5454
correlatedSceneGraph: CorrelatedSceneGraph) {
5555
super(mesh.name);
5656
this[$mesh] = mesh;
57-
const {gltf, threeGLTF} = correlatedSceneGraph;
57+
const {gltf, threeGLTF, threeObjectMap} = correlatedSceneGraph;
58+
5859
// Captures the primitive's initial material.
59-
const material = (mesh.material as MeshStandardMaterial);
60-
if (material.userData.associations != null &&
61-
material.userData.associations.materials != null) {
62-
this[$initialMaterialIdx] = material.userData.associations.materials;
60+
const materialMappings =
61+
threeObjectMap.get(mesh.material as ThreeMaterial)!;
62+
if (materialMappings.materials != null) {
63+
this[$initialMaterialIdx] = materialMappings.materials;
6364
} else {
6465
console.error(
6566
`Primitive (${mesh.name}) missing initial material reference.`);
6667
}
6768

6869
// Gets the mesh index from the node.
69-
const meshIndex = mesh.userData.associations.meshes;
70+
const meshMappings = threeObjectMap.get(mesh)!;
71+
const meshIndex = meshMappings.meshes!;
7072
// The gltf mesh array to sample from.
7173
const meshElementArray = gltf['meshes'] || [];
7274
// List of primitives under the mesh.

packages/model-viewer/src/three-components/gltf-instance/VariantMaterialLoaderPlugin.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,16 @@ export default class GLTFMaterialsVariantsExtension implements
110110
for (const scene of gltf.scenes) {
111111
// Save the variants data under associated mesh.userData
112112
scene.traverse(object => {
113-
if (object.userData.associations == null ||
114-
object.userData.associations.nodes == null) {
115-
return;
116-
}
113+
// The following code can be simplified if parser.associations directly
114+
// supports meshes.
115+
const association = parser.associations.get(object);
117116

118-
const nodeDef = json.nodes[object.userData.associations.nodes];
119-
const meshIndex = nodeDef.mesh;
120-
121-
if (meshIndex === undefined) {
117+
if (association == null || association.meshes == null) {
122118
return;
123119
}
124120

121+
const meshIndex = association.meshes;
122+
125123
// Two limitations:
126124
// 1. The nodeDef shouldn't have any objects (camera, light, or
127125
// nodeDef.extensions object)

packages/model-viewer/src/three-components/gltf-instance/correlated-scene-graph.ts

+21-66
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ export type GLTFElementToThreeObjectMap = Map<GLTFElement, ThreeObjectSet>;
1515
export type ThreeObjectToGLTFElementHandleMap =
1616
Map<ThreeSceneObject, GLTFReference>;
1717

18-
interface UserDataMapping {
19-
userData: {associations: any};
20-
}
21-
2218
const $threeGLTF = Symbol('threeGLTF');
2319
const $gltf = Symbol('gltf');
2420
const $gltfElementMap = Symbol('gltfElementMap');
@@ -27,7 +23,6 @@ const $parallelTraverseThreeScene = Symbol('parallelTraverseThreeScene');
2723

2824
const $correlateOriginalThreeGLTF = Symbol('correlateOriginalThreeGLTF');
2925
const $correlateCloneThreeGLTF = Symbol('correlateCloneThreeGLTF');
30-
const $getAssociationsData = Symbol('getAssociationsData');
3126

3227
/**
3328
* The Three.js GLTFLoader provides us with an in-memory representation
@@ -61,56 +56,51 @@ export class CorrelatedSceneGraph {
6156
}
6257
}
6358

64-
static[$getAssociationsData](object: ThreeSceneObject) {
65-
// Ensures userData exists on the threeObject.
66-
const userDataMapping = object as UserDataMapping;
67-
userDataMapping.userData = userDataMapping.userData || {};
68-
userDataMapping.userData.associations =
69-
userDataMapping.userData.associations || {};
70-
return userDataMapping.userData.associations;
71-
}
72-
73-
7459
private static[$correlateOriginalThreeGLTF](threeGLTF: ThreeGLTF):
7560
CorrelatedSceneGraph {
7661
const gltf = threeGLTF.parser.json as GLTF;
7762

7863
const associations =
79-
threeGLTF.parser.associations as Map<Object3D, GLTFReference>;
64+
threeGLTF.parser.associations as Map<ThreeSceneObject, GLTFReference>;
8065
const gltfElementMap: GLTFElementToThreeObjectMap = new Map();
8166

8267
const defaultMaterial = {name: 'Default'} as Material;
8368
const defaultReference = {type: 'materials', index: -1} as
8469
GLTFReferencePair;
8570

86-
// NOTE: IE11 does not have Map iterator methods
87-
associations.forEach((gltfMappings, threeObject) => {
88-
// Note: GLTFLoader creates a "default" material that has no corresponding
89-
// glTF element in the case that no materials are specified in the source
90-
// glTF. In this case we append a default material to allow this to be
91-
// operated upon.
92-
if (gltfMappings == null) {
71+
for (const threeMaterial of associations.keys()) {
72+
// Note: GLTFLoader creates a "default" material that has no
73+
// corresponding glTF element in the case that no materials are
74+
// specified in the source glTF. In this case we append a default
75+
// material to allow this to be operated upon.
76+
if (threeMaterial instanceof Material &&
77+
associations.get(threeMaterial) == null) {
9378
if (defaultReference.index < 0) {
9479
if (gltf.materials == null) {
9580
gltf.materials = [];
9681
}
9782
defaultReference.index = gltf.materials.length;
9883
gltf.materials.push(defaultMaterial);
99-
100-
// Updates the self-lookup user data.
101-
CorrelatedSceneGraph[$getAssociationsData](threeObject).materials =
102-
gltf.materials.length;
10384
}
10485

105-
gltfMappings = {materials: defaultReference.index};
86+
threeMaterial.name = defaultMaterial.name;
87+
associations.set(threeMaterial, {materials: defaultReference.index});
88+
}
89+
}
90+
91+
// Creates a reverse look up map (gltf-object to Three-object)
92+
for (const [threeObject, gltfMappings] of associations) {
93+
if (gltfMappings) {
94+
const objWithUserData = threeObject as {userData: {associations: {}}};
95+
objWithUserData.userData = objWithUserData.userData || {};
96+
objWithUserData.userData.associations = gltfMappings;
10697
}
10798

10899
for (const mapping in gltfMappings) {
109100
if (mapping != null && mapping !== 'primitives') {
110101
const type = mapping as GLTFReferenceType;
111102
const elementArray = gltf[type] || [];
112103
const gltfElement = elementArray[gltfMappings[type]!];
113-
114104
if (gltfElement == null) {
115105
// TODO: Maybe throw here...
116106
continue;
@@ -126,7 +116,7 @@ export class CorrelatedSceneGraph {
126116
threeObjects.add(threeObject);
127117
}
128118
}
129-
});
119+
}
130120

131121
return new CorrelatedSceneGraph(
132122
threeGLTF, gltf, associations, gltfElementMap);
@@ -147,49 +137,14 @@ export class CorrelatedSceneGraph {
147137
const cloneThreeObjectMap: ThreeObjectToGLTFElementHandleMap = new Map();
148138
const cloneGLTFElementMap: GLTFElementToThreeObjectMap = new Map();
149139

150-
const defaultMaterial = {name: 'Default'} as Material;
151-
const defaultReference = {materials: -1} as GLTFReference;
152-
153140
for (let i = 0; i < originalThreeGLTF.scenes.length; i++) {
154141
this[$parallelTraverseThreeScene](
155142
originalThreeGLTF.scenes[i],
156143
cloneThreeGLTF.scenes[i],
157144
(object: ThreeSceneObject, cloneObject: ThreeSceneObject) => {
158-
let elementReference =
145+
const elementReference =
159146
upstreamCorrelatedSceneGraph.threeObjectMap.get(object);
160147

161-
if (((object as Mesh).isMesh || (object as Material).isMaterial) &&
162-
elementReference == null) {
163-
// Checks if default material was already added to the gltf.
164-
if (cloneGLTF.materials && cloneGLTF.materials.length) {
165-
const material =
166-
cloneGLTF.materials[cloneGLTF.materials.length - 1];
167-
if (material.name === 'Default') {
168-
defaultReference.materials = cloneGLTF.materials.length - 1;
169-
CorrelatedSceneGraph[$getAssociationsData](object).materials =
170-
defaultReference.materials;
171-
}
172-
}
173-
174-
// Adds the default material if the default material was not
175-
// added.
176-
if (defaultReference.materials! < 0) {
177-
if (cloneGLTF.materials == null) {
178-
cloneGLTF.materials = [];
179-
}
180-
defaultReference.materials = cloneGLTF.materials.length;
181-
cloneGLTF.materials.push(defaultMaterial);
182-
183-
CorrelatedSceneGraph[$getAssociationsData](object).materials =
184-
defaultReference.materials;
185-
// Applies the user-data to the cloneObject.
186-
(cloneObject as UserDataMapping).userData =
187-
(object as UserDataMapping).userData;
188-
}
189-
190-
elementReference = defaultReference;
191-
}
192-
193148
if (elementReference == null) {
194149
return;
195150
}

0 commit comments

Comments
 (0)