three-gpu-pathtracer 0.0.12 → 0.0.13
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 +961 -886
- package/build/index.module.js +6850 -6481
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +6845 -6475
- package/build/index.umd.cjs.map +1 -1
- package/package.json +73 -72
- package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +346 -275
- package/src/core/PathTracingSceneGenerator.js +69 -69
- package/src/core/QuiltPathTracingRenderer.js +223 -0
- package/src/index.js +40 -39
- package/src/materials/AlphaDisplayMaterial.js +48 -48
- package/src/materials/AmbientOcclusionMaterial.js +199 -199
- package/src/materials/BlendMaterial.js +67 -67
- package/src/materials/DenoiseMaterial.js +142 -142
- package/src/materials/GraphMaterial.js +243 -243
- package/src/materials/LambertPathTracingMaterial.js +285 -285
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/PhysicalPathTracingMaterial.js +1013 -982
- 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/shaderEnvMapSampling.js +58 -58
- package/src/shader/shaderGGXFunctions.js +100 -100
- package/src/shader/shaderIridescenceFunctions.js +135 -130
- package/src/shader/shaderLayerTexelFetchFunctions.js +25 -25
- package/src/shader/shaderLightSampling.js +229 -229
- package/src/shader/shaderMaterialSampling.js +510 -506
- package/src/shader/shaderRandFunctions.js +57 -57
- package/src/shader/shaderSheenFunctions.js +98 -98
- package/src/shader/shaderSobolSampling.js +256 -256
- package/src/shader/shaderStructs.js +327 -325
- package/src/shader/shaderUtils.js +377 -361
- 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 +273 -259
- package/src/uniforms/FloatAttributeTextureArray.js +169 -169
- package/src/uniforms/IESProfilesTexture.js +100 -100
- package/src/uniforms/LightsInfoUniformStruct.js +212 -207
- package/src/uniforms/MaterialsTexture.js +426 -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/workers/PathTracingSceneWorker.js +42 -42
|
@@ -1,426 +1,426 @@
|
|
|
1
|
-
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide } from 'three';
|
|
2
|
-
import { reduceTexturesToUniqueSources, getTextureHash } from './utils.js';
|
|
3
|
-
|
|
4
|
-
const MATERIAL_PIXELS = 45;
|
|
5
|
-
const MATERIAL_STRIDE = MATERIAL_PIXELS * 4;
|
|
6
|
-
|
|
7
|
-
const MATTE_OFFSET = 14 * 4 + 0; // s14.r
|
|
8
|
-
const SHADOW_OFFSET = 14 * 4 + 1; // s14.g
|
|
9
|
-
|
|
10
|
-
export class MaterialsTexture extends DataTexture {
|
|
11
|
-
|
|
12
|
-
constructor() {
|
|
13
|
-
|
|
14
|
-
super( new Float32Array( 4 ), 1, 1 );
|
|
15
|
-
|
|
16
|
-
this.format = RGBAFormat;
|
|
17
|
-
this.type = FloatType;
|
|
18
|
-
this.wrapS = ClampToEdgeWrapping;
|
|
19
|
-
this.wrapT = ClampToEdgeWrapping;
|
|
20
|
-
this.generateMipmaps = false;
|
|
21
|
-
this.threeCompatibilityTransforms = false;
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
setCastShadow( materialIndex, cast ) {
|
|
26
|
-
|
|
27
|
-
// invert the shadow value so we default to "true" when initializing a material
|
|
28
|
-
const array = this.image.data;
|
|
29
|
-
const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
|
|
30
|
-
array[ index ] = ! cast ? 1 : 0;
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
getCastShadow( materialIndex ) {
|
|
35
|
-
|
|
36
|
-
const array = this.image.data;
|
|
37
|
-
const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
|
|
38
|
-
return ! Boolean( array[ index ] );
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
setMatte( materialIndex, matte ) {
|
|
43
|
-
|
|
44
|
-
const array = this.image.data;
|
|
45
|
-
const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
|
|
46
|
-
array[ index ] = matte ? 1 : 0;
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
getMatte( materialIndex ) {
|
|
51
|
-
|
|
52
|
-
const array = this.image.data;
|
|
53
|
-
const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
|
|
54
|
-
return Boolean( array[ index ] );
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
updateFrom( materials, textures ) {
|
|
59
|
-
|
|
60
|
-
function getTexture( material, key, def = - 1 ) {
|
|
61
|
-
|
|
62
|
-
if ( key in material && material[ key ] ) {
|
|
63
|
-
|
|
64
|
-
const hash = getTextureHash( material[ key ] );
|
|
65
|
-
return uniqueTextureLookup[ hash ];
|
|
66
|
-
|
|
67
|
-
} else {
|
|
68
|
-
|
|
69
|
-
return def;
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function getField( material, key, def ) {
|
|
76
|
-
|
|
77
|
-
return key in material ? material[ key ] : def;
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function getUVTransformTexture( material ) {
|
|
82
|
-
|
|
83
|
-
// https://github.com/mrdoob/three.js/blob/f3a832e637c98a404c64dae8174625958455e038/src/renderers/webgl/WebGLMaterials.js#L204-L306
|
|
84
|
-
// https://threejs.org/docs/#api/en/textures/Texture.offset
|
|
85
|
-
// fallback order of textures to use as a common uv transform
|
|
86
|
-
return material.map ||
|
|
87
|
-
material.specularMap ||
|
|
88
|
-
material.displacementMap ||
|
|
89
|
-
material.normalMap ||
|
|
90
|
-
material.bumpMap ||
|
|
91
|
-
material.roughnessMap ||
|
|
92
|
-
material.metalnessMap ||
|
|
93
|
-
material.alphaMap ||
|
|
94
|
-
material.emissiveMap ||
|
|
95
|
-
material.clearcoatMap ||
|
|
96
|
-
material.clearcoatNormalMap ||
|
|
97
|
-
material.clearcoatRoughnessMap ||
|
|
98
|
-
material.iridescenceMap ||
|
|
99
|
-
material.iridescenceThicknessMap ||
|
|
100
|
-
material.specularIntensityMap ||
|
|
101
|
-
material.specularColorMap ||
|
|
102
|
-
material.transmissionMap ||
|
|
103
|
-
material.thicknessMap ||
|
|
104
|
-
material.sheenColorMap ||
|
|
105
|
-
material.sheenRoughnessMap ||
|
|
106
|
-
null;
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function writeTextureMatrixToArray( material, textureKey, array, offset ) {
|
|
111
|
-
|
|
112
|
-
let texture;
|
|
113
|
-
if ( threeCompatibilityTransforms ) {
|
|
114
|
-
|
|
115
|
-
texture = getUVTransformTexture( material );
|
|
116
|
-
|
|
117
|
-
} else {
|
|
118
|
-
|
|
119
|
-
texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// check if texture exists
|
|
124
|
-
if ( texture ) {
|
|
125
|
-
|
|
126
|
-
const elements = texture.matrix.elements;
|
|
127
|
-
|
|
128
|
-
let i = 0;
|
|
129
|
-
|
|
130
|
-
// first row
|
|
131
|
-
array[ offset + i ++ ] = elements[ 0 ];
|
|
132
|
-
array[ offset + i ++ ] = elements[ 3 ];
|
|
133
|
-
array[ offset + i ++ ] = elements[ 6 ];
|
|
134
|
-
i ++;
|
|
135
|
-
|
|
136
|
-
// second row
|
|
137
|
-
array[ offset + i ++ ] = elements[ 1 ];
|
|
138
|
-
array[ offset + i ++ ] = elements[ 4 ];
|
|
139
|
-
array[ offset + i ++ ] = elements[ 7 ];
|
|
140
|
-
i ++;
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return 8;
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
let index = 0;
|
|
149
|
-
const pixelCount = materials.length * MATERIAL_PIXELS;
|
|
150
|
-
const dimension = Math.ceil( Math.sqrt( pixelCount ) );
|
|
151
|
-
const { threeCompatibilityTransforms, image } = this;
|
|
152
|
-
|
|
153
|
-
// get the list of textures with unique sources
|
|
154
|
-
const uniqueTextures = reduceTexturesToUniqueSources( textures );
|
|
155
|
-
const uniqueTextureLookup = {};
|
|
156
|
-
for ( let i = 0, l = uniqueTextures.length; i < l; i ++ ) {
|
|
157
|
-
|
|
158
|
-
uniqueTextureLookup[ getTextureHash( uniqueTextures[ i ] ) ] = i;
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if ( image.width !== dimension ) {
|
|
163
|
-
|
|
164
|
-
this.dispose();
|
|
165
|
-
|
|
166
|
-
image.data = new Float32Array( dimension * dimension * 4 );
|
|
167
|
-
image.width = dimension;
|
|
168
|
-
image.height = dimension;
|
|
169
|
-
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const floatArray = image.data;
|
|
173
|
-
|
|
174
|
-
// on some devices (Google Pixel 6) the "floatBitsToInt" function does not work correctly so we
|
|
175
|
-
// can't encode texture ids that way.
|
|
176
|
-
// const intArray = new Int32Array( floatArray.buffer );
|
|
177
|
-
|
|
178
|
-
for ( let i = 0, l = materials.length; i < l; i ++ ) {
|
|
179
|
-
|
|
180
|
-
const m = materials[ i ];
|
|
181
|
-
|
|
182
|
-
// sample 0
|
|
183
|
-
// color
|
|
184
|
-
floatArray[ index ++ ] = m.color.r;
|
|
185
|
-
floatArray[ index ++ ] = m.color.g;
|
|
186
|
-
floatArray[ index ++ ] = m.color.b;
|
|
187
|
-
floatArray[ index ++ ] = getTexture( m, 'map' );
|
|
188
|
-
|
|
189
|
-
// sample 1
|
|
190
|
-
// metalness & roughness
|
|
191
|
-
floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
|
|
192
|
-
floatArray[ index ++ ] = getTexture( m, 'metalnessMap' );
|
|
193
|
-
floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
|
|
194
|
-
floatArray[ index ++ ] = getTexture( m, 'roughnessMap' );
|
|
195
|
-
|
|
196
|
-
// sample 2
|
|
197
|
-
// transmission & emissiveIntensity
|
|
198
|
-
// three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5
|
|
199
|
-
floatArray[ index ++ ] = getField( m, 'ior', 1.5 );
|
|
200
|
-
floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
|
|
201
|
-
floatArray[ index ++ ] = getTexture( m, 'transmissionMap' );
|
|
202
|
-
floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
|
|
203
|
-
|
|
204
|
-
// sample 3
|
|
205
|
-
// emission
|
|
206
|
-
if ( 'emissive' in m ) {
|
|
207
|
-
|
|
208
|
-
floatArray[ index ++ ] = m.emissive.r;
|
|
209
|
-
floatArray[ index ++ ] = m.emissive.g;
|
|
210
|
-
floatArray[ index ++ ] = m.emissive.b;
|
|
211
|
-
|
|
212
|
-
} else {
|
|
213
|
-
|
|
214
|
-
floatArray[ index ++ ] = 0.0;
|
|
215
|
-
floatArray[ index ++ ] = 0.0;
|
|
216
|
-
floatArray[ index ++ ] = 0.0;
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
floatArray[ index ++ ] = getTexture( m, 'emissiveMap' );
|
|
221
|
-
|
|
222
|
-
// sample 4
|
|
223
|
-
// normals
|
|
224
|
-
floatArray[ index ++ ] = getTexture( m, 'normalMap' );
|
|
225
|
-
if ( 'normalScale' in m ) {
|
|
226
|
-
|
|
227
|
-
floatArray[ index ++ ] = m.normalScale.x;
|
|
228
|
-
floatArray[ index ++ ] = m.normalScale.y;
|
|
229
|
-
|
|
230
|
-
} else {
|
|
231
|
-
|
|
232
|
-
floatArray[ index ++ ] = 1;
|
|
233
|
-
floatArray[ index ++ ] = 1;
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// clearcoat
|
|
238
|
-
floatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );
|
|
239
|
-
floatArray[ index ++ ] = getTexture( m, 'clearcoatMap' ); // sample 5
|
|
240
|
-
|
|
241
|
-
floatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );
|
|
242
|
-
floatArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );
|
|
243
|
-
|
|
244
|
-
floatArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );
|
|
245
|
-
|
|
246
|
-
// sample 6
|
|
247
|
-
if ( 'clearcoatNormalScale' in m ) {
|
|
248
|
-
|
|
249
|
-
floatArray[ index ++ ] = m.clearcoatNormalScale.x;
|
|
250
|
-
floatArray[ index ++ ] = m.clearcoatNormalScale.y;
|
|
251
|
-
|
|
252
|
-
} else {
|
|
253
|
-
|
|
254
|
-
floatArray[ index ++ ] = 1;
|
|
255
|
-
floatArray[ index ++ ] = 1;
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
index ++;
|
|
260
|
-
index
|
|
261
|
-
|
|
262
|
-
// sample 7
|
|
263
|
-
// sheen
|
|
264
|
-
if ( 'sheenColor' in m ) {
|
|
265
|
-
|
|
266
|
-
floatArray[ index ++ ] = m.sheenColor.r;
|
|
267
|
-
floatArray[ index ++ ] = m.sheenColor.g;
|
|
268
|
-
floatArray[ index ++ ] = m.sheenColor.b;
|
|
269
|
-
|
|
270
|
-
} else {
|
|
271
|
-
|
|
272
|
-
floatArray[ index ++ ] = 0.0;
|
|
273
|
-
floatArray[ index ++ ] = 0.0;
|
|
274
|
-
floatArray[ index ++ ] = 0.0;
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
floatArray[ index ++ ] = getTexture( m, 'sheenColorMap' );
|
|
279
|
-
|
|
280
|
-
// sample 8
|
|
281
|
-
floatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );
|
|
282
|
-
floatArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );
|
|
283
|
-
|
|
284
|
-
// iridescence
|
|
285
|
-
floatArray[ index ++ ] = getTexture( m, 'iridescenceMap' );
|
|
286
|
-
floatArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );
|
|
287
|
-
|
|
288
|
-
floatArray[ index ++ ] = getField( m, 'iridescence', 0.0 ); // sample 9
|
|
289
|
-
floatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );
|
|
290
|
-
|
|
291
|
-
const iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );
|
|
292
|
-
floatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];
|
|
293
|
-
floatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];
|
|
294
|
-
|
|
295
|
-
// sample 10
|
|
296
|
-
// specular color
|
|
297
|
-
if ( 'specularColor' in m ) {
|
|
298
|
-
|
|
299
|
-
floatArray[ index ++ ] = m.specularColor.r;
|
|
300
|
-
floatArray[ index ++ ] = m.specularColor.g;
|
|
301
|
-
floatArray[ index ++ ] = m.specularColor.b;
|
|
302
|
-
|
|
303
|
-
} else {
|
|
304
|
-
|
|
305
|
-
floatArray[ index ++ ] = 1.0;
|
|
306
|
-
floatArray[ index ++ ] = 1.0;
|
|
307
|
-
floatArray[ index ++ ] = 1.0;
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
floatArray[ index ++ ] = getTexture( m, 'specularColorMap' );
|
|
312
|
-
|
|
313
|
-
// sample 11
|
|
314
|
-
// specular intensity
|
|
315
|
-
floatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );
|
|
316
|
-
floatArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );
|
|
317
|
-
|
|
318
|
-
// isThinFilm
|
|
319
|
-
const isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;
|
|
320
|
-
floatArray[ index ++ ] = Number( isThinFilm );
|
|
321
|
-
index ++;
|
|
322
|
-
|
|
323
|
-
// sample 12
|
|
324
|
-
if ( 'attenuationColor' in m ) {
|
|
325
|
-
|
|
326
|
-
floatArray[ index ++ ] = m.attenuationColor.r;
|
|
327
|
-
floatArray[ index ++ ] = m.attenuationColor.g;
|
|
328
|
-
floatArray[ index ++ ] = m.attenuationColor.b;
|
|
329
|
-
|
|
330
|
-
} else {
|
|
331
|
-
|
|
332
|
-
floatArray[ index ++ ] = 1.0;
|
|
333
|
-
floatArray[ index ++ ] = 1.0;
|
|
334
|
-
floatArray[ index ++ ] = 1.0;
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
floatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );
|
|
339
|
-
|
|
340
|
-
// sample 13
|
|
341
|
-
// alphaMap
|
|
342
|
-
floatArray[ index ++ ] = getTexture( m, 'alphaMap' );
|
|
343
|
-
|
|
344
|
-
// side & matte
|
|
345
|
-
floatArray[ index ++ ] = m.opacity;
|
|
346
|
-
floatArray[ index ++ ] = m.alphaTest;
|
|
347
|
-
if ( ! isThinFilm && m.transmission > 0.0 ) {
|
|
348
|
-
|
|
349
|
-
floatArray[ index ++ ] = 0;
|
|
350
|
-
|
|
351
|
-
} else {
|
|
352
|
-
|
|
353
|
-
switch ( m.side ) {
|
|
354
|
-
|
|
355
|
-
case FrontSide:
|
|
356
|
-
floatArray[ index ++ ] = 1;
|
|
357
|
-
break;
|
|
358
|
-
case BackSide:
|
|
359
|
-
floatArray[ index ++ ] = - 1;
|
|
360
|
-
break;
|
|
361
|
-
case DoubleSide:
|
|
362
|
-
floatArray[ index ++ ] = 0;
|
|
363
|
-
break;
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// sample 14
|
|
370
|
-
index ++; // matte
|
|
371
|
-
index ++; // shadow
|
|
372
|
-
floatArray[ index ++ ] = Number( m.vertexColors ) | ( Number( m.flatShading ) << 1 ); // vertexColors & flatShading
|
|
373
|
-
floatArray[ index ++ ] = Number( m.transparent ); // transparent
|
|
374
|
-
|
|
375
|
-
// map transform 15
|
|
376
|
-
index += writeTextureMatrixToArray( m, 'map', floatArray, index );
|
|
377
|
-
|
|
378
|
-
// metalnessMap transform 17
|
|
379
|
-
index += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );
|
|
380
|
-
|
|
381
|
-
// roughnessMap transform 19
|
|
382
|
-
index += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );
|
|
383
|
-
|
|
384
|
-
// transmissionMap transform 21
|
|
385
|
-
index += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );
|
|
386
|
-
|
|
387
|
-
// emissiveMap transform 22
|
|
388
|
-
index += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );
|
|
389
|
-
|
|
390
|
-
// normalMap transform 25
|
|
391
|
-
index += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );
|
|
392
|
-
|
|
393
|
-
// clearcoatMap transform 27
|
|
394
|
-
index += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );
|
|
395
|
-
|
|
396
|
-
// clearcoatNormalMap transform 29
|
|
397
|
-
index += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );
|
|
398
|
-
|
|
399
|
-
// clearcoatRoughnessMap transform 31
|
|
400
|
-
index += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );
|
|
401
|
-
|
|
402
|
-
// sheenColorMap transform 33
|
|
403
|
-
index += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );
|
|
404
|
-
|
|
405
|
-
// sheenRoughnessMap transform 35
|
|
406
|
-
index += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );
|
|
407
|
-
|
|
408
|
-
// iridescenceMap transform 37
|
|
409
|
-
index += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );
|
|
410
|
-
|
|
411
|
-
// iridescenceThicknessMap transform 39
|
|
412
|
-
index += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );
|
|
413
|
-
|
|
414
|
-
// specularColorMap transform 41
|
|
415
|
-
index += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );
|
|
416
|
-
|
|
417
|
-
// specularIntensityMap transform 43
|
|
418
|
-
index += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
this.needsUpdate = true;
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
}
|
|
1
|
+
import { DataTexture, RGBAFormat, ClampToEdgeWrapping, FloatType, FrontSide, BackSide, DoubleSide } from 'three';
|
|
2
|
+
import { reduceTexturesToUniqueSources, getTextureHash } from './utils.js';
|
|
3
|
+
|
|
4
|
+
const MATERIAL_PIXELS = 45;
|
|
5
|
+
const MATERIAL_STRIDE = MATERIAL_PIXELS * 4;
|
|
6
|
+
|
|
7
|
+
const MATTE_OFFSET = 14 * 4 + 0; // s14.r
|
|
8
|
+
const SHADOW_OFFSET = 14 * 4 + 1; // s14.g
|
|
9
|
+
|
|
10
|
+
export class MaterialsTexture extends DataTexture {
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
|
|
14
|
+
super( new Float32Array( 4 ), 1, 1 );
|
|
15
|
+
|
|
16
|
+
this.format = RGBAFormat;
|
|
17
|
+
this.type = FloatType;
|
|
18
|
+
this.wrapS = ClampToEdgeWrapping;
|
|
19
|
+
this.wrapT = ClampToEdgeWrapping;
|
|
20
|
+
this.generateMipmaps = false;
|
|
21
|
+
this.threeCompatibilityTransforms = false;
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setCastShadow( materialIndex, cast ) {
|
|
26
|
+
|
|
27
|
+
// invert the shadow value so we default to "true" when initializing a material
|
|
28
|
+
const array = this.image.data;
|
|
29
|
+
const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
|
|
30
|
+
array[ index ] = ! cast ? 1 : 0;
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getCastShadow( materialIndex ) {
|
|
35
|
+
|
|
36
|
+
const array = this.image.data;
|
|
37
|
+
const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
|
|
38
|
+
return ! Boolean( array[ index ] );
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setMatte( materialIndex, matte ) {
|
|
43
|
+
|
|
44
|
+
const array = this.image.data;
|
|
45
|
+
const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
|
|
46
|
+
array[ index ] = matte ? 1 : 0;
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getMatte( materialIndex ) {
|
|
51
|
+
|
|
52
|
+
const array = this.image.data;
|
|
53
|
+
const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
|
|
54
|
+
return Boolean( array[ index ] );
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
updateFrom( materials, textures ) {
|
|
59
|
+
|
|
60
|
+
function getTexture( material, key, def = - 1 ) {
|
|
61
|
+
|
|
62
|
+
if ( key in material && material[ key ] ) {
|
|
63
|
+
|
|
64
|
+
const hash = getTextureHash( material[ key ] );
|
|
65
|
+
return uniqueTextureLookup[ hash ];
|
|
66
|
+
|
|
67
|
+
} else {
|
|
68
|
+
|
|
69
|
+
return def;
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getField( material, key, def ) {
|
|
76
|
+
|
|
77
|
+
return key in material ? material[ key ] : def;
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getUVTransformTexture( material ) {
|
|
82
|
+
|
|
83
|
+
// https://github.com/mrdoob/three.js/blob/f3a832e637c98a404c64dae8174625958455e038/src/renderers/webgl/WebGLMaterials.js#L204-L306
|
|
84
|
+
// https://threejs.org/docs/#api/en/textures/Texture.offset
|
|
85
|
+
// fallback order of textures to use as a common uv transform
|
|
86
|
+
return material.map ||
|
|
87
|
+
material.specularMap ||
|
|
88
|
+
material.displacementMap ||
|
|
89
|
+
material.normalMap ||
|
|
90
|
+
material.bumpMap ||
|
|
91
|
+
material.roughnessMap ||
|
|
92
|
+
material.metalnessMap ||
|
|
93
|
+
material.alphaMap ||
|
|
94
|
+
material.emissiveMap ||
|
|
95
|
+
material.clearcoatMap ||
|
|
96
|
+
material.clearcoatNormalMap ||
|
|
97
|
+
material.clearcoatRoughnessMap ||
|
|
98
|
+
material.iridescenceMap ||
|
|
99
|
+
material.iridescenceThicknessMap ||
|
|
100
|
+
material.specularIntensityMap ||
|
|
101
|
+
material.specularColorMap ||
|
|
102
|
+
material.transmissionMap ||
|
|
103
|
+
material.thicknessMap ||
|
|
104
|
+
material.sheenColorMap ||
|
|
105
|
+
material.sheenRoughnessMap ||
|
|
106
|
+
null;
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function writeTextureMatrixToArray( material, textureKey, array, offset ) {
|
|
111
|
+
|
|
112
|
+
let texture;
|
|
113
|
+
if ( threeCompatibilityTransforms ) {
|
|
114
|
+
|
|
115
|
+
texture = getUVTransformTexture( material );
|
|
116
|
+
|
|
117
|
+
} else {
|
|
118
|
+
|
|
119
|
+
texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// check if texture exists
|
|
124
|
+
if ( texture ) {
|
|
125
|
+
|
|
126
|
+
const elements = texture.matrix.elements;
|
|
127
|
+
|
|
128
|
+
let i = 0;
|
|
129
|
+
|
|
130
|
+
// first row
|
|
131
|
+
array[ offset + i ++ ] = elements[ 0 ];
|
|
132
|
+
array[ offset + i ++ ] = elements[ 3 ];
|
|
133
|
+
array[ offset + i ++ ] = elements[ 6 ];
|
|
134
|
+
i ++;
|
|
135
|
+
|
|
136
|
+
// second row
|
|
137
|
+
array[ offset + i ++ ] = elements[ 1 ];
|
|
138
|
+
array[ offset + i ++ ] = elements[ 4 ];
|
|
139
|
+
array[ offset + i ++ ] = elements[ 7 ];
|
|
140
|
+
i ++;
|
|
141
|
+
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return 8;
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let index = 0;
|
|
149
|
+
const pixelCount = materials.length * MATERIAL_PIXELS;
|
|
150
|
+
const dimension = Math.ceil( Math.sqrt( pixelCount ) );
|
|
151
|
+
const { threeCompatibilityTransforms, image } = this;
|
|
152
|
+
|
|
153
|
+
// get the list of textures with unique sources
|
|
154
|
+
const uniqueTextures = reduceTexturesToUniqueSources( textures );
|
|
155
|
+
const uniqueTextureLookup = {};
|
|
156
|
+
for ( let i = 0, l = uniqueTextures.length; i < l; i ++ ) {
|
|
157
|
+
|
|
158
|
+
uniqueTextureLookup[ getTextureHash( uniqueTextures[ i ] ) ] = i;
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if ( image.width !== dimension ) {
|
|
163
|
+
|
|
164
|
+
this.dispose();
|
|
165
|
+
|
|
166
|
+
image.data = new Float32Array( dimension * dimension * 4 );
|
|
167
|
+
image.width = dimension;
|
|
168
|
+
image.height = dimension;
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const floatArray = image.data;
|
|
173
|
+
|
|
174
|
+
// on some devices (Google Pixel 6) the "floatBitsToInt" function does not work correctly so we
|
|
175
|
+
// can't encode texture ids that way.
|
|
176
|
+
// const intArray = new Int32Array( floatArray.buffer );
|
|
177
|
+
|
|
178
|
+
for ( let i = 0, l = materials.length; i < l; i ++ ) {
|
|
179
|
+
|
|
180
|
+
const m = materials[ i ];
|
|
181
|
+
|
|
182
|
+
// sample 0
|
|
183
|
+
// color
|
|
184
|
+
floatArray[ index ++ ] = m.color.r;
|
|
185
|
+
floatArray[ index ++ ] = m.color.g;
|
|
186
|
+
floatArray[ index ++ ] = m.color.b;
|
|
187
|
+
floatArray[ index ++ ] = getTexture( m, 'map' );
|
|
188
|
+
|
|
189
|
+
// sample 1
|
|
190
|
+
// metalness & roughness
|
|
191
|
+
floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
|
|
192
|
+
floatArray[ index ++ ] = getTexture( m, 'metalnessMap' );
|
|
193
|
+
floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
|
|
194
|
+
floatArray[ index ++ ] = getTexture( m, 'roughnessMap' );
|
|
195
|
+
|
|
196
|
+
// sample 2
|
|
197
|
+
// transmission & emissiveIntensity
|
|
198
|
+
// three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5
|
|
199
|
+
floatArray[ index ++ ] = getField( m, 'ior', 1.5 );
|
|
200
|
+
floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
|
|
201
|
+
floatArray[ index ++ ] = getTexture( m, 'transmissionMap' );
|
|
202
|
+
floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
|
|
203
|
+
|
|
204
|
+
// sample 3
|
|
205
|
+
// emission
|
|
206
|
+
if ( 'emissive' in m ) {
|
|
207
|
+
|
|
208
|
+
floatArray[ index ++ ] = m.emissive.r;
|
|
209
|
+
floatArray[ index ++ ] = m.emissive.g;
|
|
210
|
+
floatArray[ index ++ ] = m.emissive.b;
|
|
211
|
+
|
|
212
|
+
} else {
|
|
213
|
+
|
|
214
|
+
floatArray[ index ++ ] = 0.0;
|
|
215
|
+
floatArray[ index ++ ] = 0.0;
|
|
216
|
+
floatArray[ index ++ ] = 0.0;
|
|
217
|
+
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
floatArray[ index ++ ] = getTexture( m, 'emissiveMap' );
|
|
221
|
+
|
|
222
|
+
// sample 4
|
|
223
|
+
// normals
|
|
224
|
+
floatArray[ index ++ ] = getTexture( m, 'normalMap' );
|
|
225
|
+
if ( 'normalScale' in m ) {
|
|
226
|
+
|
|
227
|
+
floatArray[ index ++ ] = m.normalScale.x;
|
|
228
|
+
floatArray[ index ++ ] = m.normalScale.y;
|
|
229
|
+
|
|
230
|
+
} else {
|
|
231
|
+
|
|
232
|
+
floatArray[ index ++ ] = 1;
|
|
233
|
+
floatArray[ index ++ ] = 1;
|
|
234
|
+
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// clearcoat
|
|
238
|
+
floatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );
|
|
239
|
+
floatArray[ index ++ ] = getTexture( m, 'clearcoatMap' ); // sample 5
|
|
240
|
+
|
|
241
|
+
floatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );
|
|
242
|
+
floatArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );
|
|
243
|
+
|
|
244
|
+
floatArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );
|
|
245
|
+
|
|
246
|
+
// sample 6
|
|
247
|
+
if ( 'clearcoatNormalScale' in m ) {
|
|
248
|
+
|
|
249
|
+
floatArray[ index ++ ] = m.clearcoatNormalScale.x;
|
|
250
|
+
floatArray[ index ++ ] = m.clearcoatNormalScale.y;
|
|
251
|
+
|
|
252
|
+
} else {
|
|
253
|
+
|
|
254
|
+
floatArray[ index ++ ] = 1;
|
|
255
|
+
floatArray[ index ++ ] = 1;
|
|
256
|
+
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
index ++;
|
|
260
|
+
floatArray[ index ++ ] = getField( m, 'sheen', 0.0 );
|
|
261
|
+
|
|
262
|
+
// sample 7
|
|
263
|
+
// sheen
|
|
264
|
+
if ( 'sheenColor' in m ) {
|
|
265
|
+
|
|
266
|
+
floatArray[ index ++ ] = m.sheenColor.r;
|
|
267
|
+
floatArray[ index ++ ] = m.sheenColor.g;
|
|
268
|
+
floatArray[ index ++ ] = m.sheenColor.b;
|
|
269
|
+
|
|
270
|
+
} else {
|
|
271
|
+
|
|
272
|
+
floatArray[ index ++ ] = 0.0;
|
|
273
|
+
floatArray[ index ++ ] = 0.0;
|
|
274
|
+
floatArray[ index ++ ] = 0.0;
|
|
275
|
+
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
floatArray[ index ++ ] = getTexture( m, 'sheenColorMap' );
|
|
279
|
+
|
|
280
|
+
// sample 8
|
|
281
|
+
floatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );
|
|
282
|
+
floatArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );
|
|
283
|
+
|
|
284
|
+
// iridescence
|
|
285
|
+
floatArray[ index ++ ] = getTexture( m, 'iridescenceMap' );
|
|
286
|
+
floatArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );
|
|
287
|
+
|
|
288
|
+
floatArray[ index ++ ] = getField( m, 'iridescence', 0.0 ); // sample 9
|
|
289
|
+
floatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );
|
|
290
|
+
|
|
291
|
+
const iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );
|
|
292
|
+
floatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];
|
|
293
|
+
floatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];
|
|
294
|
+
|
|
295
|
+
// sample 10
|
|
296
|
+
// specular color
|
|
297
|
+
if ( 'specularColor' in m ) {
|
|
298
|
+
|
|
299
|
+
floatArray[ index ++ ] = m.specularColor.r;
|
|
300
|
+
floatArray[ index ++ ] = m.specularColor.g;
|
|
301
|
+
floatArray[ index ++ ] = m.specularColor.b;
|
|
302
|
+
|
|
303
|
+
} else {
|
|
304
|
+
|
|
305
|
+
floatArray[ index ++ ] = 1.0;
|
|
306
|
+
floatArray[ index ++ ] = 1.0;
|
|
307
|
+
floatArray[ index ++ ] = 1.0;
|
|
308
|
+
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
floatArray[ index ++ ] = getTexture( m, 'specularColorMap' );
|
|
312
|
+
|
|
313
|
+
// sample 11
|
|
314
|
+
// specular intensity
|
|
315
|
+
floatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );
|
|
316
|
+
floatArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );
|
|
317
|
+
|
|
318
|
+
// isThinFilm
|
|
319
|
+
const isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;
|
|
320
|
+
floatArray[ index ++ ] = Number( isThinFilm );
|
|
321
|
+
index ++;
|
|
322
|
+
|
|
323
|
+
// sample 12
|
|
324
|
+
if ( 'attenuationColor' in m ) {
|
|
325
|
+
|
|
326
|
+
floatArray[ index ++ ] = m.attenuationColor.r;
|
|
327
|
+
floatArray[ index ++ ] = m.attenuationColor.g;
|
|
328
|
+
floatArray[ index ++ ] = m.attenuationColor.b;
|
|
329
|
+
|
|
330
|
+
} else {
|
|
331
|
+
|
|
332
|
+
floatArray[ index ++ ] = 1.0;
|
|
333
|
+
floatArray[ index ++ ] = 1.0;
|
|
334
|
+
floatArray[ index ++ ] = 1.0;
|
|
335
|
+
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
floatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );
|
|
339
|
+
|
|
340
|
+
// sample 13
|
|
341
|
+
// alphaMap
|
|
342
|
+
floatArray[ index ++ ] = getTexture( m, 'alphaMap' );
|
|
343
|
+
|
|
344
|
+
// side & matte
|
|
345
|
+
floatArray[ index ++ ] = m.opacity;
|
|
346
|
+
floatArray[ index ++ ] = m.alphaTest;
|
|
347
|
+
if ( ! isThinFilm && m.transmission > 0.0 ) {
|
|
348
|
+
|
|
349
|
+
floatArray[ index ++ ] = 0;
|
|
350
|
+
|
|
351
|
+
} else {
|
|
352
|
+
|
|
353
|
+
switch ( m.side ) {
|
|
354
|
+
|
|
355
|
+
case FrontSide:
|
|
356
|
+
floatArray[ index ++ ] = 1;
|
|
357
|
+
break;
|
|
358
|
+
case BackSide:
|
|
359
|
+
floatArray[ index ++ ] = - 1;
|
|
360
|
+
break;
|
|
361
|
+
case DoubleSide:
|
|
362
|
+
floatArray[ index ++ ] = 0;
|
|
363
|
+
break;
|
|
364
|
+
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// sample 14
|
|
370
|
+
index ++; // matte
|
|
371
|
+
index ++; // shadow
|
|
372
|
+
floatArray[ index ++ ] = Number( m.vertexColors ) | ( Number( m.flatShading ) << 1 ); // vertexColors & flatShading
|
|
373
|
+
floatArray[ index ++ ] = Number( m.transparent ); // transparent
|
|
374
|
+
|
|
375
|
+
// map transform 15
|
|
376
|
+
index += writeTextureMatrixToArray( m, 'map', floatArray, index );
|
|
377
|
+
|
|
378
|
+
// metalnessMap transform 17
|
|
379
|
+
index += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );
|
|
380
|
+
|
|
381
|
+
// roughnessMap transform 19
|
|
382
|
+
index += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );
|
|
383
|
+
|
|
384
|
+
// transmissionMap transform 21
|
|
385
|
+
index += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );
|
|
386
|
+
|
|
387
|
+
// emissiveMap transform 22
|
|
388
|
+
index += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );
|
|
389
|
+
|
|
390
|
+
// normalMap transform 25
|
|
391
|
+
index += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );
|
|
392
|
+
|
|
393
|
+
// clearcoatMap transform 27
|
|
394
|
+
index += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );
|
|
395
|
+
|
|
396
|
+
// clearcoatNormalMap transform 29
|
|
397
|
+
index += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );
|
|
398
|
+
|
|
399
|
+
// clearcoatRoughnessMap transform 31
|
|
400
|
+
index += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );
|
|
401
|
+
|
|
402
|
+
// sheenColorMap transform 33
|
|
403
|
+
index += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );
|
|
404
|
+
|
|
405
|
+
// sheenRoughnessMap transform 35
|
|
406
|
+
index += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );
|
|
407
|
+
|
|
408
|
+
// iridescenceMap transform 37
|
|
409
|
+
index += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );
|
|
410
|
+
|
|
411
|
+
// iridescenceThicknessMap transform 39
|
|
412
|
+
index += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );
|
|
413
|
+
|
|
414
|
+
// specularColorMap transform 41
|
|
415
|
+
index += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );
|
|
416
|
+
|
|
417
|
+
// specularIntensityMap transform 43
|
|
418
|
+
index += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );
|
|
419
|
+
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
this.needsUpdate = true;
|
|
423
|
+
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
}
|