three-gpu-pathtracer 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1004 -981
  3. package/build/index.module.js +7413 -6902
  4. package/build/index.module.js.map +1 -1
  5. package/build/index.umd.cjs +7446 -6933
  6. package/build/index.umd.cjs.map +1 -1
  7. package/package.json +73 -73
  8. package/src/core/DynamicPathTracingSceneGenerator.js +119 -119
  9. package/src/core/MaterialReducer.js +256 -256
  10. package/src/core/PathTracingRenderer.js +346 -346
  11. package/src/core/PathTracingSceneGenerator.js +69 -69
  12. package/src/core/QuiltPathTracingRenderer.js +223 -223
  13. package/src/detectors/CompatibilityDetector.js +38 -0
  14. package/src/detectors/MaterialCompileDetector.js +50 -0
  15. package/src/detectors/PrecisionDetector.js +85 -0
  16. package/src/detectors/PrecisionMaterial.js +160 -0
  17. package/src/index.js +40 -36
  18. package/src/materials/MaterialBase.js +56 -56
  19. package/src/materials/debug/GraphMaterial.js +243 -243
  20. package/src/materials/fullscreen/AlphaDisplayMaterial.js +50 -48
  21. package/src/materials/fullscreen/BlendMaterial.js +67 -67
  22. package/src/materials/fullscreen/DenoiseMaterial.js +142 -142
  23. package/src/materials/fullscreen/GradientMapMaterial.js +82 -0
  24. package/src/materials/pathtracing/LambertPathTracingMaterial.js +296 -296
  25. package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +118 -196
  26. package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +177 -179
  27. package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +84 -81
  28. package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +93 -0
  29. package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +323 -317
  30. package/src/materials/pathtracing/glsl/renderStructs.glsl.js +50 -0
  31. package/src/materials/pathtracing/glsl/traceScene.glsl.js +52 -54
  32. package/src/materials/surface/AmbientOcclusionMaterial.js +207 -207
  33. package/src/materials/surface/FogVolumeMaterial.js +23 -23
  34. package/src/objects/EquirectCamera.js +13 -13
  35. package/src/objects/PhysicalCamera.js +42 -28
  36. package/src/objects/PhysicalSpotLight.js +25 -14
  37. package/src/objects/ShapedAreaLight.js +22 -12
  38. package/src/shader/bsdf/bsdfSampling.glsl.js +499 -490
  39. package/src/shader/bsdf/fog.glsl.js +22 -23
  40. package/src/shader/bsdf/ggx.glsl.js +102 -102
  41. package/src/shader/bsdf/iridescence.glsl.js +135 -135
  42. package/src/shader/bsdf/sheen.glsl.js +98 -98
  43. package/src/shader/common/arraySamplerTexelFetch.glsl.js +25 -25
  44. package/src/shader/common/bvhAnyHit.glsl.js +76 -76
  45. package/src/shader/common/fresnel.glsl.js +98 -98
  46. package/src/shader/common/intersectShapes.glsl.js +62 -62
  47. package/src/shader/common/math.glsl.js +81 -81
  48. package/src/shader/common/utils.glsl.js +116 -116
  49. package/src/shader/rand/pcg.glsl.js +57 -57
  50. package/src/shader/rand/sobol.glsl.js +256 -256
  51. package/src/shader/sampling/equirectSampling.glsl.js +62 -62
  52. package/src/shader/sampling/lightSampling.glsl.js +223 -223
  53. package/src/shader/sampling/shapeSampling.glsl.js +86 -86
  54. package/src/shader/structs/cameraStruct.glsl.js +13 -13
  55. package/src/shader/structs/equirectStruct.glsl.js +13 -14
  56. package/src/shader/structs/fogMaterialBvh.glsl.js +62 -62
  57. package/src/shader/structs/lightsStruct.glsl.js +78 -78
  58. package/src/shader/structs/materialStruct.glsl.js +207 -207
  59. package/src/textures/GradientEquirectTexture.js +35 -35
  60. package/src/textures/ProceduralEquirectTexture.js +75 -75
  61. package/src/uniforms/AttributesTextureArray.js +35 -35
  62. package/src/uniforms/EquirectHdrInfoUniform.js +269 -277
  63. package/src/uniforms/FloatAttributeTextureArray.js +169 -169
  64. package/src/uniforms/IESProfilesTexture.js +100 -100
  65. package/src/uniforms/LightsInfoUniformStruct.js +212 -212
  66. package/src/uniforms/MaterialsTexture.js +503 -503
  67. package/src/uniforms/PhysicalCameraUniform.js +36 -36
  68. package/src/uniforms/RenderTarget2DArray.js +97 -97
  69. package/src/uniforms/utils.js +30 -30
  70. package/src/utils/BlurredEnvMapGenerator.js +116 -116
  71. package/src/utils/GeometryPreparationUtils.js +214 -214
  72. package/src/utils/IESLoader.js +325 -325
  73. package/src/utils/SobolNumberMapGenerator.js +80 -80
  74. package/src/utils/UVUnwrapper.js +101 -101
  75. package/src/utils/macroify.js +9 -9
  76. package/src/workers/PathTracingSceneWorker.js +42 -42
