three-gpu-pathtracer 0.0.6 → 0.0.7
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/README.md +34 -0
- package/build/index.module.js +878 -377
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +878 -375
- package/build/index.umd.cjs.map +1 -1
- package/package.json +2 -2
- package/src/core/DynamicPathTracingSceneGenerator.js +1 -1
- package/src/core/PathTracingRenderer.js +24 -9
- package/src/core/PathTracingSceneGenerator.js +69 -68
- package/src/index.js +2 -0
- package/src/materials/AmbientOcclusionMaterial.js +3 -3
- package/src/materials/DenoiseMaterial.js +142 -0
- package/src/materials/GraphMaterial.js +243 -0
- package/src/materials/PhysicalPathTracingMaterial.js +63 -15
- package/src/shader/shaderGGXFunctions.js +3 -11
- package/src/shader/shaderMaterialSampling.js +45 -49
- package/src/shader/shaderStructs.js +22 -8
- package/src/shader/shaderUtils.js +16 -2
- package/src/uniforms/MaterialsTexture.js +46 -26
- package/src/utils/GeometryPreparationUtils.js +214 -194
|
@@ -52,6 +52,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
52
52
|
normalAttribute: { value: new FloatVertexAttributeTexture() },
|
|
53
53
|
tangentAttribute: { value: new FloatVertexAttributeTexture() },
|
|
54
54
|
uvAttribute: { value: new FloatVertexAttributeTexture() },
|
|
55
|
+
colorAttribute: { value: new FloatVertexAttributeTexture() },
|
|
55
56
|
materialIndexAttribute: { value: new UIntVertexAttributeTexture() },
|
|
56
57
|
materials: { value: new MaterialsTexture() },
|
|
57
58
|
textures: { value: new RenderTarget2DArray().texture },
|
|
@@ -130,6 +131,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
130
131
|
uniform sampler2D normalAttribute;
|
|
131
132
|
uniform sampler2D tangentAttribute;
|
|
132
133
|
uniform sampler2D uvAttribute;
|
|
134
|
+
uniform sampler2D colorAttribute;
|
|
133
135
|
uniform usampler2D materialIndexAttribute;
|
|
134
136
|
uniform BVH bvh;
|
|
135
137
|
uniform float environmentIntensity;
|
|
@@ -147,6 +149,18 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
147
149
|
uniform sampler2DArray textures;
|
|
148
150
|
varying vec2 vUv;
|
|
149
151
|
|
|
152
|
+
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
153
|
+
|
|
154
|
+
return clamp(
|
|
155
|
+
max(
|
|
156
|
+
roughness,
|
|
157
|
+
accumulatedRoughness * filterGlossyFactor * 5.0 ),
|
|
158
|
+
0.0,
|
|
159
|
+
1.0
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
150
164
|
vec3 sampleBackground( vec3 direction ) {
|
|
151
165
|
|
|
152
166
|
#if FEATURE_GRADIENT_BG
|
|
@@ -188,6 +202,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
188
202
|
// TODO: should we account for emissive surfaces here?
|
|
189
203
|
|
|
190
204
|
vec2 uv = textureSampleBarycoord( uvAttribute, barycoord, faceIndices.xyz ).xy;
|
|
205
|
+
vec4 vertexColor = textureSampleBarycoord( colorAttribute, barycoord, faceIndices.xyz );
|
|
191
206
|
uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
|
|
192
207
|
Material material = readMaterialInfo( materials, materialIndex );
|
|
193
208
|
|
|
@@ -215,8 +230,14 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
215
230
|
|
|
216
231
|
}
|
|
217
232
|
|
|
233
|
+
if ( material.vertexColors ) {
|
|
234
|
+
|
|
235
|
+
albedo *= vertexColor;
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
218
239
|
// alphaMap
|
|
219
|
-
if ( material.alphaMap != -1 ) {
|
|
240
|
+
if ( material.alphaMap != - 1 ) {
|
|
220
241
|
|
|
221
242
|
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
222
243
|
|
|
@@ -252,7 +273,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
252
273
|
|| useAlphaTest && albedo.a < alphaTest
|
|
253
274
|
|
|
254
275
|
// opacity
|
|
255
|
-
|| ! useAlphaTest && albedo.a < rand()
|
|
276
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand()
|
|
256
277
|
)
|
|
257
278
|
) {
|
|
258
279
|
|
|
@@ -260,11 +281,16 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
260
281
|
|
|
261
282
|
}
|
|
262
283
|
|
|
263
|
-
|
|
264
|
-
if ( isBelowSurface ) {
|
|
284
|
+
if ( side == 1.0 && isBelowSurface ) {
|
|
265
285
|
|
|
286
|
+
// only attenuate by surface color on the way in
|
|
266
287
|
color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
|
|
267
288
|
|
|
289
|
+
} else if ( side == - 1.0 ) {
|
|
290
|
+
|
|
291
|
+
// attenuate by medium once we hit the opposite side of the model
|
|
292
|
+
color *= transmissionAttenuation( dist, material.attenuationColor, material.attenuationDistance );
|
|
293
|
+
|
|
268
294
|
}
|
|
269
295
|
|
|
270
296
|
} else {
|
|
@@ -329,7 +355,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
329
355
|
|
|
330
356
|
#else
|
|
331
357
|
|
|
332
|
-
// get [-1, 1] normalized device coordinates
|
|
358
|
+
// get [- 1, 1] normalized device coordinates
|
|
333
359
|
vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
|
|
334
360
|
|
|
335
361
|
rayOrigin = ndcToRayOrigin( ndc );
|
|
@@ -338,7 +364,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
338
364
|
|
|
339
365
|
// Orthographic projection
|
|
340
366
|
|
|
341
|
-
rayDirection = ( cameraWorldMatrix * vec4( 0.0, 0.0, -1.0, 0.0 ) ).xyz;
|
|
367
|
+
rayDirection = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
|
|
342
368
|
rayDirection = normalize( rayDirection );
|
|
343
369
|
|
|
344
370
|
#else
|
|
@@ -512,7 +538,10 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
512
538
|
|
|
513
539
|
}
|
|
514
540
|
|
|
541
|
+
// uv coord for textures
|
|
515
542
|
vec2 uv = textureSampleBarycoord( uvAttribute, barycoord, faceIndices.xyz ).xy;
|
|
543
|
+
vec4 vertexColor = textureSampleBarycoord( colorAttribute, barycoord, faceIndices.xyz );
|
|
544
|
+
|
|
516
545
|
// albedo
|
|
517
546
|
vec4 albedo = vec4( material.color, material.opacity );
|
|
518
547
|
if ( material.map != - 1 ) {
|
|
@@ -521,8 +550,14 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
521
550
|
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
522
551
|
}
|
|
523
552
|
|
|
553
|
+
if ( material.vertexColors ) {
|
|
554
|
+
|
|
555
|
+
albedo *= vertexColor;
|
|
556
|
+
|
|
557
|
+
}
|
|
558
|
+
|
|
524
559
|
// alphaMap
|
|
525
|
-
if ( material.alphaMap != -1 ) {
|
|
560
|
+
if ( material.alphaMap != - 1 ) {
|
|
526
561
|
|
|
527
562
|
albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
|
|
528
563
|
|
|
@@ -536,16 +571,15 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
536
571
|
// and we're rendering the other then we skip it. Do the opposite on subsequent bounces to get incoming light.
|
|
537
572
|
float alphaTest = material.alphaTest;
|
|
538
573
|
bool useAlphaTest = alphaTest != 0.0;
|
|
539
|
-
bool isFirstHit = i == 0;
|
|
540
574
|
if (
|
|
541
575
|
// material sidedness
|
|
542
|
-
material.side != 0.0 &&
|
|
576
|
+
material.side != 0.0 && side != material.side
|
|
543
577
|
|
|
544
578
|
// alpha test
|
|
545
579
|
|| useAlphaTest && albedo.a < alphaTest
|
|
546
580
|
|
|
547
581
|
// opacity
|
|
548
|
-
|| ! useAlphaTest && albedo.a < rand()
|
|
582
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand()
|
|
549
583
|
) {
|
|
550
584
|
|
|
551
585
|
vec3 point = rayOrigin + rayDirection * dist;
|
|
@@ -745,27 +779,34 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
745
779
|
surfaceRec.emission = emission;
|
|
746
780
|
surfaceRec.metalness = metalness;
|
|
747
781
|
surfaceRec.color = albedo.rgb;
|
|
748
|
-
surfaceRec.roughness = roughness;
|
|
749
782
|
surfaceRec.clearcoat = clearcoat;
|
|
750
|
-
surfaceRec.clearcoatRoughness = clearcoatRoughness;
|
|
751
783
|
surfaceRec.sheenColor = sheenColor;
|
|
752
|
-
surfaceRec.sheenRoughness = sheenRoughness;
|
|
753
784
|
surfaceRec.iridescence = iridescence;
|
|
754
785
|
surfaceRec.iridescenceIor = material.iridescenceIor;
|
|
755
786
|
surfaceRec.iridescenceThickness = iridescenceThickness;
|
|
756
787
|
surfaceRec.specularColor = specularColor;
|
|
757
788
|
surfaceRec.specularIntensity = specularIntensity;
|
|
789
|
+
surfaceRec.attenuationColor = material.attenuationColor;
|
|
790
|
+
surfaceRec.attenuationDistance = material.attenuationDistance;
|
|
791
|
+
|
|
792
|
+
// apply perceptual roughness factor from gltf
|
|
793
|
+
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#microfacet-surfaces
|
|
794
|
+
surfaceRec.roughness = roughness * roughness;
|
|
795
|
+
surfaceRec.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness;
|
|
796
|
+
surfaceRec.sheenRoughness = sheenRoughness * sheenRoughness;
|
|
758
797
|
|
|
759
798
|
// frontFace is used to determine transmissive properties and PDF. If no transmission is used
|
|
760
799
|
// then we can just always assume this is a front face.
|
|
761
800
|
surfaceRec.frontFace = side == 1.0 || transmission == 0.0;
|
|
801
|
+
surfaceRec.iorRatio = material.thinFilm || surfaceRec.frontFace ? 1.0 / material.ior : material.ior;
|
|
802
|
+
surfaceRec.thinFilm = material.thinFilm;
|
|
762
803
|
|
|
763
804
|
// Compute the filtered roughness value to use during specular reflection computations.
|
|
764
805
|
// The accumulated roughness value is scaled by a user setting and a "magic value" of 5.0.
|
|
765
806
|
// If we're exiting something transmissive then scale the factor down significantly so we can retain
|
|
766
807
|
// sharp internal reflections
|
|
767
|
-
surfaceRec.filteredRoughness =
|
|
768
|
-
surfaceRec.filteredClearcoatRoughness =
|
|
808
|
+
surfaceRec.filteredRoughness = applyFilteredGlossy( surfaceRec.roughness, accumulatedRoughness );
|
|
809
|
+
surfaceRec.filteredClearcoatRoughness = applyFilteredGlossy( surfaceRec.clearcoatRoughness, accumulatedClearcoatRoughness );
|
|
769
810
|
|
|
770
811
|
mat3 normalBasis = getBasisFromNormal( surfaceRec.normal );
|
|
771
812
|
mat3 invBasis = inverse( normalBasis );
|
|
@@ -898,6 +939,13 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
898
939
|
|
|
899
940
|
throughputColor *= sampleRec.color / sampleRec.pdf;
|
|
900
941
|
|
|
942
|
+
// attenuate the throughput color by the medium color
|
|
943
|
+
if ( side == - 1.0 ) {
|
|
944
|
+
|
|
945
|
+
throughputColor *= transmissionAttenuation( dist, surfaceRec.attenuationColor, surfaceRec.attenuationDistance );
|
|
946
|
+
|
|
947
|
+
}
|
|
948
|
+
|
|
901
949
|
// discard the sample if there are any NaNs
|
|
902
950
|
if ( any( isnan( throughputColor ) ) || any( isinf( throughputColor ) ) ) {
|
|
903
951
|
|
|
@@ -40,7 +40,7 @@ vec3 ggxDirection( vec3 incidentDir, float roughnessX, float roughnessY, float r
|
|
|
40
40
|
|
|
41
41
|
// Below are PDF and related functions for use in a Monte Carlo path tracer
|
|
42
42
|
// as specified in Appendix B of the following paper
|
|
43
|
-
// See equation (
|
|
43
|
+
// See equation (34) from reference [0]
|
|
44
44
|
float ggxLamda( float theta, float roughness ) {
|
|
45
45
|
|
|
46
46
|
float tanTheta = tan( theta );
|
|
@@ -52,7 +52,7 @@ float ggxLamda( float theta, float roughness ) {
|
|
|
52
52
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// See equation (
|
|
55
|
+
// See equation (34) from reference [0]
|
|
56
56
|
float ggxShadowMaskG1( float theta, float roughness ) {
|
|
57
57
|
|
|
58
58
|
return 1.0 / ( 1.0 + ggxLamda( theta, roughness ) );
|
|
@@ -68,9 +68,9 @@ float ggxShadowMaskG2( vec3 wi, vec3 wo, float roughness ) {
|
|
|
68
68
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// See equation (33) from reference [0]
|
|
71
72
|
float ggxDistribution( vec3 halfVector, float roughness ) {
|
|
72
73
|
|
|
73
|
-
// See equation (33) from reference [0]
|
|
74
74
|
float a2 = roughness * roughness;
|
|
75
75
|
a2 = max( EPSILON, a2 );
|
|
76
76
|
float cosTheta = halfVector.z;
|
|
@@ -85,14 +85,6 @@ float ggxDistribution( vec3 halfVector, float roughness ) {
|
|
|
85
85
|
float denom = PI * cosTheta4 * pow( a2 + tanTheta2, 2.0 );
|
|
86
86
|
return ( a2 / denom );
|
|
87
87
|
|
|
88
|
-
// See equation (1) from reference [2]
|
|
89
|
-
// const { x, y, z } = halfVector;
|
|
90
|
-
// const a2 = roughness * roughness;
|
|
91
|
-
// const mult = x * x / a2 + y * y / a2 + z * z;
|
|
92
|
-
// const mult2 = mult * mult;
|
|
93
|
-
|
|
94
|
-
// return 1.0 / Math.PI * a2 * mult2;
|
|
95
|
-
|
|
96
88
|
}
|
|
97
89
|
|
|
98
90
|
// See equation (3) from reference [2]
|
|
@@ -14,7 +14,9 @@ struct SurfaceRec {
|
|
|
14
14
|
vec3 color;
|
|
15
15
|
vec3 emission;
|
|
16
16
|
float transmission;
|
|
17
|
+
bool thinFilm;
|
|
17
18
|
float ior;
|
|
19
|
+
float iorRatio;
|
|
18
20
|
float clearcoat;
|
|
19
21
|
float clearcoatRoughness;
|
|
20
22
|
float filteredClearcoatRoughness;
|
|
@@ -25,6 +27,8 @@ struct SurfaceRec {
|
|
|
25
27
|
float iridescenceThickness;
|
|
26
28
|
vec3 specularColor;
|
|
27
29
|
float specularIntensity;
|
|
30
|
+
vec3 attenuationColor;
|
|
31
|
+
float attenuationDistance;
|
|
28
32
|
};
|
|
29
33
|
|
|
30
34
|
struct SampleRec {
|
|
@@ -63,9 +67,8 @@ vec3 diffuseColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
63
67
|
// TODO: scale by 1 - F here
|
|
64
68
|
// note on division by PI
|
|
65
69
|
// https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
|
|
66
|
-
float metalFactor = ( 1.0 - surf.metalness )
|
|
67
|
-
|
|
68
|
-
return surf.color * metalFactor * transmissionFactor;
|
|
70
|
+
float metalFactor = ( 1.0 - surf.metalness );
|
|
71
|
+
return surf.color * metalFactor * wi.z / PI;
|
|
69
72
|
|
|
70
73
|
}
|
|
71
74
|
|
|
@@ -105,15 +108,15 @@ vec3 specularColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
105
108
|
|
|
106
109
|
// if roughness is set to 0 then D === NaN which results in black pixels
|
|
107
110
|
float metalness = surf.metalness;
|
|
108
|
-
float ior = surf.ior;
|
|
109
|
-
bool frontFace = surf.frontFace;
|
|
110
111
|
float filteredRoughness = surf.filteredRoughness;
|
|
111
112
|
|
|
112
113
|
vec3 halfVector = getHalfVector( wo, wi );
|
|
113
|
-
float iorRatio =
|
|
114
|
+
float iorRatio = surf.iorRatio;
|
|
114
115
|
float G = ggxShadowMaskG2( wi, wo, filteredRoughness );
|
|
115
116
|
float D = ggxDistribution( halfVector, filteredRoughness );
|
|
116
|
-
|
|
117
|
+
|
|
118
|
+
float f0 = iorRatioToF0( iorRatio );
|
|
119
|
+
vec3 F = vec3( schlickFresnel( dot( wi, halfVector ), f0 ) );
|
|
117
120
|
|
|
118
121
|
float cosTheta = min( wo.z, 1.0 );
|
|
119
122
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
@@ -124,11 +127,12 @@ vec3 specularColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
124
127
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
float f0 = pow( ( iorRatio - 1.0 ) / ( iorRatio + 1.0 ), 2.0 );
|
|
128
130
|
vec3 iridescenceFresnel = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, halfVector ), surf.iridescenceThickness, vec3( f0 ) );
|
|
129
|
-
|
|
131
|
+
vec3 metalF = mix( F, iridescenceFresnel, surf.iridescence );
|
|
132
|
+
vec3 dialectricF = F * surf.specularIntensity;
|
|
133
|
+
F = mix( dialectricF, metalF, metalness );
|
|
130
134
|
|
|
131
|
-
vec3 color = mix(
|
|
135
|
+
vec3 color = mix( surf.specularColor, surf.color, metalness );
|
|
132
136
|
color = mix( color, vec3( 1.0 ), F );
|
|
133
137
|
color *= G * D / ( 4.0 * abs( wi.z * wo.z ) );
|
|
134
138
|
color *= mix( F, vec3( 1.0 ), metalness );
|
|
@@ -194,14 +198,11 @@ function transmissionColor( wo, wi, material, hit, colorTarget ) {
|
|
|
194
198
|
// incorrect PDF value at the moment. Update it to correctly use a GGX distribution
|
|
195
199
|
float transmissionPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
196
200
|
|
|
197
|
-
float
|
|
198
|
-
bool frontFace = surf.frontFace;
|
|
199
|
-
|
|
200
|
-
float ratio = frontFace ? 1.0 / ior : ior;
|
|
201
|
+
float iorRatio = surf.iorRatio;
|
|
201
202
|
float cosTheta = min( wo.z, 1.0 );
|
|
202
203
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
203
|
-
float reflectance = schlickFresnelFromIor( cosTheta,
|
|
204
|
-
bool cannotRefract =
|
|
204
|
+
float reflectance = schlickFresnelFromIor( cosTheta, iorRatio );
|
|
205
|
+
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
205
206
|
if ( cannotRefract ) {
|
|
206
207
|
|
|
207
208
|
return 0.0;
|
|
@@ -215,26 +216,25 @@ float transmissionPDF( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
215
216
|
vec3 transmissionDirection( vec3 wo, SurfaceRec surf ) {
|
|
216
217
|
|
|
217
218
|
float roughness = surf.roughness;
|
|
218
|
-
float
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
float iorRatio = surf.iorRatio;
|
|
220
|
+
|
|
221
|
+
vec3 halfVector = normalize( vec3( 0.0, 0.0, 1.0 ) + randDirection() * roughness );
|
|
222
|
+
vec3 lightDirection = refract( normalize( - wo ), halfVector, iorRatio );
|
|
223
|
+
|
|
224
|
+
if ( surf.thinFilm ) {
|
|
221
225
|
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
lightDirection = - refract( normalize( - lightDirection ), - vec3( 0.0, 0.0, 1.0 ), 1.0 / iorRatio );
|
|
227
|
+
|
|
228
|
+
}
|
|
224
229
|
return normalize( lightDirection );
|
|
225
230
|
|
|
226
231
|
}
|
|
227
232
|
|
|
228
233
|
vec3 transmissionColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
229
234
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
vec3 color = surf.color;
|
|
234
|
-
color *= ( 1.0 - metalness );
|
|
235
|
-
color *= transmission;
|
|
236
|
-
|
|
237
|
-
return color;
|
|
235
|
+
// only attenuate the color if it's on the way in
|
|
236
|
+
vec3 col = surf.thinFilm || surf.frontFace ? surf.color : vec3( 1.0 );
|
|
237
|
+
return surf.transmission * col;
|
|
238
238
|
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -316,16 +316,16 @@ vec3 sheenColor( vec3 wo, vec3 wi, SurfaceRec surf ) {
|
|
|
316
316
|
// bsdf
|
|
317
317
|
void getLobeWeights( vec3 wo, vec3 clearcoatWo, SurfaceRec surf, out float diffuseWeight, out float specularWeight, out float transmissionWeight, out float clearcoatWeight ) {
|
|
318
318
|
|
|
319
|
-
float ior = surf.ior;
|
|
320
319
|
float metalness = surf.metalness;
|
|
321
320
|
float transmission = surf.transmission;
|
|
322
|
-
bool frontFace = surf.frontFace;
|
|
323
321
|
|
|
324
|
-
|
|
322
|
+
// TODO: we should compute a half vector ahead of time and pass it into the sampling functions
|
|
323
|
+
// so all functions will use the same half vector
|
|
324
|
+
float iorRatio = surf.iorRatio;
|
|
325
325
|
float cosTheta = min( wo.z, 1.0 );
|
|
326
326
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
327
|
-
float reflectance = schlickFresnelFromIor( cosTheta,
|
|
328
|
-
bool cannotRefract =
|
|
327
|
+
float reflectance = schlickFresnelFromIor( cosTheta, iorRatio );
|
|
328
|
+
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
329
329
|
if ( cannotRefract ) {
|
|
330
330
|
|
|
331
331
|
reflectance = 1.0;
|
|
@@ -341,27 +341,23 @@ void getLobeWeights( vec3 wo, vec3 clearcoatWo, SurfaceRec surf, out float diffu
|
|
|
341
341
|
transmissionWeight = transmission * ( 1.0 - transSpecularProb ) * ( 1.0 - clearcoatWeight );
|
|
342
342
|
|
|
343
343
|
float totalWeight = diffuseWeight + specularWeight + transmissionWeight + clearcoatWeight;
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
transmissionWeight *= invTotalWeight;
|
|
349
|
-
clearcoatWeight *= invTotalWeight;
|
|
344
|
+
diffuseWeight /= totalWeight;
|
|
345
|
+
specularWeight /= totalWeight;
|
|
346
|
+
transmissionWeight /= totalWeight;
|
|
347
|
+
clearcoatWeight /= totalWeight;
|
|
350
348
|
|
|
351
349
|
}
|
|
352
350
|
|
|
353
351
|
float bsdfPdf( vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRec surf, out float specularPdf, float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight ) {
|
|
354
352
|
|
|
355
|
-
float ior = surf.ior;
|
|
356
353
|
float metalness = surf.metalness;
|
|
357
354
|
float transmission = surf.transmission;
|
|
358
|
-
bool frontFace = surf.frontFace;
|
|
359
355
|
|
|
360
|
-
float
|
|
356
|
+
float iorRatio = surf.iorRatio;
|
|
361
357
|
float cosTheta = min( wo.z, 1.0 );
|
|
362
358
|
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
|
363
|
-
float reflectance = schlickFresnelFromIor( cosTheta,
|
|
364
|
-
bool cannotRefract =
|
|
359
|
+
float reflectance = schlickFresnelFromIor( cosTheta, iorRatio );
|
|
360
|
+
bool cannotRefract = iorRatio * sinTheta > 1.0;
|
|
365
361
|
if ( cannotRefract ) {
|
|
366
362
|
|
|
367
363
|
reflectance = 1.0;
|
|
@@ -512,22 +508,22 @@ SampleRec bsdfSample( vec3 wo, vec3 clearcoatWo, mat3 normalBasis, mat3 invBasis
|
|
|
512
508
|
vec3 clearcoatWi;
|
|
513
509
|
|
|
514
510
|
float r = rand();
|
|
515
|
-
if ( r <= cdf[0] ) {
|
|
511
|
+
if ( r <= cdf[0] ) { // diffuse
|
|
516
512
|
|
|
517
513
|
wi = diffuseDirection( wo, surf );
|
|
518
514
|
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
519
515
|
|
|
520
|
-
} else if ( r <= cdf[1] ) {
|
|
516
|
+
} else if ( r <= cdf[1] ) { // specular
|
|
521
517
|
|
|
522
518
|
wi = specularDirection( wo, surf );
|
|
523
519
|
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
524
520
|
|
|
525
|
-
} else if ( r <= cdf[2] ) {
|
|
521
|
+
} else if ( r <= cdf[2] ) { // transmission / refraction
|
|
526
522
|
|
|
527
523
|
wi = transmissionDirection( wo, surf );
|
|
528
524
|
clearcoatWi = normalize( clearcoatInvBasis * normalize( normalBasis * wi ) );
|
|
529
525
|
|
|
530
|
-
} else if ( r <= cdf[3] ) {
|
|
526
|
+
} else if ( r <= cdf[3] ) { // clearcoat
|
|
531
527
|
|
|
532
528
|
clearcoatWi = clearcoatDirection( clearcoatWo, surf );
|
|
533
529
|
wi = normalize( invBasis * normalize( clearcoatNormalBasis * clearcoatWi ) );
|
|
@@ -62,6 +62,10 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
62
62
|
|
|
63
63
|
float specularIntensity;
|
|
64
64
|
int specularIntensityMap;
|
|
65
|
+
bool thinFilm;
|
|
66
|
+
|
|
67
|
+
vec3 attenuationColor;
|
|
68
|
+
float attenuationDistance;
|
|
65
69
|
|
|
66
70
|
int alphaMap;
|
|
67
71
|
|
|
@@ -77,6 +81,9 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
77
81
|
float sheenRoughness;
|
|
78
82
|
int sheenRoughnessMap;
|
|
79
83
|
|
|
84
|
+
bool vertexColors;
|
|
85
|
+
bool transparent;
|
|
86
|
+
|
|
80
87
|
mat3 mapTransform;
|
|
81
88
|
mat3 metalnessMapTransform;
|
|
82
89
|
mat3 roughnessMapTransform;
|
|
@@ -112,7 +119,7 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
112
119
|
|
|
113
120
|
Material readMaterialInfo( sampler2D tex, uint index ) {
|
|
114
121
|
|
|
115
|
-
uint i = index *
|
|
122
|
+
uint i = index * 45u;
|
|
116
123
|
|
|
117
124
|
vec4 s0 = texelFetch1D( tex, i + 0u );
|
|
118
125
|
vec4 s1 = texelFetch1D( tex, i + 1u );
|
|
@@ -128,6 +135,7 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
128
135
|
vec4 s11 = texelFetch1D( tex, i + 11u );
|
|
129
136
|
vec4 s12 = texelFetch1D( tex, i + 12u );
|
|
130
137
|
vec4 s13 = texelFetch1D( tex, i + 13u );
|
|
138
|
+
vec4 s14 = texelFetch1D( tex, i + 14u );
|
|
131
139
|
|
|
132
140
|
Material m;
|
|
133
141
|
m.color = s0.rgb;
|
|
@@ -173,17 +181,23 @@ export const shaderMaterialStructs = /* glsl */ `
|
|
|
173
181
|
|
|
174
182
|
m.specularIntensity = s11.r;
|
|
175
183
|
m.specularIntensityMap = int( round( s11.g ) );
|
|
184
|
+
m.thinFilm = bool( s11.b );
|
|
185
|
+
|
|
186
|
+
m.attenuationColor = s12.rgb;
|
|
187
|
+
m.attenuationDistance = s12.a;
|
|
176
188
|
|
|
177
|
-
m.alphaMap = int( round(
|
|
189
|
+
m.alphaMap = int( round( s13.r ) );
|
|
178
190
|
|
|
179
|
-
m.opacity =
|
|
180
|
-
m.alphaTest =
|
|
181
|
-
m.side =
|
|
191
|
+
m.opacity = s13.g;
|
|
192
|
+
m.alphaTest = s13.b;
|
|
193
|
+
m.side = s13.a;
|
|
182
194
|
|
|
183
|
-
m.matte = bool(
|
|
184
|
-
m.castShadow = ! bool(
|
|
195
|
+
m.matte = bool( s14.r );
|
|
196
|
+
m.castShadow = ! bool( s14.g );
|
|
197
|
+
m.vertexColors = bool( s14.b );
|
|
198
|
+
m.transparent = bool( s14.a );
|
|
185
199
|
|
|
186
|
-
uint firstTextureTransformIdx = i +
|
|
200
|
+
uint firstTextureTransformIdx = i + 15u;
|
|
187
201
|
|
|
188
202
|
m.mapTransform = m.map == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx );
|
|
189
203
|
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export const shaderUtils = /* glsl */`
|
|
2
2
|
|
|
3
|
+
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
|
|
4
|
+
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
|
|
5
|
+
|
|
6
|
+
vec3 ot = - log( attColor ) / attDist;
|
|
7
|
+
return exp( - ot * dist );
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
|
|
4
12
|
float schlickFresnel( float cosine, float f0 ) {
|
|
5
13
|
|
|
@@ -14,10 +22,16 @@ export const shaderUtils = /* glsl */`
|
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
// https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation
|
|
25
|
+
float iorRatioToF0( float iorRatio ) {
|
|
26
|
+
|
|
27
|
+
return pow( ( 1.0 - iorRatio ) / ( 1.0 + iorRatio ), 2.0 );
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
17
31
|
float schlickFresnelFromIor( float cosine, float iorRatio ) {
|
|
18
32
|
|
|
19
33
|
// Schlick approximation
|
|
20
|
-
float r_0 =
|
|
34
|
+
float r_0 = iorRatioToF0( iorRatio );
|
|
21
35
|
return schlickFresnel( cosine, r_0 );
|
|
22
36
|
|
|
23
37
|
}
|
|
@@ -261,7 +275,7 @@ export const shaderUtils = /* glsl */`
|
|
|
261
275
|
|
|
262
276
|
}
|
|
263
277
|
|
|
264
|
-
vec2 square( vec2 t) {
|
|
278
|
+
vec2 square( vec2 t ) {
|
|
265
279
|
|
|
266
280
|
return t * t;
|
|
267
281
|
|