three-gpu-pathtracer 0.0.13 → 0.0.14
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 +981 -961
- package/build/index.module.js +6965 -6508
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +6959 -6505
- 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/index.js +36 -40
- package/src/materials/MaterialBase.js +56 -56
- package/src/materials/{GraphMaterial.js → debug/GraphMaterial.js} +243 -243
- package/src/materials/{AlphaDisplayMaterial.js → fullscreen/AlphaDisplayMaterial.js} +48 -48
- package/src/materials/{BlendMaterial.js → fullscreen/BlendMaterial.js} +67 -67
- package/src/materials/{DenoiseMaterial.js → fullscreen/DenoiseMaterial.js} +142 -142
- package/src/materials/{LambertPathTracingMaterial.js → pathtracing/LambertPathTracingMaterial.js} +296 -285
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +635 -0
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +179 -0
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +81 -0
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +317 -0
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +54 -0
- package/src/materials/{AmbientOcclusionMaterial.js → surface/AmbientOcclusionMaterial.js} +207 -199
- package/src/materials/surface/FogVolumeMaterial.js +23 -0
- package/src/objects/EquirectCamera.js +13 -13
- package/src/objects/PhysicalCamera.js +28 -28
- package/src/objects/PhysicalSpotLight.js +14 -14
- package/src/objects/ShapedAreaLight.js +12 -12
- package/src/shader/bsdf/bsdfSampling.glsl.js +490 -0
- package/src/shader/bsdf/fog.glsl.js +23 -0
- package/src/shader/bsdf/ggx.glsl.js +102 -0
- package/src/shader/bsdf/iridescence.glsl.js +135 -0
- package/src/shader/bsdf/sheen.glsl.js +98 -0
- package/src/shader/{shaderLayerTexelFetchFunctions.js → common/arraySamplerTexelFetch.glsl.js} +25 -25
- package/src/shader/common/bvhAnyHit.glsl.js +76 -0
- package/src/shader/common/fresnel.glsl.js +98 -0
- package/src/shader/common/intersectShapes.glsl.js +62 -0
- package/src/shader/common/math.glsl.js +81 -0
- package/src/shader/common/utils.glsl.js +116 -0
- package/src/shader/{shaderRandFunctions.js → rand/pcg.glsl.js} +57 -57
- package/src/shader/{shaderSobolSampling.js → rand/sobol.glsl.js} +256 -256
- package/src/shader/sampling/equirectSampling.glsl.js +62 -0
- package/src/shader/sampling/lightSampling.glsl.js +223 -0
- package/src/shader/sampling/shapeSampling.glsl.js +86 -0
- package/src/shader/structs/cameraStruct.glsl.js +13 -0
- package/src/shader/structs/equirectStruct.glsl.js +14 -0
- package/src/shader/structs/fogMaterialBvh.glsl.js +62 -0
- package/src/shader/structs/lightsStruct.glsl.js +78 -0
- package/src/shader/{shaderStructs.js → structs/materialStruct.glsl.js} +207 -327
- 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 +277 -273
- 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 -426
- package/src/uniforms/PhysicalCameraUniform.js +36 -36
- package/src/uniforms/RenderTarget2DArray.js +97 -97
- package/src/uniforms/utils.js +30 -30
- package/src/utils/BlurredEnvMapGenerator.js +116 -116
- package/src/utils/GeometryPreparationUtils.js +214 -214
- package/src/utils/IESLoader.js +325 -325
- package/src/utils/SobolNumberMapGenerator.js +80 -80
- package/src/utils/UVUnwrapper.js +101 -101
- package/src/utils/macroify.js +9 -0
- package/src/workers/PathTracingSceneWorker.js +42 -42
- package/src/materials/PhysicalPathTracingMaterial.js +0 -1013
- package/src/shader/shaderBvhAnyHit.js +0 -76
- package/src/shader/shaderEnvMapSampling.js +0 -58
- package/src/shader/shaderGGXFunctions.js +0 -100
- package/src/shader/shaderIridescenceFunctions.js +0 -135
- package/src/shader/shaderLightSampling.js +0 -229
- package/src/shader/shaderMaterialSampling.js +0 -510
- package/src/shader/shaderSheenFunctions.js +0 -98
- package/src/shader/shaderUtils.js +0 -377
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
export const shaderBvhAnyHit = /* glsl */`
|
|
2
|
-
|
|
3
|
-
bool bvhIntersectAnyHit(
|
|
4
|
-
BVH bvh, vec3 rayOrigin, vec3 rayDirection,
|
|
5
|
-
|
|
6
|
-
// output variables
|
|
7
|
-
out float side, out float dist
|
|
8
|
-
) {
|
|
9
|
-
|
|
10
|
-
uvec4 faceIndices;
|
|
11
|
-
vec3 faceNormal;
|
|
12
|
-
vec3 barycoord;
|
|
13
|
-
|
|
14
|
-
// stack needs to be twice as long as the deepest tree we expect because
|
|
15
|
-
// we push both the left and right child onto the stack every traversal
|
|
16
|
-
int ptr = 0;
|
|
17
|
-
uint stack[ 60 ];
|
|
18
|
-
stack[ 0 ] = 0u;
|
|
19
|
-
|
|
20
|
-
float triangleDistance = 1e20;
|
|
21
|
-
while ( ptr > - 1 && ptr < 60 ) {
|
|
22
|
-
|
|
23
|
-
uint currNodeIndex = stack[ ptr ];
|
|
24
|
-
ptr --;
|
|
25
|
-
|
|
26
|
-
// check if we intersect the current bounds
|
|
27
|
-
float boundsHitDistance = intersectsBVHNodeBounds( rayOrigin, rayDirection, bvh, currNodeIndex );
|
|
28
|
-
if ( boundsHitDistance == INFINITY ) {
|
|
29
|
-
|
|
30
|
-
continue;
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
uvec2 boundsInfo = uTexelFetch1D( bvh.bvhContents, currNodeIndex ).xy;
|
|
35
|
-
bool isLeaf = bool( boundsInfo.x & 0xffff0000u );
|
|
36
|
-
|
|
37
|
-
if ( isLeaf ) {
|
|
38
|
-
|
|
39
|
-
uint count = boundsInfo.x & 0x0000ffffu;
|
|
40
|
-
uint offset = boundsInfo.y;
|
|
41
|
-
|
|
42
|
-
bool found = intersectTriangles(
|
|
43
|
-
bvh, rayOrigin, rayDirection, offset, count, triangleDistance,
|
|
44
|
-
faceIndices, faceNormal, barycoord, side, dist
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
if ( found ) {
|
|
48
|
-
|
|
49
|
-
return true;
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
} else {
|
|
54
|
-
|
|
55
|
-
uint leftIndex = currNodeIndex + 1u;
|
|
56
|
-
uint splitAxis = boundsInfo.x & 0x0000ffffu;
|
|
57
|
-
uint rightIndex = boundsInfo.y;
|
|
58
|
-
|
|
59
|
-
// set c2 in the stack so we traverse it later. We need to keep track of a pointer in
|
|
60
|
-
// the stack while we traverse. The second pointer added is the one that will be
|
|
61
|
-
// traversed first
|
|
62
|
-
ptr ++;
|
|
63
|
-
stack[ ptr ] = leftIndex;
|
|
64
|
-
|
|
65
|
-
ptr ++;
|
|
66
|
-
stack[ ptr ] = rightIndex;
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return false;
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
`;
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export const shaderEnvMapSampling = /* glsl */`
|
|
2
|
-
|
|
3
|
-
vec3 sampleEquirectEnvMapColor( vec3 direction, sampler2D map ) {
|
|
4
|
-
|
|
5
|
-
return texture2D( map, equirectDirectionToUv( direction ) ).rgb;
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
float envMapDirectionPdf( vec3 direction ) {
|
|
10
|
-
|
|
11
|
-
vec2 uv = equirectDirectionToUv( direction );
|
|
12
|
-
float theta = uv.y * PI;
|
|
13
|
-
float sinTheta = sin( theta );
|
|
14
|
-
if ( sinTheta == 0.0 ) {
|
|
15
|
-
|
|
16
|
-
return 0.0;
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return 1.0 / ( 2.0 * PI * PI * sinTheta );
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
float sampleEnvMap( EquirectHdrInfo info, vec3 direction, out vec3 color ) {
|
|
25
|
-
|
|
26
|
-
vec2 uv = equirectDirectionToUv( direction );
|
|
27
|
-
color = texture2D( info.map, uv ).rgb;
|
|
28
|
-
|
|
29
|
-
float totalSum = info.totalSumWhole + info.totalSumDecimal;
|
|
30
|
-
float lum = luminance( color );
|
|
31
|
-
ivec2 resolution = textureSize( info.map, 0 );
|
|
32
|
-
float pdf = lum / totalSum;
|
|
33
|
-
|
|
34
|
-
return float( resolution.x * resolution.y ) * pdf * envMapDirectionPdf( direction );
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
float sampleEnvMapProbability( EquirectHdrInfo info, vec2 r, out vec3 color, out vec3 direction ) {
|
|
39
|
-
|
|
40
|
-
// sample env map cdf
|
|
41
|
-
float v = texture2D( info.marginalWeights, vec2( r.x, 0.0 ) ).x;
|
|
42
|
-
float u = texture2D( info.conditionalWeights, vec2( r.y, v ) ).x;
|
|
43
|
-
vec2 uv = vec2( u, v );
|
|
44
|
-
|
|
45
|
-
vec3 derivedDirection = equirectUvToDirection( uv );
|
|
46
|
-
direction = derivedDirection;
|
|
47
|
-
color = texture2D( info.map, uv ).rgb;
|
|
48
|
-
|
|
49
|
-
float totalSum = info.totalSumWhole + info.totalSumDecimal;
|
|
50
|
-
float lum = luminance( color );
|
|
51
|
-
ivec2 resolution = textureSize( info.map, 0 );
|
|
52
|
-
float pdf = lum / totalSum;
|
|
53
|
-
|
|
54
|
-
return float( resolution.x * resolution.y ) * pdf * envMapDirectionPdf( direction );
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
`;
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
export const shaderGGXFunctions = /* glsl */`
|
|
2
|
-
// The GGX functions provide sampling and distribution information for normals as output so
|
|
3
|
-
// in order to get probability of scatter direction the half vector must be computed and provided.
|
|
4
|
-
// [0] https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
|
|
5
|
-
// [1] https://hal.archives-ouvertes.fr/hal-01509746/document
|
|
6
|
-
// [2] http://jcgt.org/published/0007/04/01/
|
|
7
|
-
// [4] http://jcgt.org/published/0003/02/03/
|
|
8
|
-
|
|
9
|
-
// trowbridge-reitz === GGX === GTR
|
|
10
|
-
|
|
11
|
-
vec3 ggxDirection( vec3 incidentDir, vec2 roughness, vec2 uv ) {
|
|
12
|
-
|
|
13
|
-
// TODO: try GGXVNDF implementation from reference [2], here. Needs to update ggxDistribution
|
|
14
|
-
// function below, as well
|
|
15
|
-
|
|
16
|
-
// Implementation from reference [1]
|
|
17
|
-
// stretch view
|
|
18
|
-
vec3 V = normalize( vec3( roughness * incidentDir.xy, incidentDir.z ) );
|
|
19
|
-
|
|
20
|
-
// orthonormal basis
|
|
21
|
-
vec3 T1 = ( V.z < 0.9999 ) ? normalize( cross( V, vec3( 0.0, 0.0, 1.0 ) ) ) : vec3( 1.0, 0.0, 0.0 );
|
|
22
|
-
vec3 T2 = cross( T1, V );
|
|
23
|
-
|
|
24
|
-
// sample point with polar coordinates (r, phi)
|
|
25
|
-
float a = 1.0 / ( 1.0 + V.z );
|
|
26
|
-
float r = sqrt( uv.x );
|
|
27
|
-
float phi = ( uv.y < a ) ? uv.y / a * PI : PI + ( uv.y - a ) / ( 1.0 - a ) * PI;
|
|
28
|
-
float P1 = r * cos( phi );
|
|
29
|
-
float P2 = r * sin( phi ) * ( ( uv.y < a ) ? 1.0 : V.z );
|
|
30
|
-
|
|
31
|
-
// compute normal
|
|
32
|
-
vec3 N = P1 * T1 + P2 * T2 + V * sqrt( max( 0.0, 1.0 - P1 * P1 - P2 * P2 ) );
|
|
33
|
-
|
|
34
|
-
// unstretch
|
|
35
|
-
N = normalize( vec3( roughness * N.xy, max( 0.0, N.z ) ) );
|
|
36
|
-
|
|
37
|
-
return N;
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Below are PDF and related functions for use in a Monte Carlo path tracer
|
|
42
|
-
// as specified in Appendix B of the following paper
|
|
43
|
-
// See equation (34) from reference [0]
|
|
44
|
-
float ggxLamda( float theta, float roughness ) {
|
|
45
|
-
|
|
46
|
-
float tanTheta = tan( theta );
|
|
47
|
-
float tanTheta2 = tanTheta * tanTheta;
|
|
48
|
-
float alpha2 = roughness * roughness;
|
|
49
|
-
|
|
50
|
-
float numerator = - 1.0 + sqrt( 1.0 + alpha2 * tanTheta2 );
|
|
51
|
-
return numerator / 2.0;
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// See equation (34) from reference [0]
|
|
56
|
-
float ggxShadowMaskG1( float theta, float roughness ) {
|
|
57
|
-
|
|
58
|
-
return 1.0 / ( 1.0 + ggxLamda( theta, roughness ) );
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// See equation (125) from reference [4]
|
|
63
|
-
float ggxShadowMaskG2( vec3 wi, vec3 wo, float roughness ) {
|
|
64
|
-
|
|
65
|
-
float incidentTheta = acos( wi.z );
|
|
66
|
-
float scatterTheta = acos( wo.z );
|
|
67
|
-
return 1.0 / ( 1.0 + ggxLamda( incidentTheta, roughness ) + ggxLamda( scatterTheta, roughness ) );
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// See equation (33) from reference [0]
|
|
72
|
-
float ggxDistribution( vec3 halfVector, float roughness ) {
|
|
73
|
-
|
|
74
|
-
float a2 = roughness * roughness;
|
|
75
|
-
a2 = max( EPSILON, a2 );
|
|
76
|
-
float cosTheta = halfVector.z;
|
|
77
|
-
float cosTheta4 = pow( cosTheta, 4.0 );
|
|
78
|
-
|
|
79
|
-
if ( cosTheta == 0.0 ) return 0.0;
|
|
80
|
-
|
|
81
|
-
float theta = acosSafe( halfVector.z );
|
|
82
|
-
float tanTheta = tan( theta );
|
|
83
|
-
float tanTheta2 = pow( tanTheta, 2.0 );
|
|
84
|
-
|
|
85
|
-
float denom = PI * cosTheta4 * pow( a2 + tanTheta2, 2.0 );
|
|
86
|
-
return ( a2 / denom );
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// See equation (3) from reference [2]
|
|
91
|
-
float ggxPDF( vec3 wi, vec3 halfVector, float roughness ) {
|
|
92
|
-
|
|
93
|
-
float incidentTheta = acos( wi.z );
|
|
94
|
-
float D = ggxDistribution( halfVector, roughness );
|
|
95
|
-
float G1 = ggxShadowMaskG1( incidentTheta, roughness );
|
|
96
|
-
|
|
97
|
-
return D * G1 * max( 0.0, dot( wi, halfVector ) ) / wi.z;
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
`;
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
export const shaderIridescenceFunctions = /* glsl */`
|
|
2
|
-
|
|
3
|
-
// XYZ to sRGB color space
|
|
4
|
-
const mat3 XYZ_TO_REC709 = mat3(
|
|
5
|
-
3.2404542, -0.9692660, 0.0556434,
|
|
6
|
-
-1.5371385, 1.8760108, -0.2040259,
|
|
7
|
-
-0.4985314, 0.0415560, 1.0572252
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
vec3 fresnel0ToIor( vec3 fresnel0 ) {
|
|
11
|
-
|
|
12
|
-
vec3 sqrtF0 = sqrt( fresnel0 );
|
|
13
|
-
return ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Conversion FO/IOR
|
|
18
|
-
vec3 iorToFresnel0( vec3 transmittedIor, float incidentIor ) {
|
|
19
|
-
|
|
20
|
-
return square( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// ior is a value between 1.0 and 3.0. 1.0 is air interface
|
|
25
|
-
float iorToFresnel0( float transmittedIor, float incidentIor ) {
|
|
26
|
-
|
|
27
|
-
return square( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ) );
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Fresnel equations for dielectric/dielectric interfaces. See https://belcour.github.io/blog/research/2017/05/01/brdf-thin-film.html
|
|
32
|
-
vec3 evalSensitivity( float OPD, vec3 shift ) {
|
|
33
|
-
|
|
34
|
-
float phase = 2.0 * PI * OPD * 1.0e-9;
|
|
35
|
-
|
|
36
|
-
vec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );
|
|
37
|
-
vec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );
|
|
38
|
-
vec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );
|
|
39
|
-
|
|
40
|
-
vec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - square( phase ) * var );
|
|
41
|
-
xyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * square( phase ) );
|
|
42
|
-
xyz /= 1.0685e-7;
|
|
43
|
-
|
|
44
|
-
vec3 srgb = XYZ_TO_REC709 * xyz;
|
|
45
|
-
return srgb;
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// See Section 4. Analytic Spectral Integration, A Practical Extension to Microfacet Theory for the Modeling of Varying Iridescence, https://hal.archives-ouvertes.fr/hal-01518344/document
|
|
50
|
-
vec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {
|
|
51
|
-
|
|
52
|
-
vec3 I;
|
|
53
|
-
|
|
54
|
-
// Force iridescenceIor -> outsideIOR when thinFilmThickness -> 0.0
|
|
55
|
-
float iridescenceIor = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );
|
|
56
|
-
|
|
57
|
-
// Evaluate the cosTheta on the base layer (Snell law)
|
|
58
|
-
float sinTheta2Sq = square( outsideIOR / iridescenceIor ) * ( 1.0 - square( cosTheta1 ) );
|
|
59
|
-
|
|
60
|
-
// Handle TIR:
|
|
61
|
-
float cosTheta2Sq = 1.0 - sinTheta2Sq;
|
|
62
|
-
if ( cosTheta2Sq < 0.0 ) {
|
|
63
|
-
|
|
64
|
-
return vec3( 1.0 );
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
float cosTheta2 = sqrt( cosTheta2Sq );
|
|
69
|
-
|
|
70
|
-
// First interface
|
|
71
|
-
float R0 = iorToFresnel0( iridescenceIor, outsideIOR );
|
|
72
|
-
float R12 = schlickFresnel( cosTheta1, R0 );
|
|
73
|
-
float R21 = R12;
|
|
74
|
-
float T121 = 1.0 - R12;
|
|
75
|
-
float phi12 = 0.0;
|
|
76
|
-
if ( iridescenceIor < outsideIOR ) {
|
|
77
|
-
|
|
78
|
-
phi12 = PI;
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
float phi21 = PI - phi12;
|
|
83
|
-
|
|
84
|
-
// Second interface
|
|
85
|
-
vec3 baseIOR = fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) ); // guard against 1.0
|
|
86
|
-
vec3 R1 = iorToFresnel0( baseIOR, iridescenceIor );
|
|
87
|
-
vec3 R23 = schlickFresnel( cosTheta2, R1 );
|
|
88
|
-
vec3 phi23 = vec3( 0.0 );
|
|
89
|
-
if ( baseIOR[0] < iridescenceIor ) {
|
|
90
|
-
|
|
91
|
-
phi23[ 0 ] = PI;
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if ( baseIOR[1] < iridescenceIor ) {
|
|
96
|
-
|
|
97
|
-
phi23[ 1 ] = PI;
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if ( baseIOR[2] < iridescenceIor ) {
|
|
102
|
-
|
|
103
|
-
phi23[ 2 ] = PI;
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Phase shift
|
|
108
|
-
float OPD = 2.0 * iridescenceIor * thinFilmThickness * cosTheta2;
|
|
109
|
-
vec3 phi = vec3( phi21 ) + phi23;
|
|
110
|
-
|
|
111
|
-
// Compound terms
|
|
112
|
-
vec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );
|
|
113
|
-
vec3 r123 = sqrt( R123 );
|
|
114
|
-
vec3 Rs = square( T121 ) * R23 / ( vec3( 1.0 ) - R123 );
|
|
115
|
-
|
|
116
|
-
// Reflectance term for m = 0 (DC term amplitude)
|
|
117
|
-
vec3 C0 = R12 + Rs;
|
|
118
|
-
I = C0;
|
|
119
|
-
|
|
120
|
-
// Reflectance term for m > 0 (pairs of diracs)
|
|
121
|
-
vec3 Cm = Rs - T121;
|
|
122
|
-
for ( int m = 1; m <= 2; ++ m ) {
|
|
123
|
-
|
|
124
|
-
Cm *= r123;
|
|
125
|
-
vec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );
|
|
126
|
-
I += Cm * Sm;
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Since out of gamut colors might be produced, negative color values are clamped to 0.
|
|
131
|
-
return max( I, vec3( 0.0 ) );
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
`;
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
export const shaderLightSampling = /* glsl */`
|
|
2
|
-
|
|
3
|
-
float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {
|
|
4
|
-
|
|
5
|
-
return smoothstep( coneCosine, penumbraCosine, angleCosine );
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
|
|
10
|
-
|
|
11
|
-
// based upon Frostbite 3 Moving to Physically-based Rendering
|
|
12
|
-
// page 32, equation 26: E[window1]
|
|
13
|
-
// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
|
|
14
|
-
float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), EPSILON );
|
|
15
|
-
|
|
16
|
-
if ( cutoffDistance > 0.0 ) {
|
|
17
|
-
|
|
18
|
-
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return distanceFalloff;
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
float getPhotometricAttenuation( sampler2DArray iesProfiles, int iesProfile, vec3 posToLight, vec3 lightDir, vec3 u, vec3 v ) {
|
|
27
|
-
|
|
28
|
-
float cosTheta = dot( posToLight, lightDir );
|
|
29
|
-
float angle = acos( cosTheta ) * ( 1.0 / PI );
|
|
30
|
-
|
|
31
|
-
return texture2D( iesProfiles, vec3( 0.0, angle, iesProfile ) ).r;
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
struct LightSampleRec {
|
|
36
|
-
|
|
37
|
-
bool hit;
|
|
38
|
-
float dist;
|
|
39
|
-
vec3 direction;
|
|
40
|
-
float pdf;
|
|
41
|
-
vec3 emission;
|
|
42
|
-
int type;
|
|
43
|
-
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
LightSampleRec lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection ) {
|
|
47
|
-
|
|
48
|
-
LightSampleRec lightSampleRec;
|
|
49
|
-
lightSampleRec.hit = false;
|
|
50
|
-
|
|
51
|
-
uint l;
|
|
52
|
-
for ( l = 0u; l < lightCount; l ++ ) {
|
|
53
|
-
|
|
54
|
-
Light light = readLightInfo( lights, l );
|
|
55
|
-
|
|
56
|
-
vec3 u = light.u;
|
|
57
|
-
vec3 v = light.v;
|
|
58
|
-
|
|
59
|
-
// check for backface
|
|
60
|
-
vec3 normal = normalize( cross( u, v ) );
|
|
61
|
-
if ( dot( normal, rayDirection ) < 0.0 ) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
u *= 1.0 / dot( u, u );
|
|
66
|
-
v *= 1.0 / dot( v, v );
|
|
67
|
-
|
|
68
|
-
float dist;
|
|
69
|
-
|
|
70
|
-
// MIS / light intersection is not supported for punctual lights.
|
|
71
|
-
if(
|
|
72
|
-
( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
|
|
73
|
-
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
74
|
-
) {
|
|
75
|
-
|
|
76
|
-
if ( dist < lightSampleRec.dist || ! lightSampleRec.hit ) {
|
|
77
|
-
|
|
78
|
-
float cosTheta = dot( rayDirection, normal );
|
|
79
|
-
|
|
80
|
-
lightSampleRec.hit = true;
|
|
81
|
-
lightSampleRec.dist = dist;
|
|
82
|
-
lightSampleRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
83
|
-
lightSampleRec.emission = light.color * light.intensity;
|
|
84
|
-
lightSampleRec.direction = rayDirection;
|
|
85
|
-
lightSampleRec.type = light.type;
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return lightSampleRec;
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
LightSampleRec randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
|
|
98
|
-
|
|
99
|
-
LightSampleRec lightSampleRec;
|
|
100
|
-
lightSampleRec.hit = true;
|
|
101
|
-
lightSampleRec.type = light.type;
|
|
102
|
-
|
|
103
|
-
lightSampleRec.emission = light.color * light.intensity;
|
|
104
|
-
|
|
105
|
-
vec3 randomPos;
|
|
106
|
-
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
107
|
-
|
|
108
|
-
// rectangular area light
|
|
109
|
-
randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
|
|
110
|
-
|
|
111
|
-
} else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
|
|
112
|
-
|
|
113
|
-
// circular area light
|
|
114
|
-
float r = 0.5 * sqrt( ruv.x );
|
|
115
|
-
float theta = ruv.y * 2.0 * PI;
|
|
116
|
-
float x = r * cos( theta );
|
|
117
|
-
float y = r * sin( theta );
|
|
118
|
-
|
|
119
|
-
randomPos = light.position + light.u * x + light.v * y;
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
vec3 toLight = randomPos - rayOrigin;
|
|
124
|
-
float lightDistSq = dot( toLight, toLight );
|
|
125
|
-
lightSampleRec.dist = sqrt( lightDistSq );
|
|
126
|
-
|
|
127
|
-
vec3 direction = toLight / lightSampleRec.dist;
|
|
128
|
-
lightSampleRec.direction = direction;
|
|
129
|
-
|
|
130
|
-
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
131
|
-
lightSampleRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
132
|
-
|
|
133
|
-
return lightSampleRec;
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
LightSampleRec randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {
|
|
138
|
-
|
|
139
|
-
float radius = light.radius * sqrt( ruv.x );
|
|
140
|
-
float theta = ruv.y * 2.0 * PI;
|
|
141
|
-
float x = radius * cos( theta );
|
|
142
|
-
float y = radius * sin( theta );
|
|
143
|
-
|
|
144
|
-
vec3 u = light.u;
|
|
145
|
-
vec3 v = light.v;
|
|
146
|
-
vec3 normal = normalize( cross( u, v ) );
|
|
147
|
-
|
|
148
|
-
float angle = acos( light.coneCos );
|
|
149
|
-
float angleTan = tan( angle );
|
|
150
|
-
float startDistance = light.radius / max( angleTan, EPSILON );
|
|
151
|
-
|
|
152
|
-
vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
|
|
153
|
-
vec3 toLight = randomPos - rayOrigin;
|
|
154
|
-
float lightDistSq = dot( toLight, toLight );
|
|
155
|
-
float dist = sqrt( lightDistSq );
|
|
156
|
-
|
|
157
|
-
vec3 direction = toLight / max( dist, EPSILON );
|
|
158
|
-
float cosTheta = dot( direction, normal );
|
|
159
|
-
|
|
160
|
-
float spotAttenuation = light.iesProfile != - 1 ?
|
|
161
|
-
getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
|
|
162
|
-
getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
|
|
163
|
-
|
|
164
|
-
float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
|
|
165
|
-
LightSampleRec lightSampleRec;
|
|
166
|
-
lightSampleRec.hit = true;
|
|
167
|
-
lightSampleRec.type = light.type;
|
|
168
|
-
lightSampleRec.dist = dist;
|
|
169
|
-
lightSampleRec.direction = direction;
|
|
170
|
-
lightSampleRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;
|
|
171
|
-
lightSampleRec.pdf = 1.0;
|
|
172
|
-
|
|
173
|
-
return lightSampleRec;
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
LightSampleRec randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
|
|
178
|
-
|
|
179
|
-
// pick a random light
|
|
180
|
-
uint l = uint( ruv.x * float( lightCount ) );
|
|
181
|
-
Light light = readLightInfo( lights, l );
|
|
182
|
-
|
|
183
|
-
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
184
|
-
|
|
185
|
-
return randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
186
|
-
|
|
187
|
-
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
188
|
-
|
|
189
|
-
vec3 lightRay = light.u - rayOrigin;
|
|
190
|
-
float lightDist = length( lightRay );
|
|
191
|
-
float cutoffDistance = light.distance;
|
|
192
|
-
float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
|
|
193
|
-
if ( cutoffDistance > 0.0 ) {
|
|
194
|
-
|
|
195
|
-
distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
LightSampleRec rec;
|
|
200
|
-
rec.hit = true;
|
|
201
|
-
rec.direction = normalize( lightRay );
|
|
202
|
-
rec.dist = length( lightRay );
|
|
203
|
-
rec.pdf = 1.0;
|
|
204
|
-
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
205
|
-
rec.type = light.type;
|
|
206
|
-
return rec;
|
|
207
|
-
|
|
208
|
-
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
209
|
-
|
|
210
|
-
LightSampleRec rec;
|
|
211
|
-
rec.hit = true;
|
|
212
|
-
rec.dist = 1e10;
|
|
213
|
-
rec.direction = light.u;
|
|
214
|
-
rec.pdf = 1.0;
|
|
215
|
-
rec.emission = light.color * light.intensity;
|
|
216
|
-
rec.type = light.type;
|
|
217
|
-
|
|
218
|
-
return rec;
|
|
219
|
-
|
|
220
|
-
} else {
|
|
221
|
-
|
|
222
|
-
// sample the light
|
|
223
|
-
return randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
`;
|