three-gpu-pathtracer 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +981 -961
- package/build/index.module.js +6965 -6508
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +6959 -6505
- package/build/index.umd.cjs.map +1 -1
- package/package.json +73 -73
- package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +346 -346
- package/src/core/PathTracingSceneGenerator.js +69 -69
- package/src/core/QuiltPathTracingRenderer.js +223 -223
- package/src/index.js +36 -40
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/{GraphMaterial.js → debug/GraphMaterial.js} +243 -243
- package/src/materials/{AlphaDisplayMaterial.js → fullscreen/AlphaDisplayMaterial.js} +48 -48
- package/src/materials/{BlendMaterial.js → fullscreen/BlendMaterial.js} +67 -67
- package/src/materials/{DenoiseMaterial.js → fullscreen/DenoiseMaterial.js} +142 -142
- package/src/materials/{LambertPathTracingMaterial.js → pathtracing/LambertPathTracingMaterial.js} +296 -285
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +635 -0
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +179 -0
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +81 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +317 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +54 -0
- package/src/materials/{AmbientOcclusionMaterial.js → surface/AmbientOcclusionMaterial.js} +207 -199
- package/src/materials/surface/FogVolumeMaterial.js +23 -0
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +28 -28
- package/src/objects/PhysicalSpotLight.js +14 -14
- package/src/objects/ShapedAreaLight.js +12 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +490 -0
- package/src/shader/bsdf/fog.glsl.js +23 -0
- package/src/shader/bsdf/ggx.glsl.js +102 -0
- package/src/shader/bsdf/iridescence.glsl.js +135 -0
- package/src/shader/bsdf/sheen.glsl.js +98 -0
- package/src/shader/{shaderLayerTexelFetchFunctions.js → common/arraySamplerTexelFetch.glsl.js} +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -0
- package/src/shader/common/fresnel.glsl.js +98 -0
- package/src/shader/common/intersectShapes.glsl.js +62 -0
- package/src/shader/common/math.glsl.js +81 -0
- package/src/shader/common/utils.glsl.js +116 -0
- package/src/shader/{shaderRandFunctions.js → rand/pcg.glsl.js} +57 -57
- package/src/shader/{shaderSobolSampling.js → rand/sobol.glsl.js} +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -0
- package/src/shader/sampling/lightSampling.glsl.js +223 -0
- package/src/shader/sampling/shapeSampling.glsl.js +86 -0
- package/src/shader/structs/cameraStruct.glsl.js +13 -0
- package/src/shader/structs/equirectStruct.glsl.js +14 -0
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -0
- package/src/shader/structs/lightsStruct.glsl.js +78 -0
- package/src/shader/{shaderStructs.js → structs/materialStruct.glsl.js} +207 -327
- package/src/textures/GradientEquirectTexture.js +35 -35
- package/src/textures/ProceduralEquirectTexture.js +75 -75
- package/src/uniforms/AttributesTextureArray.js +35 -35
- package/src/uniforms/EquirectHdrInfoUniform.js +277 -273
- package/src/uniforms/FloatAttributeTextureArray.js +169 -169
- package/src/uniforms/IESProfilesTexture.js +100 -100
- package/src/uniforms/LightsInfoUniformStruct.js +212 -212
- package/src/uniforms/MaterialsTexture.js +503 -426
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +97 -97
- package/src/uniforms/utils.js +30 -30
- package/src/utils/BlurredEnvMapGenerator.js +116 -116
- package/src/utils/GeometryPreparationUtils.js +214 -214
- package/src/utils/IESLoader.js +325 -325
- package/src/utils/SobolNumberMapGenerator.js +80 -80
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/utils/macroify.js +9 -0
- package/src/workers/PathTracingSceneWorker.js +42 -42
- package/src/materials/PhysicalPathTracingMaterial.js +0 -1013
- package/src/shader/shaderBvhAnyHit.js +0 -76
- package/src/shader/shaderEnvMapSampling.js +0 -58
- package/src/shader/shaderGGXFunctions.js +0 -100
- package/src/shader/shaderIridescenceFunctions.js +0 -135
- package/src/shader/shaderLightSampling.js +0 -229
- package/src/shader/shaderMaterialSampling.js +0 -510
- package/src/shader/shaderSheenFunctions.js +0 -98
- package/src/shader/shaderUtils.js +0 -377
|
@@ -1,256 +1,256 @@
|
|
|
1
|
-
// https://github.com/gkjohnson/webxr-sandbox/blob/main/skinned-mesh-batching/src/MaterialReducer.js
|
|
2
|
-
|
|
3
|
-
function isTypedArray( arr ) {
|
|
4
|
-
|
|
5
|
-
return arr.buffer instanceof ArrayBuffer && 'BYTES_PER_ELEMENT' in arr;
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class MaterialReducer {
|
|
10
|
-
|
|
11
|
-
constructor() {
|
|
12
|
-
|
|
13
|
-
const ignoreKeys = new Set();
|
|
14
|
-
ignoreKeys.add( 'uuid' );
|
|
15
|
-
|
|
16
|
-
this.ignoreKeys = ignoreKeys;
|
|
17
|
-
this.shareTextures = true;
|
|
18
|
-
this.textures = [];
|
|
19
|
-
this.materials = [];
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
areEqual( objectA, objectB ) {
|
|
24
|
-
|
|
25
|
-
const keySet = new Set();
|
|
26
|
-
const traverseSet = new Set();
|
|
27
|
-
const ignoreKeys = this.ignoreKeys;
|
|
28
|
-
|
|
29
|
-
const traverse = ( a, b ) => {
|
|
30
|
-
|
|
31
|
-
if ( a === b ) {
|
|
32
|
-
|
|
33
|
-
return true;
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if ( a && b && a instanceof Object && b instanceof Object ) {
|
|
38
|
-
|
|
39
|
-
if ( traverseSet.has( a ) || traverseSet.has( b ) ) {
|
|
40
|
-
|
|
41
|
-
throw new Error( 'MaterialReducer: Material is recursive.' );
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const aIsElement = a instanceof Element;
|
|
46
|
-
const bIsElement = b instanceof Element;
|
|
47
|
-
if ( aIsElement || bIsElement ) {
|
|
48
|
-
|
|
49
|
-
if ( aIsElement !== bIsElement || ! ( a instanceof Image ) || ! ( b instanceof Image ) ) {
|
|
50
|
-
|
|
51
|
-
return false;
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return a.src === b.src;
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const aIsImageBitmap = a instanceof ImageBitmap;
|
|
60
|
-
const bIsImageBitmap = b instanceof ImageBitmap;
|
|
61
|
-
if ( aIsImageBitmap || bIsImageBitmap ) {
|
|
62
|
-
|
|
63
|
-
return false;
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if ( a.equals ) {
|
|
68
|
-
|
|
69
|
-
return a.equals( b );
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const aIsTypedArray = isTypedArray( a );
|
|
74
|
-
const bIsTypedArray = isTypedArray( b );
|
|
75
|
-
if ( aIsTypedArray || bIsTypedArray ) {
|
|
76
|
-
|
|
77
|
-
if ( aIsTypedArray !== bIsTypedArray || a.constructor !== b.constructor || a.length !== b.length ) {
|
|
78
|
-
|
|
79
|
-
return false;
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
for ( let i = 0, l = a.length; i < l; i ++ ) {
|
|
84
|
-
|
|
85
|
-
if ( a[ i ] !== b[ i ] ) return false;
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return true;
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
traverseSet.add( a );
|
|
94
|
-
traverseSet.add( b );
|
|
95
|
-
|
|
96
|
-
keySet.clear();
|
|
97
|
-
for ( const key in a ) {
|
|
98
|
-
|
|
99
|
-
if ( ! a.hasOwnProperty( key ) || a[ key ] instanceof Function || ignoreKeys.has( key ) ) {
|
|
100
|
-
|
|
101
|
-
continue;
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
keySet.add( key );
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
for ( const key in b ) {
|
|
110
|
-
|
|
111
|
-
if ( ! b.hasOwnProperty( key ) || b[ key ] instanceof Function || ignoreKeys.has( key ) ) {
|
|
112
|
-
|
|
113
|
-
continue;
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
keySet.add( key );
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const keys = Array.from( keySet.values() );
|
|
122
|
-
let result = true;
|
|
123
|
-
for ( const i in keys ) {
|
|
124
|
-
|
|
125
|
-
const key = keys[ i ];
|
|
126
|
-
if ( ignoreKeys.has( key ) ) {
|
|
127
|
-
|
|
128
|
-
continue;
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
result = traverse( a[ key ], b[ key ] );
|
|
133
|
-
if ( ! result ) {
|
|
134
|
-
|
|
135
|
-
break;
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
traverseSet.delete( a );
|
|
142
|
-
traverseSet.delete( b );
|
|
143
|
-
return result;
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return false;
|
|
148
|
-
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
return traverse( objectA, objectB );
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
process( object ) {
|
|
156
|
-
|
|
157
|
-
const { textures, materials } = this;
|
|
158
|
-
let replaced = 0;
|
|
159
|
-
|
|
160
|
-
const processMaterial = material => {
|
|
161
|
-
|
|
162
|
-
// Check if another material matches this one
|
|
163
|
-
let foundMaterial = null;
|
|
164
|
-
for ( const i in materials ) {
|
|
165
|
-
|
|
166
|
-
const otherMaterial = materials[ i ];
|
|
167
|
-
if ( this.areEqual( material, otherMaterial ) ) {
|
|
168
|
-
|
|
169
|
-
foundMaterial = otherMaterial;
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if ( foundMaterial ) {
|
|
176
|
-
|
|
177
|
-
replaced ++;
|
|
178
|
-
return foundMaterial;
|
|
179
|
-
|
|
180
|
-
} else {
|
|
181
|
-
|
|
182
|
-
materials.push( material );
|
|
183
|
-
|
|
184
|
-
if ( this.shareTextures ) {
|
|
185
|
-
|
|
186
|
-
// See if there's another texture that matches the ones on this material
|
|
187
|
-
for ( const key in material ) {
|
|
188
|
-
|
|
189
|
-
if ( ! material.hasOwnProperty( key ) ) continue;
|
|
190
|
-
|
|
191
|
-
const value = material[ key ];
|
|
192
|
-
if ( value && value.isTexture && value.image instanceof Image ) {
|
|
193
|
-
|
|
194
|
-
let foundTexture = null;
|
|
195
|
-
for ( const i in textures ) {
|
|
196
|
-
|
|
197
|
-
const texture = textures[ i ];
|
|
198
|
-
if ( this.areEqual( texture, value ) ) {
|
|
199
|
-
|
|
200
|
-
foundTexture = texture;
|
|
201
|
-
break;
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if ( foundTexture ) {
|
|
208
|
-
|
|
209
|
-
material[ key ] = foundTexture;
|
|
210
|
-
|
|
211
|
-
} else {
|
|
212
|
-
|
|
213
|
-
textures.push( value );
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return material;
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
object.traverse( c => {
|
|
230
|
-
|
|
231
|
-
if ( c.isMesh && c.material ) {
|
|
232
|
-
|
|
233
|
-
const material = c.material;
|
|
234
|
-
if ( Array.isArray( material ) ) {
|
|
235
|
-
|
|
236
|
-
for ( let i = 0; i < material.length; i ++ ) {
|
|
237
|
-
|
|
238
|
-
material[ i ] = processMaterial( material[ i ] );
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
} else {
|
|
243
|
-
|
|
244
|
-
c.material = processMaterial( material );
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
} );
|
|
251
|
-
|
|
252
|
-
return { replaced, retained: materials.length };
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
}
|
|
1
|
+
// https://github.com/gkjohnson/webxr-sandbox/blob/main/skinned-mesh-batching/src/MaterialReducer.js
|
|
2
|
+
|
|
3
|
+
function isTypedArray( arr ) {
|
|
4
|
+
|
|
5
|
+
return arr.buffer instanceof ArrayBuffer && 'BYTES_PER_ELEMENT' in arr;
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class MaterialReducer {
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
|
|
13
|
+
const ignoreKeys = new Set();
|
|
14
|
+
ignoreKeys.add( 'uuid' );
|
|
15
|
+
|
|
16
|
+
this.ignoreKeys = ignoreKeys;
|
|
17
|
+
this.shareTextures = true;
|
|
18
|
+
this.textures = [];
|
|
19
|
+
this.materials = [];
|
|
20
|
+
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
areEqual( objectA, objectB ) {
|
|
24
|
+
|
|
25
|
+
const keySet = new Set();
|
|
26
|
+
const traverseSet = new Set();
|
|
27
|
+
const ignoreKeys = this.ignoreKeys;
|
|
28
|
+
|
|
29
|
+
const traverse = ( a, b ) => {
|
|
30
|
+
|
|
31
|
+
if ( a === b ) {
|
|
32
|
+
|
|
33
|
+
return true;
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if ( a && b && a instanceof Object && b instanceof Object ) {
|
|
38
|
+
|
|
39
|
+
if ( traverseSet.has( a ) || traverseSet.has( b ) ) {
|
|
40
|
+
|
|
41
|
+
throw new Error( 'MaterialReducer: Material is recursive.' );
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const aIsElement = a instanceof Element;
|
|
46
|
+
const bIsElement = b instanceof Element;
|
|
47
|
+
if ( aIsElement || bIsElement ) {
|
|
48
|
+
|
|
49
|
+
if ( aIsElement !== bIsElement || ! ( a instanceof Image ) || ! ( b instanceof Image ) ) {
|
|
50
|
+
|
|
51
|
+
return false;
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return a.src === b.src;
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const aIsImageBitmap = a instanceof ImageBitmap;
|
|
60
|
+
const bIsImageBitmap = b instanceof ImageBitmap;
|
|
61
|
+
if ( aIsImageBitmap || bIsImageBitmap ) {
|
|
62
|
+
|
|
63
|
+
return false;
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if ( a.equals ) {
|
|
68
|
+
|
|
69
|
+
return a.equals( b );
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const aIsTypedArray = isTypedArray( a );
|
|
74
|
+
const bIsTypedArray = isTypedArray( b );
|
|
75
|
+
if ( aIsTypedArray || bIsTypedArray ) {
|
|
76
|
+
|
|
77
|
+
if ( aIsTypedArray !== bIsTypedArray || a.constructor !== b.constructor || a.length !== b.length ) {
|
|
78
|
+
|
|
79
|
+
return false;
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
for ( let i = 0, l = a.length; i < l; i ++ ) {
|
|
84
|
+
|
|
85
|
+
if ( a[ i ] !== b[ i ] ) return false;
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return true;
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
traverseSet.add( a );
|
|
94
|
+
traverseSet.add( b );
|
|
95
|
+
|
|
96
|
+
keySet.clear();
|
|
97
|
+
for ( const key in a ) {
|
|
98
|
+
|
|
99
|
+
if ( ! a.hasOwnProperty( key ) || a[ key ] instanceof Function || ignoreKeys.has( key ) ) {
|
|
100
|
+
|
|
101
|
+
continue;
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
keySet.add( key );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for ( const key in b ) {
|
|
110
|
+
|
|
111
|
+
if ( ! b.hasOwnProperty( key ) || b[ key ] instanceof Function || ignoreKeys.has( key ) ) {
|
|
112
|
+
|
|
113
|
+
continue;
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
keySet.add( key );
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const keys = Array.from( keySet.values() );
|
|
122
|
+
let result = true;
|
|
123
|
+
for ( const i in keys ) {
|
|
124
|
+
|
|
125
|
+
const key = keys[ i ];
|
|
126
|
+
if ( ignoreKeys.has( key ) ) {
|
|
127
|
+
|
|
128
|
+
continue;
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
result = traverse( a[ key ], b[ key ] );
|
|
133
|
+
if ( ! result ) {
|
|
134
|
+
|
|
135
|
+
break;
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
traverseSet.delete( a );
|
|
142
|
+
traverseSet.delete( b );
|
|
143
|
+
return result;
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return false;
|
|
148
|
+
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return traverse( objectA, objectB );
|
|
152
|
+
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
process( object ) {
|
|
156
|
+
|
|
157
|
+
const { textures, materials } = this;
|
|
158
|
+
let replaced = 0;
|
|
159
|
+
|
|
160
|
+
const processMaterial = material => {
|
|
161
|
+
|
|
162
|
+
// Check if another material matches this one
|
|
163
|
+
let foundMaterial = null;
|
|
164
|
+
for ( const i in materials ) {
|
|
165
|
+
|
|
166
|
+
const otherMaterial = materials[ i ];
|
|
167
|
+
if ( this.areEqual( material, otherMaterial ) ) {
|
|
168
|
+
|
|
169
|
+
foundMaterial = otherMaterial;
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if ( foundMaterial ) {
|
|
176
|
+
|
|
177
|
+
replaced ++;
|
|
178
|
+
return foundMaterial;
|
|
179
|
+
|
|
180
|
+
} else {
|
|
181
|
+
|
|
182
|
+
materials.push( material );
|
|
183
|
+
|
|
184
|
+
if ( this.shareTextures ) {
|
|
185
|
+
|
|
186
|
+
// See if there's another texture that matches the ones on this material
|
|
187
|
+
for ( const key in material ) {
|
|
188
|
+
|
|
189
|
+
if ( ! material.hasOwnProperty( key ) ) continue;
|
|
190
|
+
|
|
191
|
+
const value = material[ key ];
|
|
192
|
+
if ( value && value.isTexture && value.image instanceof Image ) {
|
|
193
|
+
|
|
194
|
+
let foundTexture = null;
|
|
195
|
+
for ( const i in textures ) {
|
|
196
|
+
|
|
197
|
+
const texture = textures[ i ];
|
|
198
|
+
if ( this.areEqual( texture, value ) ) {
|
|
199
|
+
|
|
200
|
+
foundTexture = texture;
|
|
201
|
+
break;
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if ( foundTexture ) {
|
|
208
|
+
|
|
209
|
+
material[ key ] = foundTexture;
|
|
210
|
+
|
|
211
|
+
} else {
|
|
212
|
+
|
|
213
|
+
textures.push( value );
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return material;
|
|
224
|
+
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
object.traverse( c => {
|
|
230
|
+
|
|
231
|
+
if ( c.isMesh && c.material ) {
|
|
232
|
+
|
|
233
|
+
const material = c.material;
|
|
234
|
+
if ( Array.isArray( material ) ) {
|
|
235
|
+
|
|
236
|
+
for ( let i = 0; i < material.length; i ++ ) {
|
|
237
|
+
|
|
238
|
+
material[ i ] = processMaterial( material[ i ] );
|
|
239
|
+
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
} else {
|
|
243
|
+
|
|
244
|
+
c.material = processMaterial( material );
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
} );
|
|
251
|
+
|
|
252
|
+
return { replaced, retained: materials.length };
|
|
253
|
+
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
}
|