three-gpu-pathtracer 0.0.14 → 0.0.16

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.
Files changed (76) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1004 -981
  3. package/build/index.module.js +7413 -6902
  4. package/build/index.module.js.map +1 -1
  5. package/build/index.umd.cjs +7446 -6933
  6. package/build/index.umd.cjs.map +1 -1
  7. package/package.json +73 -73
  8. package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
  9. package/src/core/MaterialReducer.js +256 -256
  10. package/src/core/PathTracingRenderer.js +346 -346
  11. package/src/core/PathTracingSceneGenerator.js +69 -69
  12. package/src/core/QuiltPathTracingRenderer.js +223 -223
  13. package/src/detectors/CompatibilityDetector.js +38 -0
  14. package/src/detectors/MaterialCompileDetector.js +50 -0
  15. package/src/detectors/PrecisionDetector.js +85 -0
  16. package/src/detectors/PrecisionMaterial.js +160 -0
  17. package/src/index.js +40 -36
  18. package/src/materials/MaterialBase.js +56 -56
  19. package/src/materials/debug/GraphMaterial.js +243 -243
  20. package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
  21. package/src/materials/fullscreen/BlendMaterial.js +67 -67
  22. package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
  23. package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
  24. package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
  25. package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
  26. package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
  27. package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
  28. package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
  29. package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
  30. package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
  31. package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
  32. package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
  33. package/src/materials/surface/FogVolumeMaterial.js +23 -23
  34. package/src/objects/EquirectCamera.js +13 -13
  35. package/src/objects/PhysicalCamera.js +42 -28
  36. package/src/objects/PhysicalSpotLight.js +25 -14
  37. package/src/objects/ShapedAreaLight.js +22 -12
  38. package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
  39. package/src/shader/bsdf/fog.glsl.js +22 -23
  40. package/src/shader/bsdf/ggx.glsl.js +102 -102
  41. package/src/shader/bsdf/iridescence.glsl.js +135 -135
  42. package/src/shader/bsdf/sheen.glsl.js +98 -98
  43. package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
  44. package/src/shader/common/bvhAnyHit.glsl.js +76 -76
  45. package/src/shader/common/fresnel.glsl.js +98 -98
  46. package/src/shader/common/intersectShapes.glsl.js +62 -62
  47. package/src/shader/common/math.glsl.js +81 -81
  48. package/src/shader/common/utils.glsl.js +116 -116
  49. package/src/shader/rand/pcg.glsl.js +57 -57
  50. package/src/shader/rand/sobol.glsl.js +256 -256
  51. package/src/shader/sampling/equirectSampling.glsl.js +62 -62
  52. package/src/shader/sampling/lightSampling.glsl.js +223 -223
  53. package/src/shader/sampling/shapeSampling.glsl.js +86 -86
  54. package/src/shader/structs/cameraStruct.glsl.js +13 -13
  55. package/src/shader/structs/equirectStruct.glsl.js +13 -14
  56. package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
  57. package/src/shader/structs/lightsStruct.glsl.js +78 -78
  58. package/src/shader/structs/materialStruct.glsl.js +207 -207
  59. package/src/textures/GradientEquirectTexture.js +35 -35
  60. package/src/textures/ProceduralEquirectTexture.js +75 -75
  61. package/src/uniforms/AttributesTextureArray.js +35 -35
  62. package/src/uniforms/EquirectHdrInfoUniform.js +269 -277
  63. package/src/uniforms/FloatAttributeTextureArray.js +169 -169
  64. package/src/uniforms/IESProfilesTexture.js +100 -100
  65. package/src/uniforms/LightsInfoUniformStruct.js +212 -212
  66. package/src/uniforms/MaterialsTexture.js +503 -503
  67. package/src/uniforms/PhysicalCameraUniform.js +36 -36
  68. package/src/uniforms/RenderTarget2DArray.js +97 -97
  69. package/src/uniforms/utils.js +30 -30
  70. package/src/utils/BlurredEnvMapGenerator.js +116 -116
  71. package/src/utils/GeometryPreparationUtils.js +214 -214
  72. package/src/utils/IESLoader.js +325 -325
  73. package/src/utils/SobolNumberMapGenerator.js +80 -80
  74. package/src/utils/UVUnwrapper.js +101 -101
  75. package/src/utils/macroify.js +9 -9
  76. package/src/workers/PathTracingSceneWorker.js +42 -42
