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,317 +1,323 @@
1
-
2
- export const getSurfaceRecordGLSL = /* glsl */`
3
-
4
- #define SKIP_SURFACE 0
5
- #define HIT_SURFACE 1
6
- int getSurfaceRecord(
7
- Material material, sampler2DArray attributesArray,
8
- float side, vec3 barycoord, uvec4 faceIndices, vec3 faceNormal, float accumulatedRoughness,
9
-
10
- out SurfaceRecord surf
11
- ) {
12
-
13
- if ( material.fogVolume ) {
14
-
15
- vec3 normal = vec3( 0, 0, 1 );
16
-
17
- SurfaceRecord fogSurface;
18
- fogSurface.volumeParticle = true;
19
- fogSurface.color = material.color;
20
- fogSurface.emission = material.emissiveIntensity * material.emissive;
21
- fogSurface.normal = normal;
22
- fogSurface.faceNormal = normal;
23
- fogSurface.clearcoatNormal = normal;
24
-
25
- surf = fogSurface;
26
- return HIT_SURFACE;
27
-
28
- }
29
-
30
- // uv coord for textures
31
- vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
32
- vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
33
-
34
- // albedo
35
- vec4 albedo = vec4( material.color, material.opacity );
36
- if ( material.map != - 1 ) {
37
-
38
- vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
39
- albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
40
- }
41
-
42
- if ( material.vertexColors ) {
43
-
44
- albedo *= vertexColor;
45
-
46
- }
47
-
48
- // alphaMap
49
- if ( material.alphaMap != - 1 ) {
50
-
51
- albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
52
-
53
- }
54
-
55
- // possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side
56
- // and it's single sided.
57
- // - alpha test is disabled when it === 0
58
- // - the material sidedness test is complicated because we want light to pass through the back side but still
59
- // be able to see the front side. This boolean checks if the side we hit is the front side on the first ray
60
- // and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
61
- float alphaTest = material.alphaTest;
62
- bool useAlphaTest = alphaTest != 0.0;
63
- if (
64
- // material sidedness
65
- material.side != 0.0 && side != material.side
66
-
67
- // alpha test
68
- || useAlphaTest && albedo.a < alphaTest
69
-
70
- // opacity
71
- || material.transparent && ! useAlphaTest && albedo.a < sobol( 3 )
72
- ) {
73
-
74
- return SKIP_SURFACE;
75
-
76
- }
77
-
78
- // fetch the interpolated smooth normal
79
- vec3 normal = normalize( textureSampleBarycoord(
80
- attributesArray,
81
- ATTR_NORMAL,
82
- barycoord,
83
- faceIndices.xyz
84
- ).xyz );
85
-
86
- // roughness
87
- float roughness = material.roughness;
88
- if ( material.roughnessMap != - 1 ) {
89
-
90
- vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );
91
- roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;
92
-
93
- }
94
-
95
- // metalness
96
- float metalness = material.metalness;
97
- if ( material.metalnessMap != - 1 ) {
98
-
99
- vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
100
- metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
101
-
102
- }
103
-
104
- // emission
105
- vec3 emission = material.emissiveIntensity * material.emissive;
106
- if ( material.emissiveMap != - 1 ) {
107
-
108
- vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );
109
- emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;
110
-
111
- }
112
-
113
- // transmission
114
- float transmission = material.transmission;
115
- if ( material.transmissionMap != - 1 ) {
116
-
117
- vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
118
- transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
119
-
120
- }
121
-
122
- // normal
123
- if ( material.flatShading ) {
124
-
125
- // if we're rendering a flat shaded object then use the face normals - the face normal
126
- // is provided based on the side the ray hits the mesh so flip it to align with the
127
- // interpolated vertex normals.
128
- normal = faceNormal * side;
129
-
130
- }
131
-
132
- vec3 baseNormal = normal;
133
- if ( material.normalMap != - 1 ) {
134
-
135
- vec4 tangentSample = textureSampleBarycoord(
136
- attributesArray,
137
- ATTR_TANGENT,
138
- barycoord,
139
- faceIndices.xyz
140
- );
141
-
142
- // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
143
- // resulting in NaNs and slow path tracing.
144
- if ( length( tangentSample.xyz ) > 0.0 ) {
145
-
146
- vec3 tangent = normalize( tangentSample.xyz );
147
- vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );
148
- mat3 vTBN = mat3( tangent, bitangent, normal );
149
-
150
- vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );
151
- vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;
152
- texNormal.xy *= material.normalScale;
153
- normal = vTBN * texNormal;
154
-
155
- }
156
-
157
- }
158
-
159
- normal *= side;
160
-
161
- // clearcoat
162
- float clearcoat = material.clearcoat;
163
- if ( material.clearcoatMap != - 1 ) {
164
-
165
- vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );
166
- clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;
167
-
168
- }
169
-
170
- // clearcoatRoughness
171
- float clearcoatRoughness = material.clearcoatRoughness;
172
- if ( material.clearcoatRoughnessMap != - 1 ) {
173
-
174
- vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );
175
- clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;
176
-
177
- }
178
-
179
- // clearcoatNormal
180
- vec3 clearcoatNormal = baseNormal;
181
- if ( material.clearcoatNormalMap != - 1 ) {
182
-
183
- vec4 tangentSample = textureSampleBarycoord(
184
- attributesArray,
185
- ATTR_TANGENT,
186
- barycoord,
187
- faceIndices.xyz
188
- );
189
-
190
- // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
191
- // resulting in NaNs and slow path tracing.
192
- if ( length( tangentSample.xyz ) > 0.0 ) {
193
-
194
- vec3 tangent = normalize( tangentSample.xyz );
195
- vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );
196
- mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
197
-
198
- vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );
199
- vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;
200
- texNormal.xy *= material.clearcoatNormalScale;
201
- clearcoatNormal = vTBN * texNormal;
202
-
203
- }
204
-
205
- }
206
-
207
- clearcoatNormal *= side;
208
-
209
- // sheenColor
210
- vec3 sheenColor = material.sheenColor;
211
- if ( material.sheenColorMap != - 1 ) {
212
-
213
- vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );
214
- sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;
215
-
216
- }
217
-
218
- // sheenRoughness
219
- float sheenRoughness = material.sheenRoughness;
220
- if ( material.sheenRoughnessMap != - 1 ) {
221
-
222
- vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );
223
- sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;
224
-
225
- }
226
-
227
- // iridescence
228
- float iridescence = material.iridescence;
229
- if ( material.iridescenceMap != - 1 ) {
230
-
231
- vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );
232
- iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;
233
-
234
- }
235
-
236
- // iridescence thickness
237
- float iridescenceThickness = material.iridescenceThicknessMaximum;
238
- if ( material.iridescenceThicknessMap != - 1 ) {
239
-
240
- vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );
241
- float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;
242
- iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );
243
-
244
- }
245
-
246
- iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;
247
-
248
- // specular color
249
- vec3 specularColor = material.specularColor;
250
- if ( material.specularColorMap != - 1 ) {
251
-
252
- vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );
253
- specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;
254
-
255
- }
256
-
257
- // specular intensity
258
- float specularIntensity = material.specularIntensity;
259
- if ( material.specularIntensityMap != - 1 ) {
260
-
261
- vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );
262
- specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;
263
-
264
- }
265
-
266
- surf.volumeParticle = false;
267
-
268
- surf.faceNormal = faceNormal;
269
- surf.normal = normal;
270
-
271
- surf.metalness = metalness;
272
- surf.color = albedo.rgb;
273
- surf.emission = emission;
274
-
275
- surf.ior = material.ior;
276
- surf.transmission = transmission;
277
- surf.thinFilm = material.thinFilm;
278
- surf.attenuationColor = material.attenuationColor;
279
- surf.attenuationDistance = material.attenuationDistance;
280
-
281
- surf.clearcoatNormal = clearcoatNormal;
282
- surf.clearcoat = clearcoat;
283
-
284
- surf.sheen = material.sheen;
285
- surf.sheenColor = sheenColor;
286
-
287
- surf.iridescence = iridescence;
288
- surf.iridescenceIor = material.iridescenceIor;
289
- surf.iridescenceThickness = iridescenceThickness;
290
-
291
- surf.specularColor = specularColor;
292
- surf.specularIntensity = specularIntensity;
293
-
294
- // apply perceptual roughness factor from gltf. sheen perceptual roughness is
295
- // applied by its brdf function
296
- // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
297
- surf.roughness = roughness * roughness;
298
- surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
299
- surf.sheenRoughness = sheenRoughness;
300
-
301
- // frontFace is used to determine transmissive properties and PDF. If no transmission is used
302
- // then we can just always assume this is a front face.
303
- surf.frontFace = side == 1.0 || transmission == 0.0;
304
- surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;
305
- surf.f0 = iorRatioToF0( surf.eta );
306
-
307
- // Compute the filtered roughness value to use during specular reflection computations.
308
- // The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
309
- // If we're exiting something transmissive then scale the factor down significantly so we can retain
310
- // sharp internal reflections
311
- surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );
312
- surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );
313
-
314
- return HIT_SURFACE;
315
-
316
- }
317
- `;
1
+
2
+ export const getSurfaceRecordGLSL = /* glsl */`
3
+
4
+ #define SKIP_SURFACE 0
5
+ #define HIT_SURFACE 1
6
+ int getSurfaceRecord(
7
+ Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,
8
+ float accumulatedRoughness,
9
+ out SurfaceRecord surf
10
+ ) {
11
+
12
+ if ( material.fogVolume ) {
13
+
14
+ vec3 normal = vec3( 0, 0, 1 );
15
+
16
+ SurfaceRecord fogSurface;
17
+ fogSurface.volumeParticle = true;
18
+ fogSurface.color = material.color;
19
+ fogSurface.emission = material.emissiveIntensity * material.emissive;
20
+ fogSurface.normal = normal;
21
+ fogSurface.faceNormal = normal;
22
+ fogSurface.clearcoatNormal = normal;
23
+
24
+ surf = fogSurface;
25
+ return HIT_SURFACE;
26
+
27
+ }
28
+
29
+ // uv coord for textures
30
+ vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;
31
+ vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );
32
+
33
+ // albedo
34
+ vec4 albedo = vec4( material.color, material.opacity );
35
+ if ( material.map != - 1 ) {
36
+
37
+ vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
38
+ albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
39
+ }
40
+
41
+ if ( material.vertexColors ) {
42
+
43
+ albedo *= vertexColor;
44
+
45
+ }
46
+
47
+ // alphaMap
48
+ if ( material.alphaMap != - 1 ) {
49
+
50
+ albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
51
+
52
+ }
53
+
54
+ // possibly skip this sample if it's transparent, alpha test is enabled, or we hit the wrong material side
55
+ // and it's single sided.
56
+ // - alpha test is disabled when it === 0
57
+ // - the material sidedness test is complicated because we want light to pass through the back side but still
58
+ // be able to see the front side. This boolean checks if the side we hit is the front side on the first ray
59
+ // and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
60
+ float alphaTest = material.alphaTest;
61
+ bool useAlphaTest = alphaTest != 0.0;
62
+ if (
63
+ // material sidedness
64
+ material.side != 0.0 && surfaceHit.side != material.side
65
+
66
+ // alpha test
67
+ || useAlphaTest && albedo.a < alphaTest
68
+
69
+ // opacity
70
+ || material.transparent && ! useAlphaTest && albedo.a < sobol( 3 )
71
+ ) {
72
+
73
+ return SKIP_SURFACE;
74
+
75
+ }
76
+
77
+ // fetch the interpolated smooth normal
78
+ vec3 normal = normalize( textureSampleBarycoord(
79
+ attributesArray,
80
+ ATTR_NORMAL,
81
+ surfaceHit.barycoord,
82
+ surfaceHit.faceIndices.xyz
83
+ ).xyz );
84
+
85
+ // roughness
86
+ float roughness = material.roughness;
87
+ if ( material.roughnessMap != - 1 ) {
88
+
89
+ vec3 uvPrime = material.roughnessMapTransform * vec3( uv, 1 );
90
+ roughness *= texture2D( textures, vec3( uvPrime.xy, material.roughnessMap ) ).g;
91
+
92
+ }
93
+
94
+ // metalness
95
+ float metalness = material.metalness;
96
+ if ( material.metalnessMap != - 1 ) {
97
+
98
+ vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
99
+ metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
100
+
101
+ }
102
+
103
+ // emission
104
+ vec3 emission = material.emissiveIntensity * material.emissive;
105
+ if ( material.emissiveMap != - 1 ) {
106
+
107
+ vec3 uvPrime = material.emissiveMapTransform * vec3( uv, 1 );
108
+ emission *= texture2D( textures, vec3( uvPrime.xy, material.emissiveMap ) ).xyz;
109
+
110
+ }
111
+
112
+ // transmission
113
+ float transmission = material.transmission;
114
+ if ( material.transmissionMap != - 1 ) {
115
+
116
+ vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
117
+ transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
118
+
119
+ }
120
+
121
+ // normal
122
+ if ( material.flatShading ) {
123
+
124
+ // if we're rendering a flat shaded object then use the face normals - the face normal
125
+ // is provided based on the side the ray hits the mesh so flip it to align with the
126
+ // interpolated vertex normals.
127
+ normal = surfaceHit.faceNormal * surfaceHit.side;
128
+
129
+ }
130
+
131
+ vec3 baseNormal = normal;
132
+ if ( material.normalMap != - 1 ) {
133
+
134
+ vec4 tangentSample = textureSampleBarycoord(
135
+ attributesArray,
136
+ ATTR_TANGENT,
137
+ surfaceHit.barycoord,
138
+ surfaceHit.faceIndices.xyz
139
+ );
140
+
141
+ // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
142
+ // resulting in NaNs and slow path tracing.
143
+ if ( length( tangentSample.xyz ) > 0.0 ) {
144
+
145
+ vec3 tangent = normalize( tangentSample.xyz );
146
+ vec3 bitangent = normalize( cross( normal, tangent ) * tangentSample.w );
147
+ mat3 vTBN = mat3( tangent, bitangent, normal );
148
+
149
+ vec3 uvPrime = material.normalMapTransform * vec3( uv, 1 );
150
+ vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.normalMap ) ).xyz * 2.0 - 1.0;
151
+ texNormal.xy *= material.normalScale;
152
+ normal = vTBN * texNormal;
153
+
154
+ }
155
+
156
+ }
157
+
158
+ normal *= surfaceHit.side;
159
+
160
+ // clearcoat
161
+ float clearcoat = material.clearcoat;
162
+ if ( material.clearcoatMap != - 1 ) {
163
+
164
+ vec3 uvPrime = material.clearcoatMapTransform * vec3( uv, 1 );
165
+ clearcoat *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatMap ) ).r;
166
+
167
+ }
168
+
169
+ // clearcoatRoughness
170
+ float clearcoatRoughness = material.clearcoatRoughness;
171
+ if ( material.clearcoatRoughnessMap != - 1 ) {
172
+
173
+ vec3 uvPrime = material.clearcoatRoughnessMapTransform * vec3( uv, 1 );
174
+ clearcoatRoughness *= texture2D( textures, vec3( uvPrime.xy, material.clearcoatRoughnessMap ) ).g;
175
+
176
+ }
177
+
178
+ // clearcoatNormal
179
+ vec3 clearcoatNormal = baseNormal;
180
+ if ( material.clearcoatNormalMap != - 1 ) {
181
+
182
+ vec4 tangentSample = textureSampleBarycoord(
183
+ attributesArray,
184
+ ATTR_TANGENT,
185
+ surfaceHit.barycoord,
186
+ surfaceHit.faceIndices.xyz
187
+ );
188
+
189
+ // some provided tangents can be malformed (0, 0, 0) causing the normal to be degenerate
190
+ // resulting in NaNs and slow path tracing.
191
+ if ( length( tangentSample.xyz ) > 0.0 ) {
192
+
193
+ vec3 tangent = normalize( tangentSample.xyz );
194
+ vec3 bitangent = normalize( cross( clearcoatNormal, tangent ) * tangentSample.w );
195
+ mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
196
+
197
+ vec3 uvPrime = material.clearcoatNormalMapTransform * vec3( uv, 1 );
198
+ vec3 texNormal = texture2D( textures, vec3( uvPrime.xy, material.clearcoatNormalMap ) ).xyz * 2.0 - 1.0;
199
+ texNormal.xy *= material.clearcoatNormalScale;
200
+ clearcoatNormal = vTBN * texNormal;
201
+
202
+ }
203
+
204
+ }
205
+
206
+ clearcoatNormal *= surfaceHit.side;
207
+
208
+ // sheenColor
209
+ vec3 sheenColor = material.sheenColor;
210
+ if ( material.sheenColorMap != - 1 ) {
211
+
212
+ vec3 uvPrime = material.sheenColorMapTransform * vec3( uv, 1 );
213
+ sheenColor *= texture2D( textures, vec3( uvPrime.xy, material.sheenColorMap ) ).rgb;
214
+
215
+ }
216
+
217
+ // sheenRoughness
218
+ float sheenRoughness = material.sheenRoughness;
219
+ if ( material.sheenRoughnessMap != - 1 ) {
220
+
221
+ vec3 uvPrime = material.sheenRoughnessMapTransform * vec3( uv, 1 );
222
+ sheenRoughness *= texture2D( textures, vec3( uvPrime.xy, material.sheenRoughnessMap ) ).a;
223
+
224
+ }
225
+
226
+ // iridescence
227
+ float iridescence = material.iridescence;
228
+ if ( material.iridescenceMap != - 1 ) {
229
+
230
+ vec3 uvPrime = material.iridescenceMapTransform * vec3( uv, 1 );
231
+ iridescence *= texture2D( textures, vec3( uvPrime.xy, material.iridescenceMap ) ).r;
232
+
233
+ }
234
+
235
+ // iridescence thickness
236
+ float iridescenceThickness = material.iridescenceThicknessMaximum;
237
+ if ( material.iridescenceThicknessMap != - 1 ) {
238
+
239
+ vec3 uvPrime = material.iridescenceThicknessMapTransform * vec3( uv, 1 );
240
+ float iridescenceThicknessSampled = texture2D( textures, vec3( uvPrime.xy, material.iridescenceThicknessMap ) ).g;
241
+ iridescenceThickness = mix( material.iridescenceThicknessMinimum, material.iridescenceThicknessMaximum, iridescenceThicknessSampled );
242
+
243
+ }
244
+
245
+ iridescence = iridescenceThickness == 0.0 ? 0.0 : iridescence;
246
+
247
+ // specular color
248
+ vec3 specularColor = material.specularColor;
249
+ if ( material.specularColorMap != - 1 ) {
250
+
251
+ vec3 uvPrime = material.specularColorMapTransform * vec3( uv, 1 );
252
+ specularColor *= texture2D( textures, vec3( uvPrime.xy, material.specularColorMap ) ).rgb;
253
+
254
+ }
255
+
256
+ // specular intensity
257
+ float specularIntensity = material.specularIntensity;
258
+ if ( material.specularIntensityMap != - 1 ) {
259
+
260
+ vec3 uvPrime = material.specularIntensityMapTransform * vec3( uv, 1 );
261
+ specularIntensity *= texture2D( textures, vec3( uvPrime.xy, material.specularIntensityMap ) ).a;
262
+
263
+ }
264
+
265
+ surf.volumeParticle = false;
266
+
267
+ surf.faceNormal = surfaceHit.faceNormal;
268
+ surf.normal = normal;
269
+
270
+ surf.metalness = metalness;
271
+ surf.color = albedo.rgb;
272
+ surf.emission = emission;
273
+
274
+ surf.ior = material.ior;
275
+ surf.transmission = transmission;
276
+ surf.thinFilm = material.thinFilm;
277
+ surf.attenuationColor = material.attenuationColor;
278
+ surf.attenuationDistance = material.attenuationDistance;
279
+
280
+ surf.clearcoatNormal = clearcoatNormal;
281
+ surf.clearcoat = clearcoat;
282
+
283
+ surf.sheen = material.sheen;
284
+ surf.sheenColor = sheenColor;
285
+
286
+ surf.iridescence = iridescence;
287
+ surf.iridescenceIor = material.iridescenceIor;
288
+ surf.iridescenceThickness = iridescenceThickness;
289
+
290
+ surf.specularColor = specularColor;
291
+ surf.specularIntensity = specularIntensity;
292
+
293
+ // apply perceptual roughness factor from gltf. sheen perceptual roughness is
294
+ // applied by its brdf function
295
+ // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
296
+ surf.roughness = roughness * roughness;
297
+ surf.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
298
+ surf.sheenRoughness = sheenRoughness;
299
+
300
+ // frontFace is used to determine transmissive properties and PDF. If no transmission is used
301
+ // then we can just always assume this is a front face.
302
+ surf.frontFace = surfaceHit.side == 1.0 || transmission == 0.0;
303
+ surf.eta = material.thinFilm || surf.frontFace ? 1.0 / material.ior : material.ior;
304
+ surf.f0 = iorRatioToF0( surf.eta );
305
+
306
+ // Compute the filtered roughness value to use during specular reflection computations.
307
+ // The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
308
+ // If we're exiting something transmissive then scale the factor down significantly so we can retain
309
+ // sharp internal reflections
310
+ surf.filteredRoughness = applyFilteredGlossy( surf.roughness, accumulatedRoughness );
311
+ surf.filteredClearcoatRoughness = applyFilteredGlossy( surf.clearcoatRoughness, accumulatedRoughness );
312
+
313
+ // get the normal frames
314
+ surf.normalBasis = getBasisFromNormal( surf.normal );
315
+ surf.normalInvBasis = inverse( surf.normalBasis );
316
+
317
+ surf.clearcoatBasis = getBasisFromNormal( surf.clearcoatNormal );
318
+ surf.clearcoatInvBasis = inverse( surf.clearcoatBasis );
319
+
320
+ return HIT_SURFACE;
321
+
322
+ }
323
+ `;