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,179 +1,177 @@
1
- export const attenuateHitGLSL = /* glsl */`
2
-
3
- // step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
4
- // returns true if a solid surface was hit
5
- bool attenuateHit(
6
- BVH bvh, vec3 rayOrigin, vec3 rayDirection, float rayDist,
7
- int traversals, int transmissiveTraversals, bool isShadowRay,
8
- Material fogMaterial,
9
- out vec3 color
10
- ) {
11
-
12
- vec3 ogRayOrigin = rayOrigin;
13
-
14
- // hit results
15
- uvec4 faceIndices = uvec4( 0u );
16
- vec3 faceNormal = vec3( 0.0, 0.0, 1.0 );
17
- vec3 barycoord = vec3( 0.0 );
18
- float side = 1.0;
19
- float dist = 0.0;
20
- LightSampleRecord lightSampleRec;
21
-
22
- color = vec3( 1.0 );
23
-
24
- // TODO: we should be using sobol sampling here instead of rand but the sobol bounce and path indices need to be incremented
25
- // and then reset.
26
- for ( int i = 0; i < traversals; i ++ ) {
27
-
28
- int hitType = traceScene(
29
- rayOrigin, rayDirection,
30
- bvh, lights, fogMaterial,
31
- faceIndices, faceNormal, barycoord, side, dist,
32
- lightSampleRec
33
- );
34
-
35
- if ( hitType == FOG_HIT ) {
36
-
37
- return true;
38
-
39
- } else if ( hitType == LIGHT_HIT ) {
40
-
41
- float totalDist = distance( ogRayOrigin, rayOrigin + rayDirection * lightSampleRec.dist );
42
- return totalDist < rayDist - max( totalDist, rayDist ) * 1e-4;
43
-
44
- } else if ( hitType == SURFACE_HIT ) {
45
-
46
- float totalDist = distance( ogRayOrigin, rayOrigin + rayDirection * dist );
47
- if ( totalDist > rayDist ) {
48
-
49
- return false;
50
-
51
- }
52
-
53
- // TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
54
- // Should be able to work using the material BSDF functions which will take into account specularity, etc.
55
- // TODO: should we account for emissive surfaces here?
56
-
57
- uint materialIndex = uTexelFetch1D( materialIndexAttribute, faceIndices.x ).r;
58
- Material material = readMaterialInfo( materials, materialIndex );
59
-
60
- // adjust the ray to the new surface
61
- bool isEntering = side == 1.0;
62
- rayOrigin = stepRayOrigin( rayOrigin, rayDirection, - faceNormal, dist );
63
-
64
- #if FEATURE_FOG
65
-
66
- if ( material.fogVolume ) {
67
-
68
- fogMaterial = material;
69
- fogMaterial.fogVolume = side == 1.0;
70
- i -= sign( transmissiveTraversals );
71
- transmissiveTraversals --;
72
- continue;
73
-
74
- }
75
-
76
- #endif
77
-
78
- if ( ! material.castShadow && isShadowRay ) {
79
-
80
- continue;
81
-
82
- }
83
-
84
- vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, barycoord, faceIndices.xyz ).xy;
85
- vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, barycoord, faceIndices.xyz );
86
-
87
- // albedo
88
- vec4 albedo = vec4( material.color, material.opacity );
89
- if ( material.map != - 1 ) {
90
-
91
- vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
92
- albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
93
-
94
- }
95
-
96
- if ( material.vertexColors ) {
97
-
98
- albedo *= vertexColor;
99
-
100
- }
101
-
102
- // alphaMap
103
- if ( material.alphaMap != - 1 ) {
104
-
105
- albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
106
-
107
- }
108
-
109
- // transmission
110
- float transmission = material.transmission;
111
- if ( material.transmissionMap != - 1 ) {
112
-
113
- vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
114
- transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
115
-
116
- }
117
-
118
- // metalness
119
- float metalness = material.metalness;
120
- if ( material.metalnessMap != - 1 ) {
121
-
122
- vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
123
- metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
124
-
125
- }
126
-
127
- float alphaTest = material.alphaTest;
128
- bool useAlphaTest = alphaTest != 0.0;
129
- float transmissionFactor = ( 1.0 - metalness ) * transmission;
130
- if (
131
- transmissionFactor < rand() && ! (
132
- // material sidedness
133
- material.side != 0.0 && side == material.side
134
-
135
- // alpha test
136
- || useAlphaTest && albedo.a < alphaTest
137
-
138
- // opacity
139
- || material.transparent && ! useAlphaTest && albedo.a < rand()
140
- )
141
- ) {
142
-
143
- return true;
144
-
145
- }
146
-
147
- if ( side == 1.0 && isEntering ) {
148
-
149
- // only attenuate by surface color on the way in
150
- color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
151
-
152
- } else if ( side == - 1.0 ) {
153
-
154
- // attenuate by medium once we hit the opposite side of the model
155
- color *= transmissionAttenuation( dist, material.attenuationColor, material.attenuationDistance );
156
-
157
- }
158
-
159
- bool isTransmissiveRay = dot( rayDirection, faceNormal * side ) < 0.0;
160
- if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {
161
-
162
- i -= sign( transmissiveTraversals );
163
- transmissiveTraversals --;
164
-
165
- }
166
-
167
- } else {
168
-
169
- return false;
170
-
171
- }
172
-
173
- }
174
-
175
- return true;
176
-
177
- }
178
-
179
- `;
1
+ export const attenuateHitGLSL = /* glsl */`
2
+
3
+ // step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
4
+ // returns true if a solid surface was hit
5
+ bool attenuateHit(
6
+ BVH bvh, RenderState state,
7
+ Ray ray, float rayDist,
8
+ out vec3 color
9
+ ) {
10
+
11
+ int traversals = state.traversals;
12
+ int transmissiveTraversals = state.transmissiveTraversals;
13
+ bool isShadowRay = state.isShadowRay;
14
+ Material fogMaterial = state.fogMaterial;
15
+
16
+ vec3 startPoint = ray.origin;
17
+
18
+ // hit results
19
+ SurfaceHit surfaceHit;
20
+ LightRecord lightRec;
21
+
22
+ color = vec3( 1.0 );
23
+
24
+ // TODO: we should be using sobol sampling here instead of rand but the sobol bounce and path indices need to be incremented
25
+ // and then reset.
26
+ for ( int i = 0; i < traversals; i ++ ) {
27
+
28
+ int hitType = traceScene(
29
+ ray, bvh, lights, fogMaterial,
30
+ surfaceHit, lightRec
31
+ );
32
+
33
+ if ( hitType == FOG_HIT ) {
34
+
35
+ return true;
36
+
37
+ } else if ( hitType == LIGHT_HIT ) {
38
+
39
+ float totalDist = distance( startPoint, ray.origin + ray.direction * lightRec.dist );
40
+ return totalDist < rayDist - max( totalDist, rayDist ) * 1e-4;
41
+
42
+ } else if ( hitType == SURFACE_HIT ) {
43
+
44
+ float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );
45
+ if ( totalDist > rayDist ) {
46
+
47
+ return false;
48
+
49
+ }
50
+
51
+ // TODO: attenuate the contribution based on the PDF of the resulting ray including refraction values
52
+ // Should be able to work using the material BSDF functions which will take into account specularity, etc.
53
+ // TODO: should we account for emissive surfaces here?
54
+
55
+ uint materialIndex = uTexelFetch1D( materialIndexAttribute, surfaceHit.faceIndices.x ).r;
56
+ Material material = readMaterialInfo( materials, materialIndex );
57
+
58
+ // adjust the ray to the new surface
59
+ bool isEntering = surfaceHit.side == 1.0;
60
+ ray.origin = stepRayOrigin( ray.origin, ray.direction, - surfaceHit.faceNormal, surfaceHit.dist );
61
+
62
+ #if FEATURE_FOG
63
+
64
+ if ( material.fogVolume ) {
65
+
66
+ fogMaterial = material;
67
+ fogMaterial.fogVolume = surfaceHit.side == 1.0;
68
+ i -= sign( transmissiveTraversals );
69
+ transmissiveTraversals --;
70
+ continue;
71
+
72
+ }
73
+
74
+ #endif
75
+
76
+ if ( ! material.castShadow && isShadowRay ) {
77
+
78
+ continue;
79
+
80
+ }
81
+
82
+ vec2 uv = textureSampleBarycoord( attributesArray, ATTR_UV, surfaceHit.barycoord, surfaceHit.faceIndices.xyz ).xy;
83
+ vec4 vertexColor = textureSampleBarycoord( attributesArray, ATTR_COLOR, surfaceHit.barycoord, surfaceHit.faceIndices.xyz );
84
+
85
+ // albedo
86
+ vec4 albedo = vec4( material.color, material.opacity );
87
+ if ( material.map != - 1 ) {
88
+
89
+ vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
90
+ albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
91
+
92
+ }
93
+
94
+ if ( material.vertexColors ) {
95
+
96
+ albedo *= vertexColor;
97
+
98
+ }
99
+
100
+ // alphaMap
101
+ if ( material.alphaMap != - 1 ) {
102
+
103
+ albedo.a *= texture2D( textures, vec3( uv, material.alphaMap ) ).x;
104
+
105
+ }
106
+
107
+ // transmission
108
+ float transmission = material.transmission;
109
+ if ( material.transmissionMap != - 1 ) {
110
+
111
+ vec3 uvPrime = material.transmissionMapTransform * vec3( uv, 1 );
112
+ transmission *= texture2D( textures, vec3( uvPrime.xy, material.transmissionMap ) ).r;
113
+
114
+ }
115
+
116
+ // metalness
117
+ float metalness = material.metalness;
118
+ if ( material.metalnessMap != - 1 ) {
119
+
120
+ vec3 uvPrime = material.metalnessMapTransform * vec3( uv, 1 );
121
+ metalness *= texture2D( textures, vec3( uvPrime.xy, material.metalnessMap ) ).b;
122
+
123
+ }
124
+
125
+ float alphaTest = material.alphaTest;
126
+ bool useAlphaTest = alphaTest != 0.0;
127
+ float transmissionFactor = ( 1.0 - metalness ) * transmission;
128
+ if (
129
+ transmissionFactor < rand() && ! (
130
+ // material sidedness
131
+ material.side != 0.0 && surfaceHit.side == material.side
132
+
133
+ // alpha test
134
+ || useAlphaTest && albedo.a < alphaTest
135
+
136
+ // opacity
137
+ || material.transparent && ! useAlphaTest && albedo.a < rand()
138
+ )
139
+ ) {
140
+
141
+ return true;
142
+
143
+ }
144
+
145
+ if ( surfaceHit.side == 1.0 && isEntering ) {
146
+
147
+ // only attenuate by surface color on the way in
148
+ color *= mix( vec3( 1.0 ), albedo.rgb, transmissionFactor );
149
+
150
+ } else if ( surfaceHit.side == - 1.0 ) {
151
+
152
+ // attenuate by medium once we hit the opposite side of the model
153
+ color *= transmissionAttenuation( surfaceHit.dist, material.attenuationColor, material.attenuationDistance );
154
+
155
+ }
156
+
157
+ bool isTransmissiveRay = dot( ray.direction, surfaceHit.faceNormal * surfaceHit.side ) < 0.0;
158
+ if ( ( isTransmissiveRay || isEntering ) && transmissiveTraversals > 0 ) {
159
+
160
+ i -= sign( transmissiveTraversals );
161
+ transmissiveTraversals --;
162
+
163
+ }
164
+
165
+ } else {
166
+
167
+ return false;
168
+
169
+ }
170
+
171
+ }
172
+
173
+ return true;
174
+
175
+ }
176
+
177
+ `;
@@ -1,81 +1,84 @@
1
- export const cameraUtilsGLSL = /* glsl */`
2
-
3
- vec3 ndcToRayOrigin( vec2 coord ) {
4
-
5
- vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
6
- return rayOrigin4.xyz / rayOrigin4.w;
7
- }
8
-
9
- void getCameraRay( out vec3 rayDirection, out vec3 rayOrigin ) {
10
-
11
- vec2 ssd = vec2( 1.0 ) / resolution;
12
-
13
- // Jitter the camera ray by finding a uv coordinate at a random sample
14
- // around this pixel's UV coordinate for AA
15
- vec2 ruv = sobol2( 0 );
16
- vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
17
-
18
- #if CAMERA_TYPE == 2
19
-
20
- // Equirectangular projection
21
- vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );
22
- vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );
23
-
24
- rayDirection4 = cameraWorldMatrix * rayDirection4;
25
- rayOrigin4 = cameraWorldMatrix * rayOrigin4;
26
-
27
- rayDirection = normalize( rayDirection4.xyz );
28
- rayOrigin = rayOrigin4.xyz / rayOrigin4.w;
29
-
30
- #else
31
-
32
- // get [- 1, 1] normalized device coordinates
33
- vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
34
- rayOrigin = ndcToRayOrigin( ndc );
35
-
36
- #if CAMERA_TYPE == 1
37
-
38
- // Orthographic projection
39
- rayDirection = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
40
- rayDirection = normalize( rayDirection );
41
-
42
- #else
43
-
44
- // Perspective projection
45
- rayDirection = normalize( mat3(cameraWorldMatrix) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );
46
-
47
- #endif
48
-
49
- #endif
50
-
51
- #if FEATURE_DOF
52
- {
53
-
54
- // depth of field
55
- vec3 focalPoint = rayOrigin + normalize( rayDirection ) * physicalCamera.focusDistance;
56
-
57
- // get the aperture sample
58
- // if blades === 0 then we assume a circle
59
- vec3 shapeUVW= sobol3( 1 );
60
- int blades = physicalCamera.apertureBlades;
61
- float anamorphicRatio = physicalCamera.anamorphicRatio;
62
- vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );
63
- apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;
64
-
65
- // rotate the aperture shape
66
- apertureSample =
67
- rotateVector( apertureSample, physicalCamera.apertureRotation ) *
68
- saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );
69
-
70
- // create the new ray
71
- rayOrigin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;
72
- rayDirection = focalPoint - rayOrigin;
73
-
74
- }
75
- #endif
76
-
77
- rayDirection = normalize( rayDirection );
78
-
79
- }
80
-
81
- `;
1
+ export const cameraUtilsGLSL = /* glsl */`
2
+
3
+ vec3 ndcToRayOrigin( vec2 coord ) {
4
+
5
+ vec4 rayOrigin4 = cameraWorldMatrix * invProjectionMatrix * vec4( coord, - 1.0, 1.0 );
6
+ return rayOrigin4.xyz / rayOrigin4.w;
7
+ }
8
+
9
+ Ray getCameraRay() {
10
+
11
+ vec2 ssd = vec2( 1.0 ) / resolution;
12
+
13
+ // Jitter the camera ray by finding a uv coordinate at a random sample
14
+ // around this pixel's UV coordinate for AA
15
+ vec2 ruv = sobol2( 0 );
16
+ vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
17
+ Ray ray;
18
+
19
+ #if CAMERA_TYPE == 2
20
+
21
+ // Equirectangular projection
22
+ vec4 rayDirection4 = vec4( equirectUvToDirection( jitteredUv ), 0.0 );
23
+ vec4 rayOrigin4 = vec4( 0.0, 0.0, 0.0, 1.0 );
24
+
25
+ rayDirection4 = cameraWorldMatrix * rayDirection4;
26
+ rayOrigin4 = cameraWorldMatrix * rayOrigin4;
27
+
28
+ ray.direction = normalize( rayDirection4.xyz );
29
+ ray.origin = rayOrigin4.xyz / rayOrigin4.w;
30
+
31
+ #else
32
+
33
+ // get [- 1, 1] normalized device coordinates
34
+ vec2 ndc = 2.0 * jitteredUv - vec2( 1.0 );
35
+ ray.origin = ndcToRayOrigin( ndc );
36
+
37
+ #if CAMERA_TYPE == 1
38
+
39
+ // Orthographic projection
40
+ ray.direction = ( cameraWorldMatrix * vec4( 0.0, 0.0, - 1.0, 0.0 ) ).xyz;
41
+ ray.direction = normalize( ray.direction );
42
+
43
+ #else
44
+
45
+ // Perspective projection
46
+ ray.direction = normalize( mat3( cameraWorldMatrix ) * ( invProjectionMatrix * vec4( ndc, 0.0, 1.0 ) ).xyz );
47
+
48
+ #endif
49
+
50
+ #endif
51
+
52
+ #if FEATURE_DOF
53
+ {
54
+
55
+ // depth of field
56
+ vec3 focalPoint = ray.origin + normalize( ray.direction ) * physicalCamera.focusDistance;
57
+
58
+ // get the aperture sample
59
+ // if blades === 0 then we assume a circle
60
+ vec3 shapeUVW= sobol3( 1 );
61
+ int blades = physicalCamera.apertureBlades;
62
+ float anamorphicRatio = physicalCamera.anamorphicRatio;
63
+ vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );
64
+ apertureSample *= physicalCamera.bokehSize * 0.5 * 1e-3;
65
+
66
+ // rotate the aperture shape
67
+ apertureSample =
68
+ rotateVector( apertureSample, physicalCamera.apertureRotation ) *
69
+ saturate( vec2( anamorphicRatio, 1.0 / anamorphicRatio ) );
70
+
71
+ // create the new ray
72
+ ray.origin += ( cameraWorldMatrix * vec4( apertureSample, 0.0, 0.0 ) ).xyz;
73
+ ray.direction = focalPoint - ray.origin;
74
+
75
+ }
76
+ #endif
77
+
78
+ ray.direction = normalize( ray.direction );
79
+
80
+ return ray;
81
+
82
+ }
83
+
84
+ `;
@@ -0,0 +1,93 @@
1
+ export const directLightContributionGLSL = /*glsl*/`
2
+
3
+ vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {
4
+
5
+ // uniformly pick a light or environment map
6
+ if( lightsDenom != 0.0 && sobol( 5 ) < float( lights.count ) / lightsDenom ) {
7
+
8
+ // sample a light or environment
9
+ LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, sobol3( 6 ) );
10
+
11
+ bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, lightRec.direction ) < 0.0;
12
+ if ( isSampleBelowSurface ) {
13
+
14
+ lightRec.pdf = 0.0;
15
+
16
+ }
17
+
18
+ // check if a ray could even reach the light area
19
+ Ray lightRay;
20
+ lightRay.origin = rayOrigin;
21
+ lightRay.direction = lightRec.direction;
22
+ vec3 attenuatedColor;
23
+ if (
24
+ lightRec.pdf > 0.0 &&
25
+ isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&
26
+ ! attenuateHit( bvh, state, lightRay, lightRec.dist, attenuatedColor )
27
+ ) {
28
+
29
+ // get the material pdf
30
+ vec3 sampleColor;
31
+ float lightMaterialPdf = bsdfResult( worldWo, lightRec.direction, surf, sampleColor );
32
+ bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
33
+ if ( lightMaterialPdf > 0.0 && isValidSampleColor ) {
34
+
35
+ // weight the direct light contribution
36
+ float lightPdf = lightRec.pdf / lightsDenom;
37
+ float misWeight = lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
38
+ return attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;
39
+
40
+ }
41
+
42
+ }
43
+
44
+ } else {
45
+
46
+ // find a sample in the environment map to include in the contribution
47
+ vec3 envColor, envDirection;
48
+ float envPdf = sampleEquirectProbability( envMapInfo, sobol2( 7 ), envColor, envDirection );
49
+ envDirection = invEnvRotation3x3 * envDirection;
50
+
51
+ // this env sampling is not set up for transmissive sampling and yields overly bright
52
+ // results so we ignore the sample in this case.
53
+ // TODO: this should be improved but how? The env samples could traverse a few layers?
54
+ bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, envDirection ) < 0.0;
55
+ if ( isSampleBelowSurface ) {
56
+
57
+ envPdf = 0.0;
58
+
59
+ }
60
+
61
+ // check if a ray could even reach the surface
62
+ Ray envRay;
63
+ envRay.origin = rayOrigin;
64
+ envRay.direction = envDirection;
65
+ vec3 attenuatedColor;
66
+ if (
67
+ envPdf > 0.0 &&
68
+ isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&
69
+ ! attenuateHit( bvh, state, envRay, INFINITY, attenuatedColor )
70
+ ) {
71
+
72
+ // get the material pdf
73
+ vec3 sampleColor;
74
+ float envMaterialPdf = bsdfResult( worldWo, envDirection, surf, sampleColor );
75
+ bool isValidSampleColor = all( greaterThanEqual( sampleColor, vec3( 0.0 ) ) );
76
+ if ( envMaterialPdf > 0.0 && isValidSampleColor ) {
77
+
78
+ // weight the direct light contribution
79
+ envPdf /= lightsDenom;
80
+ float misWeight = misHeuristic( envPdf, envMaterialPdf );
81
+ return attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;
82
+
83
+ }
84
+
85
+ }
86
+
87
+ }
88
+
89
+ return vec3( 0.0 );
90
+
91
+ }
92
+
93
+ `;