@@ -1,503 +1,503 @@
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
- class MaterialFeatures {
11
-
12
- constructor() {
13
-
14
- this._features = {};
15
-
16
- }
17
-
18
- isUsed( feature ) {
19
-
20
- return feature in this._features;
21
-
22
- }
23
-
24
- setUsed( feature, used = true ) {
25
-
26
- if ( used === false ) {
27
-
28
- delete this._features[ feature ];
29
-
30
- } else {
31
-
32
- this._features[ feature ] = true;
33
-
34
- }
35
-
36
- }
37
-
38
- reset() {
39
-
40
- this._features = {};
41
-
42
- }
43
-
44
- }
45
-
46
- export class MaterialsTexture extends DataTexture {
47
-
48
- constructor() {
49
-
50
- super( new Float32Array( 4 ), 1, 1 );
51
-
52
- this.format = RGBAFormat;
53
- this.type = FloatType;
54
- this.wrapS = ClampToEdgeWrapping;
55
- this.wrapT = ClampToEdgeWrapping;
56
- this.generateMipmaps = false;
57
- this.threeCompatibilityTransforms = false;
58
- this.features = new MaterialFeatures();
59
-
60
- }
61
-
62
- setCastShadow( materialIndex, cast ) {
63
-
64
- // invert the shadow value so we default to "true" when initializing a material
65
- const array = this.image.data;
66
- const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
67
- array[ index ] = ! cast ? 1 : 0;
68
-
69
- }
70
-
71
- getCastShadow( materialIndex ) {
72
-
73
- const array = this.image.data;
74
- const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
75
- return ! Boolean( array[ index ] );
76
-
77
- }
78
-
79
- setMatte( materialIndex, matte ) {
80
-
81
- const array = this.image.data;
82
- const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
83
- array[ index ] = matte ? 1 : 0;
84
-
85
- }
86
-
87
- getMatte( materialIndex ) {
88
-
89
- const array = this.image.data;
90
- const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
91
- return Boolean( array[ index ] );
92
-
93
- }
94
-
95
- updateFrom( materials, textures ) {
96
-
97
- function getTexture( material, key, def = - 1 ) {
98
-
99
- if ( key in material && material[ key ] ) {
100
-
101
- const hash = getTextureHash( material[ key ] );
102
- return uniqueTextureLookup[ hash ];
103
-
104
- } else {
105
-
106
- return def;
107
-
108
- }
109
-
110
- }
111
-
112
- function getField( material, key, def ) {
113
-
114
- return key in material ? material[ key ] : def;
115
-
116
- }
117
-
118
- function getUVTransformTexture( material ) {
119
-
120
- // https://github.com/mrdoob/three.js/blob/f3a832e637c98a404c64dae8174625958455e038/src/renderers/webgl/WebGLMaterials.js#L204-L306
121
- // https://threejs.org/docs/#api/en/textures/Texture.offset
122
- // fallback order of textures to use as a common uv transform
123
- return material.map ||
124
- material.specularMap ||
125
- material.displacementMap ||
126
- material.normalMap ||
127
- material.bumpMap ||
128
- material.roughnessMap ||
129
- material.metalnessMap ||
130
- material.alphaMap ||
131
- material.emissiveMap ||
132
- material.clearcoatMap ||
133
- material.clearcoatNormalMap ||
134
- material.clearcoatRoughnessMap ||
135
- material.iridescenceMap ||
136
- material.iridescenceThicknessMap ||
137
- material.specularIntensityMap ||
138
- material.specularColorMap ||
139
- material.transmissionMap ||
140
- material.thicknessMap ||
141
- material.sheenColorMap ||
142
- material.sheenRoughnessMap ||
143
- null;
144
-
145
- }
146
-
147
- function writeTextureMatrixToArray( material, textureKey, array, offset ) {
148
-
149
- let texture;
150
- if ( threeCompatibilityTransforms ) {
151
-
152
- texture = getUVTransformTexture( material );
153
-
154
- } else {
155
-
156
- texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;
157
-
158
- }
159
-
160
- // check if texture exists
161
- if ( texture ) {
162
-
163
- const elements = texture.matrix.elements;
164
-
165
- let i = 0;
166
-
167
- // first row
168
- array[ offset + i ++ ] = elements[ 0 ];
169
- array[ offset + i ++ ] = elements[ 3 ];
170
- array[ offset + i ++ ] = elements[ 6 ];
171
- i ++;
172
-
173
- // second row
174
- array[ offset + i ++ ] = elements[ 1 ];
175
- array[ offset + i ++ ] = elements[ 4 ];
176
- array[ offset + i ++ ] = elements[ 7 ];
177
- i ++;
178
-
179
- }
180
-
181
- return 8;
182
-
183
- }
184
-
185
- let index = 0;
186
- const pixelCount = materials.length * MATERIAL_PIXELS;
187
- const dimension = Math.ceil( Math.sqrt( pixelCount ) );
188
- const { threeCompatibilityTransforms, image, features } = this;
189
-
190
- // get the list of textures with unique sources
191
- const uniqueTextures = reduceTexturesToUniqueSources( textures );
192
- const uniqueTextureLookup = {};
193
- for ( let i = 0, l = uniqueTextures.length; i < l; i ++ ) {
194
-
195
- uniqueTextureLookup[ getTextureHash( uniqueTextures[ i ] ) ] = i;
196
-
197
- }
198
-
199
- if ( image.width !== dimension ) {
200
-
201
- this.dispose();
202
-
203
- image.data = new Float32Array( dimension * dimension * 4 );
204
- image.width = dimension;
205
- image.height = dimension;
206
-
207
- }
208
-
209
- const floatArray = image.data;
210
-
211
- // on some devices (Google Pixel 6) the "floatBitsToInt" function does not work correctly so we
212
- // can't encode texture ids that way.
213
- // const intArray = new Int32Array( floatArray.buffer );
214
-
215
- features.reset();
216
- for ( let i = 0, l = materials.length; i < l; i ++ ) {
217
-
218
- const m = materials[ i ];
219
-
220
- if ( m.isFogVolumeMaterial ) {
221
-
222
- features.setUsed( 'FOG' );
223
-
224
- for ( let j = 0; j < MATERIAL_STRIDE; j ++ ) {
225
-
226
- floatArray[ index + j ] = 0;
227
-
228
- }
229
-
230
- // sample 0 .rgb
231
- floatArray[ index + 0 * 4 + 0 ] = m.color.r;
232
- floatArray[ index + 0 * 4 + 1 ] = m.color.g;
233
- floatArray[ index + 0 * 4 + 2 ] = m.color.b;
234
-
235
- // sample 2 .a
236
- floatArray[ index + 2 * 4 + 3 ] = getField( m, 'emissiveIntensity', 0.0 );
237
-
238
- // sample 3 .rgb
239
- floatArray[ index + 3 * 4 + 0 ] = m.emissive.r;
240
- floatArray[ index + 3 * 4 + 1 ] = m.emissive.g;
241
- floatArray[ index + 3 * 4 + 2 ] = m.emissive.b;
242
-
243
- // sample 13 .g
244
- // reusing opacity field
245
- floatArray[ index + 13 * 4 + 1 ] = m.density;
246
-
247
- // side
248
- floatArray[ index + 13 * 4 + 3 ] = 0.0;
249
-
250
- // sample 14 .b
251
- floatArray[ index + 14 * 4 + 2 ] = 1 << 2;
252
-
253
- index += MATERIAL_STRIDE;
254
- continue;
255
-
256
- }
257
-
258
- // sample 0
259
- // color
260
- floatArray[ index ++ ] = m.color.r;
261
- floatArray[ index ++ ] = m.color.g;
262
- floatArray[ index ++ ] = m.color.b;
263
- floatArray[ index ++ ] = getTexture( m, 'map' );
264
-
265
- // sample 1
266
- // metalness & roughness
267
- floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
268
- floatArray[ index ++ ] = getTexture( m, 'metalnessMap' );
269
- floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
270
- floatArray[ index ++ ] = getTexture( m, 'roughnessMap' );
271
-
272
- // sample 2
273
- // transmission & emissiveIntensity
274
- // three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5
275
- floatArray[ index ++ ] = getField( m, 'ior', 1.5 );
276
- floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
277
- floatArray[ index ++ ] = getTexture( m, 'transmissionMap' );
278
- floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
279
-
280
- // sample 3
281
- // emission
282
- if ( 'emissive' in m ) {
283
-
284
- floatArray[ index ++ ] = m.emissive.r;
285
- floatArray[ index ++ ] = m.emissive.g;
286
- floatArray[ index ++ ] = m.emissive.b;
287
-
288
- } else {
289
-
290
- floatArray[ index ++ ] = 0.0;
291
- floatArray[ index ++ ] = 0.0;
292
- floatArray[ index ++ ] = 0.0;
293
-
294
- }
295
-
296
- floatArray[ index ++ ] = getTexture( m, 'emissiveMap' );
297
-
298
- // sample 4
299
- // normals
300
- floatArray[ index ++ ] = getTexture( m, 'normalMap' );
301
- if ( 'normalScale' in m ) {
302
-
303
- floatArray[ index ++ ] = m.normalScale.x;
304
- floatArray[ index ++ ] = m.normalScale.y;
305
-
306
- } else {
307
-
308
- floatArray[ index ++ ] = 1;
309
- floatArray[ index ++ ] = 1;
310
-
311
- }
312
-
313
- // clearcoat
314
- floatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );
315
- floatArray[ index ++ ] = getTexture( m, 'clearcoatMap' ); // sample 5
316
-
317
- floatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );
318
- floatArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );
319
-
320
- floatArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );
321
-
322
- // sample 6
323
- if ( 'clearcoatNormalScale' in m ) {
324
-
325
- floatArray[ index ++ ] = m.clearcoatNormalScale.x;
326
- floatArray[ index ++ ] = m.clearcoatNormalScale.y;
327
-
328
- } else {
329
-
330
- floatArray[ index ++ ] = 1;
331
- floatArray[ index ++ ] = 1;
332
-
333
- }
334
-
335
- index ++;
336
- floatArray[ index ++ ] = getField( m, 'sheen', 0.0 );
337
-
338
- // sample 7
339
- // sheen
340
- if ( 'sheenColor' in m ) {
341
-
342
- floatArray[ index ++ ] = m.sheenColor.r;
343
- floatArray[ index ++ ] = m.sheenColor.g;
344
- floatArray[ index ++ ] = m.sheenColor.b;
345
-
346
- } else {
347
-
348
- floatArray[ index ++ ] = 0.0;
349
- floatArray[ index ++ ] = 0.0;
350
- floatArray[ index ++ ] = 0.0;
351
-
352
- }
353
-
354
- floatArray[ index ++ ] = getTexture( m, 'sheenColorMap' );
355
-
356
- // sample 8
357
- floatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );
358
- floatArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );
359
-
360
- // iridescence
361
- floatArray[ index ++ ] = getTexture( m, 'iridescenceMap' );
362
- floatArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );
363
-
364
- // sample 9
365
- floatArray[ index ++ ] = getField( m, 'iridescence', 0.0 );
366
- floatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );
367
-
368
- const iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );
369
- floatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];
370
- floatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];
371
-
372
- // sample 10
373
- // specular color
374
- if ( 'specularColor' in m ) {
375
-
376
- floatArray[ index ++ ] = m.specularColor.r;
377
- floatArray[ index ++ ] = m.specularColor.g;
378
- floatArray[ index ++ ] = m.specularColor.b;
379
-
380
- } else {
381
-
382
- floatArray[ index ++ ] = 1.0;
383
- floatArray[ index ++ ] = 1.0;
384
- floatArray[ index ++ ] = 1.0;
385
-
386
- }
387
-
388
- floatArray[ index ++ ] = getTexture( m, 'specularColorMap' );
389
-
390
- // sample 11
391
- // specular intensity
392
- floatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );
393
- floatArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );
394
-
395
- // isThinFilm
396
- const isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;
397
- floatArray[ index ++ ] = Number( isThinFilm );
398
- index ++;
399
-
400
- // sample 12
401
- if ( 'attenuationColor' in m ) {
402
-
403
- floatArray[ index ++ ] = m.attenuationColor.r;
404
- floatArray[ index ++ ] = m.attenuationColor.g;
405
- floatArray[ index ++ ] = m.attenuationColor.b;
406
-
407
- } else {
408
-
409
- floatArray[ index ++ ] = 1.0;
410
- floatArray[ index ++ ] = 1.0;
411
- floatArray[ index ++ ] = 1.0;
412
-
413
- }
414
-
415
- floatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );
416
-
417
- // sample 13
418
- // alphaMap
419
- floatArray[ index ++ ] = getTexture( m, 'alphaMap' );
420
-
421
- // side & matte
422
- floatArray[ index ++ ] = m.opacity;
423
- floatArray[ index ++ ] = m.alphaTest;
424
- if ( ! isThinFilm && m.transmission > 0.0 ) {
425
-
426
- floatArray[ index ++ ] = 0;
427
-
428
- } else {
429
-
430
- switch ( m.side ) {
431
-
432
- case FrontSide:
433
- floatArray[ index ++ ] = 1;
434
- break;
435
- case BackSide:
436
- floatArray[ index ++ ] = - 1;
437
- break;
438
- case DoubleSide:
439
- floatArray[ index ++ ] = 0;
440
- break;
441
-
442
- }
443
-
444
- }
445
-
446
- // sample 14
447
- index ++; // matte
448
- index ++; // shadow
449
- floatArray[ index ++ ] = Number( m.vertexColors ) | ( Number( m.flatShading ) << 1 ); // vertexColors & flatShading
450
- floatArray[ index ++ ] = Number( m.transparent ); // transparent
451
-
452
- // map transform 15
453
- index += writeTextureMatrixToArray( m, 'map', floatArray, index );
454
-
455
- // metalnessMap transform 17
456
- index += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );
457
-
458
- // roughnessMap transform 19
459
- index += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );
460
-
461
- // transmissionMap transform 21
462
- index += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );
463
-
464
- // emissiveMap transform 22
465
- index += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );
466
-
467
- // normalMap transform 25
468
- index += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );
469
-
470
- // clearcoatMap transform 27
471
- index += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );
472
-
473
- // clearcoatNormalMap transform 29
474
- index += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );
475
-
476
- // clearcoatRoughnessMap transform 31
477
- index += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );
478
-
479
- // sheenColorMap transform 33
480
- index += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );
481
-
482
- // sheenRoughnessMap transform 35
483
- index += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );
484
-
485
- // iridescenceMap transform 37
486
- index += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );
487
-
488
- // iridescenceThicknessMap transform 39
489
- index += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );
490
-
491
- // specularColorMap transform 41
492
- index += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );
493
-
494
- // specularIntensityMap transform 43
495
- index += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );
496
-
497
- }
498
-
499
- this.needsUpdate = true;
500
-
501
- }
502
-
503
- }
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
+ class MaterialFeatures {
11
+
12
+ constructor() {
13
+
14
+ this._features = {};
15
+
16
+ }
17
+
18
+ isUsed( feature ) {
19
+
20
+ return feature in this._features;
21
+
22
+ }
23
+
24
+ setUsed( feature, used = true ) {
25
+
26
+ if ( used === false ) {
27
+
28
+ delete this._features[ feature ];
29
+
30
+ } else {
31
+
32
+ this._features[ feature ] = true;
33
+
34
+ }
35
+
36
+ }
37
+
38
+ reset() {
39
+
40
+ this._features = {};
41
+
42
+ }
43
+
44
+ }
45
+
46
+ export class MaterialsTexture extends DataTexture {
47
+
48
+ constructor() {
49
+
50
+ super( new Float32Array( 4 ), 1, 1 );
51
+
52
+ this.format = RGBAFormat;
53
+ this.type = FloatType;
54
+ this.wrapS = ClampToEdgeWrapping;
55
+ this.wrapT = ClampToEdgeWrapping;
56
+ this.generateMipmaps = false;
57
+ this.threeCompatibilityTransforms = false;
58
+ this.features = new MaterialFeatures();
59
+
60
+ }
61
+
62
+ setCastShadow( materialIndex, cast ) {
63
+
64
+ // invert the shadow value so we default to "true" when initializing a material
65
+ const array = this.image.data;
66
+ const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
67
+ array[ index ] = ! cast ? 1 : 0;
68
+
69
+ }
70
+
71
+ getCastShadow( materialIndex ) {
72
+
73
+ const array = this.image.data;
74
+ const index = materialIndex * MATERIAL_STRIDE + SHADOW_OFFSET;
75
+ return ! Boolean( array[ index ] );
76
+
77
+ }
78
+
79
+ setMatte( materialIndex, matte ) {
80
+
81
+ const array = this.image.data;
82
+ const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
83
+ array[ index ] = matte ? 1 : 0;
84
+
85
+ }
86
+
87
+ getMatte( materialIndex ) {
88
+
89
+ const array = this.image.data;
90
+ const index = materialIndex * MATERIAL_STRIDE + MATTE_OFFSET;
91
+ return Boolean( array[ index ] );
92
+
93
+ }
94
+
95
+ updateFrom( materials, textures ) {
96
+
97
+ function getTexture( material, key, def = - 1 ) {
98
+
99
+ if ( key in material && material[ key ] ) {
100
+
101
+ const hash = getTextureHash( material[ key ] );
102
+ return uniqueTextureLookup[ hash ];
103
+
104
+ } else {
105
+
106
+ return def;
107
+
108
+ }
109
+
110
+ }
111
+
112
+ function getField( material, key, def ) {
113
+
114
+ return key in material ? material[ key ] : def;
115
+
116
+ }
117
+
118
+ function getUVTransformTexture( material ) {
119
+
120
+ // https://github.com/mrdoob/three.js/blob/f3a832e637c98a404c64dae8174625958455e038/src/renderers/webgl/WebGLMaterials.js#L204-L306
121
+ // https://threejs.org/docs/#api/en/textures/Texture.offset
122
+ // fallback order of textures to use as a common uv transform
123
+ return material.map ||
124
+ material.specularMap ||
125
+ material.displacementMap ||
126
+ material.normalMap ||
127
+ material.bumpMap ||
128
+ material.roughnessMap ||
129
+ material.metalnessMap ||
130
+ material.alphaMap ||
131
+ material.emissiveMap ||
132
+ material.clearcoatMap ||
133
+ material.clearcoatNormalMap ||
134
+ material.clearcoatRoughnessMap ||
135
+ material.iridescenceMap ||
136
+ material.iridescenceThicknessMap ||
137
+ material.specularIntensityMap ||
138
+ material.specularColorMap ||
139
+ material.transmissionMap ||
140
+ material.thicknessMap ||
141
+ material.sheenColorMap ||
142
+ material.sheenRoughnessMap ||
143
+ null;
144
+
145
+ }
146
+
147
+ function writeTextureMatrixToArray( material, textureKey, array, offset ) {
148
+
149
+ let texture;
150
+ if ( threeCompatibilityTransforms ) {
151
+
152
+ texture = getUVTransformTexture( material );
153
+
154
+ } else {
155
+
156
+ texture = material[ textureKey ] && material[ textureKey ].isTexture ? material[ textureKey ] : null;
157
+
158
+ }
159
+
160
+ // check if texture exists
161
+ if ( texture ) {
162
+
163
+ const elements = texture.matrix.elements;
164
+
165
+ let i = 0;
166
+
167
+ // first row
168
+ array[ offset + i ++ ] = elements[ 0 ];
169
+ array[ offset + i ++ ] = elements[ 3 ];
170
+ array[ offset + i ++ ] = elements[ 6 ];
171
+ i ++;
172
+
173
+ // second row
174
+ array[ offset + i ++ ] = elements[ 1 ];
175
+ array[ offset + i ++ ] = elements[ 4 ];
176
+ array[ offset + i ++ ] = elements[ 7 ];
177
+ i ++;
178
+
179
+ }
180
+
181
+ return 8;
182
+
183
+ }
184
+
185
+ let index = 0;
186
+ const pixelCount = materials.length * MATERIAL_PIXELS;
187
+ const dimension = Math.ceil( Math.sqrt( pixelCount ) );
188
+ const { threeCompatibilityTransforms, image, features } = this;
189
+
190
+ // get the list of textures with unique sources
191
+ const uniqueTextures = reduceTexturesToUniqueSources( textures );
192
+ const uniqueTextureLookup = {};
193
+ for ( let i = 0, l = uniqueTextures.length; i < l; i ++ ) {
194
+
195
+ uniqueTextureLookup[ getTextureHash( uniqueTextures[ i ] ) ] = i;
196
+
197
+ }
198
+
199
+ if ( image.width !== dimension ) {
200
+
201
+ this.dispose();
202
+
203
+ image.data = new Float32Array( dimension * dimension * 4 );
204
+ image.width = dimension;
205
+ image.height = dimension;
206
+
207
+ }
208
+
209
+ const floatArray = image.data;
210
+
211
+ // on some devices (Google Pixel 6) the "floatBitsToInt" function does not work correctly so we
212
+ // can't encode texture ids that way.
213
+ // const intArray = new Int32Array( floatArray.buffer );
214
+
215
+ features.reset();
216
+ for ( let i = 0, l = materials.length; i < l; i ++ ) {
217
+
218
+ const m = materials[ i ];
219
+
220
+ if ( m.isFogVolumeMaterial ) {
221
+
222
+ features.setUsed( 'FOG' );
223
+
224
+ for ( let j = 0; j < MATERIAL_STRIDE; j ++ ) {
225
+
226
+ floatArray[ index + j ] = 0;
227
+
228
+ }
229
+
230
+ // sample 0 .rgb
231
+ floatArray[ index + 0 * 4 + 0 ] = m.color.r;
232
+ floatArray[ index + 0 * 4 + 1 ] = m.color.g;
233
+ floatArray[ index + 0 * 4 + 2 ] = m.color.b;
234
+
235
+ // sample 2 .a
236
+ floatArray[ index + 2 * 4 + 3 ] = getField( m, 'emissiveIntensity', 0.0 );
237
+
238
+ // sample 3 .rgb
239
+ floatArray[ index + 3 * 4 + 0 ] = m.emissive.r;
240
+ floatArray[ index + 3 * 4 + 1 ] = m.emissive.g;
241
+ floatArray[ index + 3 * 4 + 2 ] = m.emissive.b;
242
+
243
+ // sample 13 .g
244
+ // reusing opacity field
245
+ floatArray[ index + 13 * 4 + 1 ] = m.density;
246
+
247
+ // side
248
+ floatArray[ index + 13 * 4 + 3 ] = 0.0;
249
+
250
+ // sample 14 .b
251
+ floatArray[ index + 14 * 4 + 2 ] = 1 << 2;
252
+
253
+ index += MATERIAL_STRIDE;
254
+ continue;
255
+
256
+ }
257
+
258
+ // sample 0
259
+ // color
260
+ floatArray[ index ++ ] = m.color.r;
261
+ floatArray[ index ++ ] = m.color.g;
262
+ floatArray[ index ++ ] = m.color.b;
263
+ floatArray[ index ++ ] = getTexture( m, 'map' );
264
+
265
+ // sample 1
266
+ // metalness & roughness
267
+ floatArray[ index ++ ] = getField( m, 'metalness', 0.0 );
268
+ floatArray[ index ++ ] = getTexture( m, 'metalnessMap' );
269
+ floatArray[ index ++ ] = getField( m, 'roughness', 0.0 );
270
+ floatArray[ index ++ ] = getTexture( m, 'roughnessMap' );
271
+
272
+ // sample 2
273
+ // transmission & emissiveIntensity
274
+ // three.js assumes a default f0 of 0.04 if no ior is provided which equates to an ior of 1.5
275
+ floatArray[ index ++ ] = getField( m, 'ior', 1.5 );
276
+ floatArray[ index ++ ] = getField( m, 'transmission', 0.0 );
277
+ floatArray[ index ++ ] = getTexture( m, 'transmissionMap' );
278
+ floatArray[ index ++ ] = getField( m, 'emissiveIntensity', 0.0 );
279
+
280
+ // sample 3
281
+ // emission
282
+ if ( 'emissive' in m ) {
283
+
284
+ floatArray[ index ++ ] = m.emissive.r;
285
+ floatArray[ index ++ ] = m.emissive.g;
286
+ floatArray[ index ++ ] = m.emissive.b;
287
+
288
+ } else {
289
+
290
+ floatArray[ index ++ ] = 0.0;
291
+ floatArray[ index ++ ] = 0.0;
292
+ floatArray[ index ++ ] = 0.0;
293
+
294
+ }
295
+
296
+ floatArray[ index ++ ] = getTexture( m, 'emissiveMap' );
297
+
298
+ // sample 4
299
+ // normals
300
+ floatArray[ index ++ ] = getTexture( m, 'normalMap' );
301
+ if ( 'normalScale' in m ) {
302
+
303
+ floatArray[ index ++ ] = m.normalScale.x;
304
+ floatArray[ index ++ ] = m.normalScale.y;
305
+
306
+ } else {
307
+
308
+ floatArray[ index ++ ] = 1;
309
+ floatArray[ index ++ ] = 1;
310
+
311
+ }
312
+
313
+ // clearcoat
314
+ floatArray[ index ++ ] = getField( m, 'clearcoat', 0.0 );
315
+ floatArray[ index ++ ] = getTexture( m, 'clearcoatMap' ); // sample 5
316
+
317
+ floatArray[ index ++ ] = getField( m, 'clearcoatRoughness', 0.0 );
318
+ floatArray[ index ++ ] = getTexture( m, 'clearcoatRoughnessMap' );
319
+
320
+ floatArray[ index ++ ] = getTexture( m, 'clearcoatNormalMap' );
321
+
322
+ // sample 6
323
+ if ( 'clearcoatNormalScale' in m ) {
324
+
325
+ floatArray[ index ++ ] = m.clearcoatNormalScale.x;
326
+ floatArray[ index ++ ] = m.clearcoatNormalScale.y;
327
+
328
+ } else {
329
+
330
+ floatArray[ index ++ ] = 1;
331
+ floatArray[ index ++ ] = 1;
332
+
333
+ }
334
+
335
+ index ++;
336
+ floatArray[ index ++ ] = getField( m, 'sheen', 0.0 );
337
+
338
+ // sample 7
339
+ // sheen
340
+ if ( 'sheenColor' in m ) {
341
+
342
+ floatArray[ index ++ ] = m.sheenColor.r;
343
+ floatArray[ index ++ ] = m.sheenColor.g;
344
+ floatArray[ index ++ ] = m.sheenColor.b;
345
+
346
+ } else {
347
+
348
+ floatArray[ index ++ ] = 0.0;
349
+ floatArray[ index ++ ] = 0.0;
350
+ floatArray[ index ++ ] = 0.0;
351
+
352
+ }
353
+
354
+ floatArray[ index ++ ] = getTexture( m, 'sheenColorMap' );
355
+
356
+ // sample 8
357
+ floatArray[ index ++ ] = getField( m, 'sheenRoughness', 0.0 );
358
+ floatArray[ index ++ ] = getTexture( m, 'sheenRoughnessMap' );
359
+
360
+ // iridescence
361
+ floatArray[ index ++ ] = getTexture( m, 'iridescenceMap' );
362
+ floatArray[ index ++ ] = getTexture( m, 'iridescenceThicknessMap' );
363
+
364
+ // sample 9
365
+ floatArray[ index ++ ] = getField( m, 'iridescence', 0.0 );
366
+ floatArray[ index ++ ] = getField( m, 'iridescenceIOR', 1.3 );
367
+
368
+ const iridescenceThicknessRange = getField( m, 'iridescenceThicknessRange', [ 100, 400 ] );
369
+ floatArray[ index ++ ] = iridescenceThicknessRange[ 0 ];
370
+ floatArray[ index ++ ] = iridescenceThicknessRange[ 1 ];
371
+
372
+ // sample 10
373
+ // specular color
374
+ if ( 'specularColor' in m ) {
375
+
376
+ floatArray[ index ++ ] = m.specularColor.r;
377
+ floatArray[ index ++ ] = m.specularColor.g;
378
+ floatArray[ index ++ ] = m.specularColor.b;
379
+
380
+ } else {
381
+
382
+ floatArray[ index ++ ] = 1.0;
383
+ floatArray[ index ++ ] = 1.0;
384
+ floatArray[ index ++ ] = 1.0;
385
+
386
+ }
387
+
388
+ floatArray[ index ++ ] = getTexture( m, 'specularColorMap' );
389
+
390
+ // sample 11
391
+ // specular intensity
392
+ floatArray[ index ++ ] = getField( m, 'specularIntensity', 1.0 );
393
+ floatArray[ index ++ ] = getTexture( m, 'specularIntensityMap' );
394
+
395
+ // isThinFilm
396
+ const isThinFilm = getField( m, 'thickness', 0.0 ) === 0.0 && getField( m, 'attenuationDistance', Infinity ) === Infinity;
397
+ floatArray[ index ++ ] = Number( isThinFilm );
398
+ index ++;
399
+
400
+ // sample 12
401
+ if ( 'attenuationColor' in m ) {
402
+
403
+ floatArray[ index ++ ] = m.attenuationColor.r;
404
+ floatArray[ index ++ ] = m.attenuationColor.g;
405
+ floatArray[ index ++ ] = m.attenuationColor.b;
406
+
407
+ } else {
408
+
409
+ floatArray[ index ++ ] = 1.0;
410
+ floatArray[ index ++ ] = 1.0;
411
+ floatArray[ index ++ ] = 1.0;
412
+
413
+ }
414
+
415
+ floatArray[ index ++ ] = getField( m, 'attenuationDistance', Infinity );
416
+
417
+ // sample 13
418
+ // alphaMap
419
+ floatArray[ index ++ ] = getTexture( m, 'alphaMap' );
420
+
421
+ // side & matte
422
+ floatArray[ index ++ ] = m.opacity;
423
+ floatArray[ index ++ ] = m.alphaTest;
424
+ if ( ! isThinFilm && m.transmission > 0.0 ) {
425
+
426
+ floatArray[ index ++ ] = 0;
427
+
428
+ } else {
429
+
430
+ switch ( m.side ) {
431
+
432
+ case FrontSide:
433
+ floatArray[ index ++ ] = 1;
434
+ break;
435
+ case BackSide:
436
+ floatArray[ index ++ ] = - 1;
437
+ break;
438
+ case DoubleSide:
439
+ floatArray[ index ++ ] = 0;
440
+ break;
441
+
442
+ }
443
+
444
+ }
445
+
446
+ // sample 14
447
+ index ++; // matte
448
+ index ++; // shadow
449
+ floatArray[ index ++ ] = Number( m.vertexColors ) | ( Number( m.flatShading ) << 1 ); // vertexColors & flatShading
450
+ floatArray[ index ++ ] = Number( m.transparent ); // transparent
451
+
452
+ // map transform 15
453
+ index += writeTextureMatrixToArray( m, 'map', floatArray, index );
454
+
455
+ // metalnessMap transform 17
456
+ index += writeTextureMatrixToArray( m, 'metalnessMap', floatArray, index );
457
+
458
+ // roughnessMap transform 19
459
+ index += writeTextureMatrixToArray( m, 'roughnessMap', floatArray, index );
460
+
461
+ // transmissionMap transform 21
462
+ index += writeTextureMatrixToArray( m, 'transmissionMap', floatArray, index );
463
+
464
+ // emissiveMap transform 22
465
+ index += writeTextureMatrixToArray( m, 'emissiveMap', floatArray, index );
466
+
467
+ // normalMap transform 25
468
+ index += writeTextureMatrixToArray( m, 'normalMap', floatArray, index );
469
+
470
+ // clearcoatMap transform 27
471
+ index += writeTextureMatrixToArray( m, 'clearcoatMap', floatArray, index );
472
+
473
+ // clearcoatNormalMap transform 29
474
+ index += writeTextureMatrixToArray( m, 'clearcoatNormalMap', floatArray, index );
475
+
476
+ // clearcoatRoughnessMap transform 31
477
+ index += writeTextureMatrixToArray( m, 'clearcoatRoughnessMap', floatArray, index );
478
+
479
+ // sheenColorMap transform 33
480
+ index += writeTextureMatrixToArray( m, 'sheenColorMap', floatArray, index );
481
+
482
+ // sheenRoughnessMap transform 35
483
+ index += writeTextureMatrixToArray( m, 'sheenRoughnessMap', floatArray, index );
484
+
485
+ // iridescenceMap transform 37
486
+ index += writeTextureMatrixToArray( m, 'iridescenceMap', floatArray, index );
487
+
488
+ // iridescenceThicknessMap transform 39
489
+ index += writeTextureMatrixToArray( m, 'iridescenceThicknessMap', floatArray, index );
490
+
491
+ // specularColorMap transform 41
492
+ index += writeTextureMatrixToArray( m, 'specularColorMap', floatArray, index );
493
+
494
+ // specularIntensityMap transform 43
495
+ index += writeTextureMatrixToArray( m, 'specularIntensityMap', floatArray, index );
496
+
497
+ }
498
+
499
+ this.needsUpdate = true;
500
+
501
+ }
502
+
503
+ }