@@ -1,223 +1,223 @@
1
- export const lightSamplingGLSL = /* 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 LightSampleRecord {
36
-
37
- float dist;
38
- vec3 direction;
39
- float pdf;
40
- vec3 emission;
41
- int type;
42
-
43
- };
44
-
45
- bool lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection, out LightSampleRecord lightSampleRec ) {
46
-
47
- bool didHit = false;
48
- uint l;
49
- for ( l = 0u; l < lightCount; l ++ ) {
50
-
51
- Light light = readLightInfo( lights, l );
52
-
53
- vec3 u = light.u;
54
- vec3 v = light.v;
55
-
56
- // check for backface
57
- vec3 normal = normalize( cross( u, v ) );
58
- if ( dot( normal, rayDirection ) < 0.0 ) {
59
-
60
- continue;
61
-
62
- }
63
-
64
- u *= 1.0 / dot( u, u );
65
- v *= 1.0 / dot( v, v );
66
-
67
- float dist;
68
-
69
- // MIS / light intersection is not supported for punctual lights.
70
- if(
71
- ( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
72
- ( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
73
- ) {
74
-
75
- if ( ! didHit || dist < lightSampleRec.dist ) {
76
-
77
- float cosTheta = dot( rayDirection, normal );
78
- didHit = true;
79
- lightSampleRec.dist = dist;
80
- lightSampleRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
81
- lightSampleRec.emission = light.color * light.intensity;
82
- lightSampleRec.direction = rayDirection;
83
- lightSampleRec.type = light.type;
84
-
85
- }
86
-
87
- }
88
-
89
- }
90
-
91
- return didHit;
92
-
93
- }
94
-
95
- LightSampleRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
96
-
97
- LightSampleRecord lightSampleRec;
98
- lightSampleRec.type = light.type;
99
-
100
- lightSampleRec.emission = light.color * light.intensity;
101
-
102
- vec3 randomPos;
103
- if( light.type == RECT_AREA_LIGHT_TYPE ) {
104
-
105
- // rectangular area light
106
- randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
107
-
108
- } else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
109
-
110
- // circular area light
111
- float r = 0.5 * sqrt( ruv.x );
112
- float theta = ruv.y * 2.0 * PI;
113
- float x = r * cos( theta );
114
- float y = r * sin( theta );
115
-
116
- randomPos = light.position + light.u * x + light.v * y;
117
-
118
- }
119
-
120
- vec3 toLight = randomPos - rayOrigin;
121
- float lightDistSq = dot( toLight, toLight );
122
- lightSampleRec.dist = sqrt( lightDistSq );
123
-
124
- vec3 direction = toLight / lightSampleRec.dist;
125
- lightSampleRec.direction = direction;
126
-
127
- vec3 lightNormal = normalize( cross( light.u, light.v ) );
128
- lightSampleRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
129
-
130
- return lightSampleRec;
131
-
132
- }
133
-
134
- LightSampleRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {
135
-
136
- float radius = light.radius * sqrt( ruv.x );
137
- float theta = ruv.y * 2.0 * PI;
138
- float x = radius * cos( theta );
139
- float y = radius * sin( theta );
140
-
141
- vec3 u = light.u;
142
- vec3 v = light.v;
143
- vec3 normal = normalize( cross( u, v ) );
144
-
145
- float angle = acos( light.coneCos );
146
- float angleTan = tan( angle );
147
- float startDistance = light.radius / max( angleTan, EPSILON );
148
-
149
- vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
150
- vec3 toLight = randomPos - rayOrigin;
151
- float lightDistSq = dot( toLight, toLight );
152
- float dist = sqrt( lightDistSq );
153
-
154
- vec3 direction = toLight / max( dist, EPSILON );
155
- float cosTheta = dot( direction, normal );
156
-
157
- float spotAttenuation = light.iesProfile != - 1 ?
158
- getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
159
- getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
160
-
161
- float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
162
- LightSampleRecord lightSampleRec;
163
- lightSampleRec.type = light.type;
164
- lightSampleRec.dist = dist;
165
- lightSampleRec.direction = direction;
166
- lightSampleRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;
167
- lightSampleRec.pdf = 1.0;
168
-
169
- return lightSampleRec;
170
-
171
- }
172
-
173
- LightSampleRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
174
-
175
- // pick a random light
176
- uint l = uint( ruv.x * float( lightCount ) );
177
- Light light = readLightInfo( lights, l );
178
-
179
- if ( light.type == SPOT_LIGHT_TYPE ) {
180
-
181
- return randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
182
-
183
- } else if ( light.type == POINT_LIGHT_TYPE ) {
184
-
185
- vec3 lightRay = light.u - rayOrigin;
186
- float lightDist = length( lightRay );
187
- float cutoffDistance = light.distance;
188
- float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
189
- if ( cutoffDistance > 0.0 ) {
190
-
191
- distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
192
-
193
- }
194
-
195
- LightSampleRecord rec;
196
- rec.direction = normalize( lightRay );
197
- rec.dist = length( lightRay );
198
- rec.pdf = 1.0;
199
- rec.emission = light.color * light.intensity * distanceFalloff;
200
- rec.type = light.type;
201
- return rec;
202
-
203
- } else if ( light.type == DIR_LIGHT_TYPE ) {
204
-
205
- LightSampleRecord rec;
206
- rec.dist = 1e10;
207
- rec.direction = light.u;
208
- rec.pdf = 1.0;
209
- rec.emission = light.color * light.intensity;
210
- rec.type = light.type;
211
-
212
- return rec;
213
-
214
- } else {
215
-
216
- // sample the light
217
- return randomAreaLightSample( light, rayOrigin, ruv.yz );
218
-
219
- }
220
-
221
- }
222
-
223
- `;
1
+ export const lightSamplingGLSL = /* 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 LightRecord {
36
+
37
+ float dist;
38
+ vec3 direction;
39
+ float pdf;
40
+ vec3 emission;
41
+ int type;
42
+
43
+ };
44
+
45
+ bool lightsClosestHit( sampler2D lights, uint lightCount, vec3 rayOrigin, vec3 rayDirection, out LightRecord lightRec ) {
46
+
47
+ bool didHit = false;
48
+ uint l;
49
+ for ( l = 0u; l < lightCount; l ++ ) {
50
+
51
+ Light light = readLightInfo( lights, l );
52
+
53
+ vec3 u = light.u;
54
+ vec3 v = light.v;
55
+
56
+ // check for backface
57
+ vec3 normal = normalize( cross( u, v ) );
58
+ if ( dot( normal, rayDirection ) < 0.0 ) {
59
+
60
+ continue;
61
+
62
+ }
63
+
64
+ u *= 1.0 / dot( u, u );
65
+ v *= 1.0 / dot( v, v );
66
+
67
+ float dist;
68
+
69
+ // MIS / light intersection is not supported for punctual lights.
70
+ if(
71
+ ( light.type == RECT_AREA_LIGHT_TYPE && intersectsRectangle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) ) ||
72
+ ( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
73
+ ) {
74
+
75
+ if ( ! didHit || dist < lightRec.dist ) {
76
+
77
+ float cosTheta = dot( rayDirection, normal );
78
+ didHit = true;
79
+ lightRec.dist = dist;
80
+ lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
81
+ lightRec.emission = light.color * light.intensity;
82
+ lightRec.direction = rayDirection;
83
+ lightRec.type = light.type;
84
+
85
+ }
86
+
87
+ }
88
+
89
+ }
90
+
91
+ return didHit;
92
+
93
+ }
94
+
95
+ LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
96
+
97
+ LightRecord lightRec;
98
+ lightRec.type = light.type;
99
+
100
+ lightRec.emission = light.color * light.intensity;
101
+
102
+ vec3 randomPos;
103
+ if( light.type == RECT_AREA_LIGHT_TYPE ) {
104
+
105
+ // rectangular area light
106
+ randomPos = light.position + light.u * ( ruv.x - 0.5 ) + light.v * ( ruv.y - 0.5 );
107
+
108
+ } else if( light.type == CIRC_AREA_LIGHT_TYPE ) {
109
+
110
+ // circular area light
111
+ float r = 0.5 * sqrt( ruv.x );
112
+ float theta = ruv.y * 2.0 * PI;
113
+ float x = r * cos( theta );
114
+ float y = r * sin( theta );
115
+
116
+ randomPos = light.position + light.u * x + light.v * y;
117
+
118
+ }
119
+
120
+ vec3 toLight = randomPos - rayOrigin;
121
+ float lightDistSq = dot( toLight, toLight );
122
+ lightRec.dist = sqrt( lightDistSq );
123
+
124
+ vec3 direction = toLight / lightRec.dist;
125
+ lightRec.direction = direction;
126
+
127
+ vec3 lightNormal = normalize( cross( light.u, light.v ) );
128
+ lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
129
+
130
+ return lightRec;
131
+
132
+ }
133
+
134
+ LightRecord randomSpotLightSample( Light light, sampler2DArray iesProfiles, vec3 rayOrigin, vec2 ruv ) {
135
+
136
+ float radius = light.radius * sqrt( ruv.x );
137
+ float theta = ruv.y * 2.0 * PI;
138
+ float x = radius * cos( theta );
139
+ float y = radius * sin( theta );
140
+
141
+ vec3 u = light.u;
142
+ vec3 v = light.v;
143
+ vec3 normal = normalize( cross( u, v ) );
144
+
145
+ float angle = acos( light.coneCos );
146
+ float angleTan = tan( angle );
147
+ float startDistance = light.radius / max( angleTan, EPSILON );
148
+
149
+ vec3 randomPos = light.position - normal * startDistance + u * x + v * y;
150
+ vec3 toLight = randomPos - rayOrigin;
151
+ float lightDistSq = dot( toLight, toLight );
152
+ float dist = sqrt( lightDistSq );
153
+
154
+ vec3 direction = toLight / max( dist, EPSILON );
155
+ float cosTheta = dot( direction, normal );
156
+
157
+ float spotAttenuation = light.iesProfile != - 1 ?
158
+ getPhotometricAttenuation( iesProfiles, light.iesProfile, direction, normal, u, v ) :
159
+ getSpotAttenuation( light.coneCos, light.penumbraCos, cosTheta );
160
+
161
+ float distanceAttenuation = getDistanceAttenuation( dist, light.distance, light.decay );
162
+ LightRecord lightRec;
163
+ lightRec.type = light.type;
164
+ lightRec.dist = dist;
165
+ lightRec.direction = direction;
166
+ lightRec.emission = light.color * light.intensity * distanceAttenuation * spotAttenuation;
167
+ lightRec.pdf = 1.0;
168
+
169
+ return lightRec;
170
+
171
+ }
172
+
173
+ LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
174
+
175
+ // pick a random light
176
+ uint l = uint( ruv.x * float( lightCount ) );
177
+ Light light = readLightInfo( lights, l );
178
+
179
+ if ( light.type == SPOT_LIGHT_TYPE ) {
180
+
181
+ return randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
182
+
183
+ } else if ( light.type == POINT_LIGHT_TYPE ) {
184
+
185
+ vec3 lightRay = light.u - rayOrigin;
186
+ float lightDist = length( lightRay );
187
+ float cutoffDistance = light.distance;
188
+ float distanceFalloff = 1.0 / max( pow( lightDist, light.decay ), 0.01 );
189
+ if ( cutoffDistance > 0.0 ) {
190
+
191
+ distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDist / cutoffDistance ) ) );
192
+
193
+ }
194
+
195
+ LightRecord rec;
196
+ rec.direction = normalize( lightRay );
197
+ rec.dist = length( lightRay );
198
+ rec.pdf = 1.0;
199
+ rec.emission = light.color * light.intensity * distanceFalloff;
200
+ rec.type = light.type;
201
+ return rec;
202
+
203
+ } else if ( light.type == DIR_LIGHT_TYPE ) {
204
+
205
+ LightRecord rec;
206
+ rec.dist = 1e10;
207
+ rec.direction = light.u;
208
+ rec.pdf = 1.0;
209
+ rec.emission = light.color * light.intensity;
210
+ rec.type = light.type;
211
+
212
+ return rec;
213
+
214
+ } else {
215
+
216
+ // sample the light
217
+ return randomAreaLightSample( light, rayOrigin, ruv.yz );
218
+
219
+ }
220
+
221
+ }
222
+
223
+ `;
@@ -1,86 +1,86 @@
1
- export const shapeSamplingGLSL = /* glsl */`
2
-
3
- vec3 sampleHemisphere( vec3 n, vec2 uv ) {
4
-
5
- // https://www.rorydriscoll.com/2009/01/07/better-sampling/
6
- // https://graphics.pixar.com/library/OrthonormalB/paper.pdf
7
- float sign = n.z == 0.0 ? 1.0 : sign( n.z );
8
- float a = - 1.0 / ( sign + n.z );
9
- float b = n.x * n.y * a;
10
- vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
11
- vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
12
-
13
- float r = sqrt( uv.x );
14
- float theta = 2.0 * PI * uv.y;
15
- float x = r * cos( theta );
16
- float y = r * sin( theta );
17
- return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
18
-
19
- }
20
-
21
- vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {
22
-
23
- // get the edges of the triangle and the diagonal across the
24
- // center of the parallelogram
25
- vec2 e1 = a - b;
26
- vec2 e2 = c - b;
27
- vec2 diag = normalize( e1 + e2 );
28
-
29
- // pick the point in the parallelogram
30
- if ( r.x + r.y > 1.0 ) {
31
-
32
- r = vec2( 1.0 ) - r;
33
-
34
- }
35
-
36
- return e1 * r.x + e2 * r.y;
37
-
38
- }
39
-
40
- vec2 sampleCircle( vec2 uv ) {
41
-
42
- float angle = 2.0 * PI * uv.x;
43
- float radius = sqrt( uv.y );
44
- return vec2( cos( angle ), sin( angle ) ) * radius;
45
-
46
- }
47
-
48
- vec3 sampleSphere( vec2 uv ) {
49
-
50
- float u = ( uv.x - 0.5 ) * 2.0;
51
- float t = uv.y * PI * 2.0;
52
- float f = sqrt( 1.0 - u * u );
53
-
54
- return vec3( f * cos( t ), f * sin( t ), u );
55
-
56
- }
57
-
58
- vec2 sampleRegularPolygon( int sides, vec3 uvw ) {
59
-
60
- sides = max( sides, 3 );
61
-
62
- vec3 r = uvw;
63
- float anglePerSegment = 2.0 * PI / float( sides );
64
- float segment = floor( float( sides ) * r.x );
65
-
66
- float angle1 = anglePerSegment * segment;
67
- float angle2 = angle1 + anglePerSegment;
68
- vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
69
- vec2 b = vec2( 0.0, 0.0 );
70
- vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
71
-
72
- return sampleTriangle( a, b, c, r.yz );
73
-
74
- }
75
-
76
- // samples an aperture shape with the given number of sides. 0 means circle
77
- vec2 sampleAperture( int blades, vec3 uvw ) {
78
-
79
- return blades == 0 ?
80
- sampleCircle( uvw.xy ) :
81
- sampleRegularPolygon( blades, uvw );
82
-
83
- }
84
-
85
-
86
- `;
1
+ export const shapeSamplingGLSL = /* glsl */`
2
+
3
+ vec3 sampleHemisphere( vec3 n, vec2 uv ) {
4
+
5
+ // https://www.rorydriscoll.com/2009/01/07/better-sampling/
6
+ // https://graphics.pixar.com/library/OrthonormalB/paper.pdf
7
+ float sign = n.z == 0.0 ? 1.0 : sign( n.z );
8
+ float a = - 1.0 / ( sign + n.z );
9
+ float b = n.x * n.y * a;
10
+ vec3 b1 = vec3( 1.0 + sign * n.x * n.x * a, sign * b, - sign * n.x );
11
+ vec3 b2 = vec3( b, sign + n.y * n.y * a, - n.y );
12
+
13
+ float r = sqrt( uv.x );
14
+ float theta = 2.0 * PI * uv.y;
15
+ float x = r * cos( theta );
16
+ float y = r * sin( theta );
17
+ return x * b1 + y * b2 + sqrt( 1.0 - uv.x ) * n;
18
+
19
+ }
20
+
21
+ vec2 sampleTriangle( vec2 a, vec2 b, vec2 c, vec2 r ) {
22
+
23
+ // get the edges of the triangle and the diagonal across the
24
+ // center of the parallelogram
25
+ vec2 e1 = a - b;
26
+ vec2 e2 = c - b;
27
+ vec2 diag = normalize( e1 + e2 );
28
+
29
+ // pick the point in the parallelogram
30
+ if ( r.x + r.y > 1.0 ) {
31
+
32
+ r = vec2( 1.0 ) - r;
33
+
34
+ }
35
+
36
+ return e1 * r.x + e2 * r.y;
37
+
38
+ }
39
+
40
+ vec2 sampleCircle( vec2 uv ) {
41
+
42
+ float angle = 2.0 * PI * uv.x;
43
+ float radius = sqrt( uv.y );
44
+ return vec2( cos( angle ), sin( angle ) ) * radius;
45
+
46
+ }
47
+
48
+ vec3 sampleSphere( vec2 uv ) {
49
+
50
+ float u = ( uv.x - 0.5 ) * 2.0;
51
+ float t = uv.y * PI * 2.0;
52
+ float f = sqrt( 1.0 - u * u );
53
+
54
+ return vec3( f * cos( t ), f * sin( t ), u );
55
+
56
+ }
57
+
58
+ vec2 sampleRegularPolygon( int sides, vec3 uvw ) {
59
+
60
+ sides = max( sides, 3 );
61
+
62
+ vec3 r = uvw;
63
+ float anglePerSegment = 2.0 * PI / float( sides );
64
+ float segment = floor( float( sides ) * r.x );
65
+
66
+ float angle1 = anglePerSegment * segment;
67
+ float angle2 = angle1 + anglePerSegment;
68
+ vec2 a = vec2( sin( angle1 ), cos( angle1 ) );
69
+ vec2 b = vec2( 0.0, 0.0 );
70
+ vec2 c = vec2( sin( angle2 ), cos( angle2 ) );
71
+
72
+ return sampleTriangle( a, b, c, r.yz );
73
+
74
+ }
75
+
76
+ // samples an aperture shape with the given number of sides. 0 means circle
77
+ vec2 sampleAperture( int blades, vec3 uvw ) {
78
+
79
+ return blades == 0 ?
80
+ sampleCircle( uvw.xy ) :
81
+ sampleRegularPolygon( blades, uvw );
82
+
83
+ }
84
+
85
+
86
+ `;
@@ -1,13 +1,13 @@
1
- export const cameraStructGLSL = /* glsl */`
2
-
3
- struct PhysicalCamera {
4
-
5
- float focusDistance;
6
- float anamorphicRatio;
7
- float bokehSize;
8
- int apertureBlades;
9
- float apertureRotation;
10
-
11
- };
12
-
13
- `;
1
+ export const cameraStructGLSL = /* glsl */`
2
+
3
+ struct PhysicalCamera {
4
+
5
+ float focusDistance;
6
+ float anamorphicRatio;
7
+ float bokehSize;
8
+ int apertureBlades;
9
+ float apertureRotation;
10
+
11
+ };
12
+
13
+ `;
@@ -1,14 +1,13 @@
1
- export const equirectStructGLSL = /* glsl */`
2
-
3
- struct EquirectHdrInfo {
4
-
5
- sampler2D marginalWeights;
6
- sampler2D conditionalWeights;
7
- sampler2D map;
8
-
9
- float totalSumWhole;
10
- float totalSumDecimal;
11
-
12
- };
13
-
14
- `;
1
+ export const equirectStructGLSL = /* glsl */`
2
+
3
+ struct EquirectHdrInfo {
4
+
5
+ sampler2D marginalWeights;
6
+ sampler2D conditionalWeights;
7
+ sampler2D map;
8
+
9
+ float totalSum;
10
+
11
+ };
12
+
13
+ `;