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.
- package/LICENSE +21 -21
- package/README.md +1004 -981
- package/build/index.module.js +7413 -6902
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +7446 -6933
- package/build/index.umd.cjs.map +1 -1
- package/package.json +73 -73
- package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
- package/src/core/MaterialReducer.js +256 -256
- package/src/core/PathTracingRenderer.js +346 -346
- package/src/core/PathTracingSceneGenerator.js +69 -69
- package/src/core/QuiltPathTracingRenderer.js +223 -223
- package/src/detectors/CompatibilityDetector.js +38 -0
- package/src/detectors/MaterialCompileDetector.js +50 -0
- package/src/detectors/PrecisionDetector.js +85 -0
- package/src/detectors/PrecisionMaterial.js +160 -0
- package/src/index.js +40 -36
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/debug/GraphMaterial.js +243 -243
- package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
- package/src/materials/fullscreen/BlendMaterial.js +67 -67
- package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
- package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
- package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
- package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
- package/src/materials/surface/FogVolumeMaterial.js +23 -23
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +42 -28
- package/src/objects/PhysicalSpotLight.js +25 -14
- package/src/objects/ShapedAreaLight.js +22 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
- package/src/shader/bsdf/fog.glsl.js +22 -23
- package/src/shader/bsdf/ggx.glsl.js +102 -102
- package/src/shader/bsdf/iridescence.glsl.js +135 -135
- package/src/shader/bsdf/sheen.glsl.js +98 -98
- package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -76
- package/src/shader/common/fresnel.glsl.js +98 -98
- package/src/shader/common/intersectShapes.glsl.js +62 -62
- package/src/shader/common/math.glsl.js +81 -81
- package/src/shader/common/utils.glsl.js +116 -116
- package/src/shader/rand/pcg.glsl.js +57 -57
- package/src/shader/rand/sobol.glsl.js +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -62
- package/src/shader/sampling/lightSampling.glsl.js +223 -223
- package/src/shader/sampling/shapeSampling.glsl.js +86 -86
- package/src/shader/structs/cameraStruct.glsl.js +13 -13
- package/src/shader/structs/equirectStruct.glsl.js +13 -14
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
- package/src/shader/structs/lightsStruct.glsl.js +78 -78
- package/src/shader/structs/materialStruct.glsl.js +207 -207
- 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 +269 -277
- package/src/uniforms/FloatAttributeTextureArray.js +169 -169
- package/src/uniforms/IESProfilesTexture.js +100 -100
- package/src/uniforms/LightsInfoUniformStruct.js +212 -212
- package/src/uniforms/MaterialsTexture.js +503 -503
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +97 -97
- package/src/uniforms/utils.js +30 -30
- package/src/utils/BlurredEnvMapGenerator.js +116 -116
- package/src/utils/GeometryPreparationUtils.js +214 -214
- package/src/utils/IESLoader.js +325 -325
- package/src/utils/SobolNumberMapGenerator.js +80 -80
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/utils/macroify.js +9 -9
- package/src/workers/PathTracingSceneWorker.js +42 -42
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
export const intersectShapesGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
4
|
-
// falls in the bounds of the rectangle on that same plane.
|
|
5
|
-
// Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
|
|
6
|
-
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
|
|
7
|
-
|
|
8
|
-
float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
9
|
-
|
|
10
|
-
if ( t > EPSILON ) {
|
|
11
|
-
|
|
12
|
-
vec3 p = rayOrigin + rayDirection * t;
|
|
13
|
-
vec3 vi = p - center;
|
|
14
|
-
|
|
15
|
-
// check if p falls inside the rectangle
|
|
16
|
-
float a1 = dot( u, vi );
|
|
17
|
-
if ( abs( a1 ) <= 0.5 ) {
|
|
18
|
-
|
|
19
|
-
float a2 = dot( v, vi );
|
|
20
|
-
if ( abs( a2 ) <= 0.5 ) {
|
|
21
|
-
|
|
22
|
-
dist = t;
|
|
23
|
-
return true;
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
36
|
-
// falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.
|
|
37
|
-
bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
|
|
38
|
-
|
|
39
|
-
float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
40
|
-
|
|
41
|
-
if ( t > EPSILON ) {
|
|
42
|
-
|
|
43
|
-
vec3 hit = rayOrigin + rayDirection * t;
|
|
44
|
-
vec3 vi = hit - position;
|
|
45
|
-
|
|
46
|
-
float a1 = dot( u, vi );
|
|
47
|
-
float a2 = dot( v, vi );
|
|
48
|
-
|
|
49
|
-
if( length( vec2( a1, a2 ) ) <= 0.5 ) {
|
|
50
|
-
|
|
51
|
-
dist = t;
|
|
52
|
-
return true;
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
`;
|
|
1
|
+
export const intersectShapesGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
4
|
+
// falls in the bounds of the rectangle on that same plane.
|
|
5
|
+
// Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
|
|
6
|
+
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
|
|
7
|
+
|
|
8
|
+
float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
9
|
+
|
|
10
|
+
if ( t > EPSILON ) {
|
|
11
|
+
|
|
12
|
+
vec3 p = rayOrigin + rayDirection * t;
|
|
13
|
+
vec3 vi = p - center;
|
|
14
|
+
|
|
15
|
+
// check if p falls inside the rectangle
|
|
16
|
+
float a1 = dot( u, vi );
|
|
17
|
+
if ( abs( a1 ) <= 0.5 ) {
|
|
18
|
+
|
|
19
|
+
float a2 = dot( v, vi );
|
|
20
|
+
if ( abs( a2 ) <= 0.5 ) {
|
|
21
|
+
|
|
22
|
+
dist = t;
|
|
23
|
+
return true;
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return false;
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
36
|
+
// falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.
|
|
37
|
+
bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
|
|
38
|
+
|
|
39
|
+
float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
40
|
+
|
|
41
|
+
if ( t > EPSILON ) {
|
|
42
|
+
|
|
43
|
+
vec3 hit = rayOrigin + rayDirection * t;
|
|
44
|
+
vec3 vi = hit - position;
|
|
45
|
+
|
|
46
|
+
float a1 = dot( u, vi );
|
|
47
|
+
float a2 = dot( v, vi );
|
|
48
|
+
|
|
49
|
+
if( length( vec2( a1, a2 ) ) <= 0.5 ) {
|
|
50
|
+
|
|
51
|
+
dist = t;
|
|
52
|
+
return true;
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return false;
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
`;
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
export const mathGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.
|
|
4
|
-
// This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].
|
|
5
|
-
// For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248
|
|
6
|
-
float acosApprox( float x ) {
|
|
7
|
-
|
|
8
|
-
x = clamp( x, -1.0, 1.0 );
|
|
9
|
-
return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// An acos with input values bound to the range [-1, 1].
|
|
14
|
-
float acosSafe( float x ) {
|
|
15
|
-
|
|
16
|
-
return acos( clamp( x, -1.0, 1.0 ) );
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
float saturateCos( float val ) {
|
|
21
|
-
|
|
22
|
-
return clamp( val, 0.001, 1.0 );
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
float square( float t ) {
|
|
27
|
-
|
|
28
|
-
return t * t;
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
vec2 square( vec2 t ) {
|
|
33
|
-
|
|
34
|
-
return t * t;
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
vec3 square( vec3 t ) {
|
|
39
|
-
|
|
40
|
-
return t * t;
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
vec4 square( vec4 t ) {
|
|
45
|
-
|
|
46
|
-
return t * t;
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
vec2 rotateVector( vec2 v, float t ) {
|
|
51
|
-
|
|
52
|
-
float ac = cos( t );
|
|
53
|
-
float as = sin( t );
|
|
54
|
-
return vec2(
|
|
55
|
-
v.x * ac - v.y * as,
|
|
56
|
-
v.x * as + v.y * ac
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// forms a basis with the normal vector as Z
|
|
62
|
-
mat3 getBasisFromNormal( vec3 normal ) {
|
|
63
|
-
|
|
64
|
-
vec3 other;
|
|
65
|
-
if ( abs( normal.x ) > 0.5 ) {
|
|
66
|
-
|
|
67
|
-
other = vec3( 0.0, 1.0, 0.0 );
|
|
68
|
-
|
|
69
|
-
} else {
|
|
70
|
-
|
|
71
|
-
other = vec3( 1.0, 0.0, 0.0 );
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
vec3 ortho = normalize( cross( normal, other ) );
|
|
76
|
-
vec3 ortho2 = normalize( cross( normal, ortho ) );
|
|
77
|
-
return mat3( ortho2, ortho, normal );
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
`;
|
|
1
|
+
export const mathGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// Fast arccos approximation used to remove banding artifacts caused by numerical errors in acos.
|
|
4
|
+
// This is a cubic Lagrange interpolating polynomial for x = [-1, -1/2, 0, 1/2, 1].
|
|
5
|
+
// For more information see: https://github.com/gkjohnson/three-gpu-pathtracer/pull/171#issuecomment-1152275248
|
|
6
|
+
float acosApprox( float x ) {
|
|
7
|
+
|
|
8
|
+
x = clamp( x, -1.0, 1.0 );
|
|
9
|
+
return ( - 0.69813170079773212 * x * x - 0.87266462599716477 ) * x + 1.5707963267948966;
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// An acos with input values bound to the range [-1, 1].
|
|
14
|
+
float acosSafe( float x ) {
|
|
15
|
+
|
|
16
|
+
return acos( clamp( x, -1.0, 1.0 ) );
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
float saturateCos( float val ) {
|
|
21
|
+
|
|
22
|
+
return clamp( val, 0.001, 1.0 );
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
float square( float t ) {
|
|
27
|
+
|
|
28
|
+
return t * t;
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
vec2 square( vec2 t ) {
|
|
33
|
+
|
|
34
|
+
return t * t;
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
vec3 square( vec3 t ) {
|
|
39
|
+
|
|
40
|
+
return t * t;
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
vec4 square( vec4 t ) {
|
|
45
|
+
|
|
46
|
+
return t * t;
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
vec2 rotateVector( vec2 v, float t ) {
|
|
51
|
+
|
|
52
|
+
float ac = cos( t );
|
|
53
|
+
float as = sin( t );
|
|
54
|
+
return vec2(
|
|
55
|
+
v.x * ac - v.y * as,
|
|
56
|
+
v.x * as + v.y * ac
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// forms a basis with the normal vector as Z
|
|
62
|
+
mat3 getBasisFromNormal( vec3 normal ) {
|
|
63
|
+
|
|
64
|
+
vec3 other;
|
|
65
|
+
if ( abs( normal.x ) > 0.5 ) {
|
|
66
|
+
|
|
67
|
+
other = vec3( 0.0, 1.0, 0.0 );
|
|
68
|
+
|
|
69
|
+
} else {
|
|
70
|
+
|
|
71
|
+
other = vec3( 1.0, 0.0, 0.0 );
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
vec3 ortho = normalize( cross( normal, other ) );
|
|
76
|
+
vec3 ortho2 = normalize( cross( normal, ortho ) );
|
|
77
|
+
return mat3( ortho2, ortho, normal );
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
`;
|
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
export const utilsGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// TODO: possibly this should be renamed something related to material or path tracing logic
|
|
4
|
-
|
|
5
|
-
#ifndef RAY_OFFSET
|
|
6
|
-
#define RAY_OFFSET 1e-4
|
|
7
|
-
#endif
|
|
8
|
-
|
|
9
|
-
// adjust the hit point by the surface normal by a factor of some offset and the
|
|
10
|
-
// maximum component-wise value of the current point to accommodate floating point
|
|
11
|
-
// error as values increase.
|
|
12
|
-
vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {
|
|
13
|
-
|
|
14
|
-
vec3 point = rayOrigin + rayDirection * dist;
|
|
15
|
-
vec3 absPoint = abs( point );
|
|
16
|
-
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
17
|
-
return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
|
|
22
|
-
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
|
|
23
|
-
|
|
24
|
-
vec3 ot = - log( attColor ) / attDist;
|
|
25
|
-
return exp( - ot * dist );
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
vec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {
|
|
30
|
-
|
|
31
|
-
// get the half vector - assuming if the light incident vector is on the other side
|
|
32
|
-
// of the that it's transmissive.
|
|
33
|
-
vec3 h;
|
|
34
|
-
if ( wi.z > 0.0 ) {
|
|
35
|
-
|
|
36
|
-
h = normalize( wi + wo );
|
|
37
|
-
|
|
38
|
-
} else {
|
|
39
|
-
|
|
40
|
-
// Scale by the ior ratio to retrieve the appropriate half vector
|
|
41
|
-
// From Section 2.2 on computing the transmission half vector:
|
|
42
|
-
// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
|
|
43
|
-
h = normalize( wi + wo * eta );
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
h *= sign( h.z );
|
|
48
|
-
return h;
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
vec3 getHalfVector( vec3 a, vec3 b ) {
|
|
53
|
-
|
|
54
|
-
return normalize( a + b );
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray
|
|
59
|
-
// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If
|
|
60
|
-
// we find a ray like that we ignore it to avoid artifacts.
|
|
61
|
-
// This function returns if the direction is on the same side of both planes.
|
|
62
|
-
bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {
|
|
63
|
-
|
|
64
|
-
bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;
|
|
65
|
-
bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;
|
|
66
|
-
return aboveSurfaceNormal == aboveGeometryNormal;
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// ray sampling x and z are swapped to align with expected background view
|
|
71
|
-
vec2 equirectDirectionToUv( vec3 direction ) {
|
|
72
|
-
|
|
73
|
-
// from Spherical.setFromCartesianCoords
|
|
74
|
-
vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );
|
|
75
|
-
uv /= vec2( 2.0 * PI, PI );
|
|
76
|
-
|
|
77
|
-
// apply adjustments to get values in range [0, 1] and y right side up
|
|
78
|
-
uv.x += 0.5;
|
|
79
|
-
uv.y = 1.0 - uv.y;
|
|
80
|
-
return uv;
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
vec3 equirectUvToDirection( vec2 uv ) {
|
|
85
|
-
|
|
86
|
-
// undo above adjustments
|
|
87
|
-
uv.x -= 0.5;
|
|
88
|
-
uv.y = 1.0 - uv.y;
|
|
89
|
-
|
|
90
|
-
// from Vector3.setFromSphericalCoords
|
|
91
|
-
float theta = uv.x * 2.0 * PI;
|
|
92
|
-
float phi = uv.y * PI;
|
|
93
|
-
|
|
94
|
-
float sinPhi = sin( phi );
|
|
95
|
-
|
|
96
|
-
return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// power heuristic for multiple importance sampling
|
|
101
|
-
float misHeuristic( float a, float b ) {
|
|
102
|
-
|
|
103
|
-
float aa = a * a;
|
|
104
|
-
float bb = b * b;
|
|
105
|
-
return aa / ( aa + bb );
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60
|
|
110
|
-
// erichlof/THREE.js-PathTracing-Renderer/
|
|
111
|
-
float tentFilter( float x ) {
|
|
112
|
-
|
|
113
|
-
return x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
`;
|
|
1
|
+
export const utilsGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// TODO: possibly this should be renamed something related to material or path tracing logic
|
|
4
|
+
|
|
5
|
+
#ifndef RAY_OFFSET
|
|
6
|
+
#define RAY_OFFSET 1e-4
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
// adjust the hit point by the surface normal by a factor of some offset and the
|
|
10
|
+
// maximum component-wise value of the current point to accommodate floating point
|
|
11
|
+
// error as values increase.
|
|
12
|
+
vec3 stepRayOrigin( vec3 rayOrigin, vec3 rayDirection, vec3 offset, float dist ) {
|
|
13
|
+
|
|
14
|
+
vec3 point = rayOrigin + rayDirection * dist;
|
|
15
|
+
vec3 absPoint = abs( point );
|
|
16
|
+
float maxPoint = max( absPoint.x, max( absPoint.y, absPoint.z ) );
|
|
17
|
+
return point + offset * ( maxPoint + 1.0 ) * RAY_OFFSET;
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md#attenuation
|
|
22
|
+
vec3 transmissionAttenuation( float dist, vec3 attColor, float attDist ) {
|
|
23
|
+
|
|
24
|
+
vec3 ot = - log( attColor ) / attDist;
|
|
25
|
+
return exp( - ot * dist );
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
vec3 getHalfVector( vec3 wi, vec3 wo, float eta ) {
|
|
30
|
+
|
|
31
|
+
// get the half vector - assuming if the light incident vector is on the other side
|
|
32
|
+
// of the that it's transmissive.
|
|
33
|
+
vec3 h;
|
|
34
|
+
if ( wi.z > 0.0 ) {
|
|
35
|
+
|
|
36
|
+
h = normalize( wi + wo );
|
|
37
|
+
|
|
38
|
+
} else {
|
|
39
|
+
|
|
40
|
+
// Scale by the ior ratio to retrieve the appropriate half vector
|
|
41
|
+
// From Section 2.2 on computing the transmission half vector:
|
|
42
|
+
// https://blog.selfshadow.com/publications/s2015-shading-course/burley/s2015_pbs_disney_bsdf_notes.pdf
|
|
43
|
+
h = normalize( wi + wo * eta );
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
h *= sign( h.z );
|
|
48
|
+
return h;
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
vec3 getHalfVector( vec3 a, vec3 b ) {
|
|
53
|
+
|
|
54
|
+
return normalize( a + b );
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The discrepancy between interpolated surface normal and geometry normal can cause issues when a ray
|
|
59
|
+
// is cast that is on the top side of the geometry normal plane but below the surface normal plane. If
|
|
60
|
+
// we find a ray like that we ignore it to avoid artifacts.
|
|
61
|
+
// This function returns if the direction is on the same side of both planes.
|
|
62
|
+
bool isDirectionValid( vec3 direction, vec3 surfaceNormal, vec3 geometryNormal ) {
|
|
63
|
+
|
|
64
|
+
bool aboveSurfaceNormal = dot( direction, surfaceNormal ) > 0.0;
|
|
65
|
+
bool aboveGeometryNormal = dot( direction, geometryNormal ) > 0.0;
|
|
66
|
+
return aboveSurfaceNormal == aboveGeometryNormal;
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ray sampling x and z are swapped to align with expected background view
|
|
71
|
+
vec2 equirectDirectionToUv( vec3 direction ) {
|
|
72
|
+
|
|
73
|
+
// from Spherical.setFromCartesianCoords
|
|
74
|
+
vec2 uv = vec2( atan( direction.z, direction.x ), acos( direction.y ) );
|
|
75
|
+
uv /= vec2( 2.0 * PI, PI );
|
|
76
|
+
|
|
77
|
+
// apply adjustments to get values in range [0, 1] and y right side up
|
|
78
|
+
uv.x += 0.5;
|
|
79
|
+
uv.y = 1.0 - uv.y;
|
|
80
|
+
return uv;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
vec3 equirectUvToDirection( vec2 uv ) {
|
|
85
|
+
|
|
86
|
+
// undo above adjustments
|
|
87
|
+
uv.x -= 0.5;
|
|
88
|
+
uv.y = 1.0 - uv.y;
|
|
89
|
+
|
|
90
|
+
// from Vector3.setFromSphericalCoords
|
|
91
|
+
float theta = uv.x * 2.0 * PI;
|
|
92
|
+
float phi = uv.y * PI;
|
|
93
|
+
|
|
94
|
+
float sinPhi = sin( phi );
|
|
95
|
+
|
|
96
|
+
return vec3( sinPhi * cos( theta ), cos( phi ), sinPhi * sin( theta ) );
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// power heuristic for multiple importance sampling
|
|
101
|
+
float misHeuristic( float a, float b ) {
|
|
102
|
+
|
|
103
|
+
float aa = a * a;
|
|
104
|
+
float bb = b * b;
|
|
105
|
+
return aa / ( aa + bb );
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// tentFilter from Peter Shirley's 'Realistic Ray Tracing (2nd Edition)' book, pg. 60
|
|
110
|
+
// erichlof/THREE.js-PathTracing-Renderer/
|
|
111
|
+
float tentFilter( float x ) {
|
|
112
|
+
|
|
113
|
+
return x < 0.5 ? sqrt( 2.0 * x ) - 1.0 : 1.0 - sqrt( 2.0 - ( 2.0 * x ) );
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
export const pcgGLSL = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// https://www.shadertoy.com/view/wltcRS
|
|
4
|
-
uvec4 WHITE_NOISE_SEED;
|
|
5
|
-
|
|
6
|
-
void rng_initialize( vec2 p, int frame ) {
|
|
7
|
-
|
|
8
|
-
// white noise seed
|
|
9
|
-
WHITE_NOISE_SEED = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// https://www.pcg-random.org/
|
|
14
|
-
void pcg4d( inout uvec4 v ) {
|
|
15
|
-
|
|
16
|
-
v = v * 1664525u + 1013904223u;
|
|
17
|
-
v.x += v.y * v.w;
|
|
18
|
-
v.y += v.z * v.x;
|
|
19
|
-
v.z += v.x * v.y;
|
|
20
|
-
v.w += v.y * v.z;
|
|
21
|
-
v = v ^ ( v >> 16u );
|
|
22
|
-
v.x += v.y*v.w;
|
|
23
|
-
v.y += v.z*v.x;
|
|
24
|
-
v.z += v.x*v.y;
|
|
25
|
-
v.w += v.y*v.z;
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// returns [ 0, 1 ]
|
|
30
|
-
float rand() {
|
|
31
|
-
|
|
32
|
-
pcg4d( WHITE_NOISE_SEED );
|
|
33
|
-
return float( WHITE_NOISE_SEED.x ) / float( 0xffffffffu );
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
vec2 rand2() {
|
|
38
|
-
|
|
39
|
-
pcg4d( WHITE_NOISE_SEED );
|
|
40
|
-
return vec2( WHITE_NOISE_SEED.xy ) / float(0xffffffffu);
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
vec3 rand3() {
|
|
45
|
-
|
|
46
|
-
pcg4d( WHITE_NOISE_SEED );
|
|
47
|
-
return vec3( WHITE_NOISE_SEED.xyz ) / float( 0xffffffffu );
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
vec4 rand4() {
|
|
52
|
-
|
|
53
|
-
pcg4d( WHITE_NOISE_SEED );
|
|
54
|
-
return vec4( WHITE_NOISE_SEED ) / float( 0xffffffffu );
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
`;
|
|
1
|
+
export const pcgGLSL = /* glsl */`
|
|
2
|
+
|
|
3
|
+
// https://www.shadertoy.com/view/wltcRS
|
|
4
|
+
uvec4 WHITE_NOISE_SEED;
|
|
5
|
+
|
|
6
|
+
void rng_initialize( vec2 p, int frame ) {
|
|
7
|
+
|
|
8
|
+
// white noise seed
|
|
9
|
+
WHITE_NOISE_SEED = uvec4( p, uint( frame ), uint( p.x ) + uint( p.y ) );
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// https://www.pcg-random.org/
|
|
14
|
+
void pcg4d( inout uvec4 v ) {
|
|
15
|
+
|
|
16
|
+
v = v * 1664525u + 1013904223u;
|
|
17
|
+
v.x += v.y * v.w;
|
|
18
|
+
v.y += v.z * v.x;
|
|
19
|
+
v.z += v.x * v.y;
|
|
20
|
+
v.w += v.y * v.z;
|
|
21
|
+
v = v ^ ( v >> 16u );
|
|
22
|
+
v.x += v.y*v.w;
|
|
23
|
+
v.y += v.z*v.x;
|
|
24
|
+
v.z += v.x*v.y;
|
|
25
|
+
v.w += v.y*v.z;
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// returns [ 0, 1 ]
|
|
30
|
+
float rand() {
|
|
31
|
+
|
|
32
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
33
|
+
return float( WHITE_NOISE_SEED.x ) / float( 0xffffffffu );
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
vec2 rand2() {
|
|
38
|
+
|
|
39
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
40
|
+
return vec2( WHITE_NOISE_SEED.xy ) / float(0xffffffffu);
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
vec3 rand3() {
|
|
45
|
+
|
|
46
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
47
|
+
return vec3( WHITE_NOISE_SEED.xyz ) / float( 0xffffffffu );
|
|
48
|
+
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
vec4 rand4() {
|
|
52
|
+
|
|
53
|
+
pcg4d( WHITE_NOISE_SEED );
|
|
54
|
+
return vec4( WHITE_NOISE_SEED ) / float( 0xffffffffu );
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
`;
|