three-gpu-pathtracer 0.0.10 → 0.0.12

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 (53) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +886 -886
  3. package/build/index.module.js +6479 -6472
  4. package/build/index.module.js.map +1 -1
  5. package/build/index.umd.cjs +6478 -6470
  6. package/build/index.umd.cjs.map +1 -1
  7. package/package.json +72 -69
  8. package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
  9. package/src/core/MaterialReducer.js +256 -256
  10. package/src/core/PathTracingRenderer.js +275 -275
  11. package/src/core/PathTracingSceneGenerator.js +69 -69
  12. package/src/index.js +39 -39
  13. package/src/materials/AlphaDisplayMaterial.js +48 -48
  14. package/src/materials/AmbientOcclusionMaterial.js +199 -199
  15. package/src/materials/BlendMaterial.js +67 -67
  16. package/src/materials/DenoiseMaterial.js +142 -142
  17. package/src/materials/GraphMaterial.js +243 -243
  18. package/src/materials/LambertPathTracingMaterial.js +285 -285
  19. package/src/materials/MaterialBase.js +56 -56
  20. package/src/materials/PhysicalPathTracingMaterial.js +982 -982
  21. package/src/objects/EquirectCamera.js +13 -13
  22. package/src/objects/PhysicalCamera.js +28 -28
  23. package/src/objects/PhysicalSpotLight.js +14 -14
  24. package/src/objects/ShapedAreaLight.js +12 -12
  25. package/src/shader/shaderBvhAnyHit.js +76 -0
  26. package/src/shader/shaderEnvMapSampling.js +58 -58
  27. package/src/shader/shaderGGXFunctions.js +100 -100
  28. package/src/shader/shaderIridescenceFunctions.js +130 -130
  29. package/src/shader/shaderLayerTexelFetchFunctions.js +25 -25
  30. package/src/shader/shaderLightSampling.js +229 -229
  31. package/src/shader/shaderMaterialSampling.js +506 -498
  32. package/src/shader/shaderRandFunctions.js +57 -57
  33. package/src/shader/shaderSheenFunctions.js +98 -98
  34. package/src/shader/shaderSobolSampling.js +256 -256
  35. package/src/shader/shaderStructs.js +325 -325
  36. package/src/shader/shaderUtils.js +361 -361
  37. package/src/textures/GradientEquirectTexture.js +35 -35
  38. package/src/textures/ProceduralEquirectTexture.js +75 -75
  39. package/src/uniforms/AttributesTextureArray.js +35 -35
  40. package/src/uniforms/EquirectHdrInfoUniform.js +259 -259
  41. package/src/uniforms/FloatAttributeTextureArray.js +169 -169
  42. package/src/uniforms/IESProfilesTexture.js +100 -100
  43. package/src/uniforms/LightsInfoUniformStruct.js +207 -207
  44. package/src/uniforms/MaterialsTexture.js +426 -426
  45. package/src/uniforms/PhysicalCameraUniform.js +36 -36
  46. package/src/uniforms/RenderTarget2DArray.js +97 -97
  47. package/src/uniforms/utils.js +30 -30
  48. package/src/utils/BlurredEnvMapGenerator.js +116 -116
  49. package/src/utils/GeometryPreparationUtils.js +214 -214
  50. package/src/utils/IESLoader.js +325 -325
  51. package/src/utils/SobolNumberMapGenerator.js +80 -80
  52. package/src/utils/UVUnwrapper.js +101 -101
  53. package/src/workers/PathTracingSceneWorker.js +42 -42
@@ -1,13 +1,13 @@
1
- import { Camera } from 'three';
2
-
3
- export class EquirectCamera extends Camera {
4
-
5
- constructor() {
6
-
7
- super();
8
-
9
- this.isEquirectCamera = true;
10
-
11
- }
12
-
13
- }
1
+ import { Camera } from 'three';
2
+
3
+ export class EquirectCamera extends Camera {
4
+
5
+ constructor() {
6
+
7
+ super();
8
+
9
+ this.isEquirectCamera = true;
10
+
11
+ }
12
+
13
+ }
@@ -1,28 +1,28 @@
1
- import { PerspectiveCamera } from 'three';
2
-
3
- export class PhysicalCamera extends PerspectiveCamera {
4
-
5
- set bokehSize( size ) {
6
-
7
- this.fStop = this.getFocalLength() / size;
8
-
9
- }
10
-
11
- get bokehSize() {
12
-
13
- return this.getFocalLength() / this.fStop;
14
-
15
- }
16
-
17
- constructor( ...args ) {
18
-
19
- super( ...args );
20
- this.fStop = 1.4;
21
- this.apertureBlades = 0;
22
- this.apertureRotation = 0;
23
- this.focusDistance = 25;
24
- this.anamorphicRatio = 1;
25
-
26
- }
27
-
28
- }
1
+ import { PerspectiveCamera } from 'three';
2
+
3
+ export class PhysicalCamera extends PerspectiveCamera {
4
+
5
+ set bokehSize( size ) {
6
+
7
+ this.fStop = this.getFocalLength() / size;
8
+
9
+ }
10
+
11
+ get bokehSize() {
12
+
13
+ return this.getFocalLength() / this.fStop;
14
+
15
+ }
16
+
17
+ constructor( ...args ) {
18
+
19
+ super( ...args );
20
+ this.fStop = 1.4;
21
+ this.apertureBlades = 0;
22
+ this.apertureRotation = 0;
23
+ this.focusDistance = 25;
24
+ this.anamorphicRatio = 1;
25
+
26
+ }
27
+
28
+ }
@@ -1,14 +1,14 @@
1
- import { SpotLight } from 'three';
2
-
3
- export class PhysicalSpotLight extends SpotLight {
4
-
5
- constructor( ...args ) {
6
-
7
- super( ...args );
8
-
9
- this.iesTexture = null;
10
- this.radius = 0;
11
-
12
- }
13
-
14
- }
1
+ import { SpotLight } from 'three';
2
+
3
+ export class PhysicalSpotLight extends SpotLight {
4
+
5
+ constructor( ...args ) {
6
+
7
+ super( ...args );
8
+
9
+ this.iesTexture = null;
10
+ this.radius = 0;
11
+
12
+ }
13
+
14
+ }
@@ -1,12 +1,12 @@
1
- import { RectAreaLight } from 'three';
2
-
3
- export class ShapedAreaLight extends RectAreaLight {
4
-
5
- constructor( ...args ) {
6
-
7
- super( ...args );
8
- this.isCircular = false;
9
-
10
- }
11
-
12
- }
1
+ import { RectAreaLight } from 'three';
2
+
3
+ export class ShapedAreaLight extends RectAreaLight {
4
+
5
+ constructor( ...args ) {
6
+
7
+ super( ...args );
8
+ this.isCircular = false;
9
+
10
+ }
11
+
12
+ }
@@ -0,0 +1,76 @@
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 +1,58 @@
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
+ 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 +1,100 @@
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
+ 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
+ `;