three-gpu-pathtracer 0.0.16 → 0.0.17

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 (38) hide show
  1. package/README.md +3 -1
  2. package/build/index.module.js +248 -198
  3. package/build/index.module.js.map +1 -1
  4. package/build/index.umd.cjs +245 -195
  5. package/build/index.umd.cjs.map +1 -1
  6. package/package.json +5 -6
  7. package/src/core/DynamicPathTracingSceneGenerator.js +8 -3
  8. package/src/core/PathTracingRenderer.js +8 -4
  9. package/src/core/PathTracingSceneGenerator.js +6 -1
  10. package/src/materials/debug/GraphMaterial.js +1 -1
  11. package/src/materials/fullscreen/AlphaDisplayMaterial.js +1 -1
  12. package/src/materials/fullscreen/DenoiseMaterial.js +1 -1
  13. package/src/materials/fullscreen/GradientMapMaterial.js +1 -1
  14. package/src/materials/pathtracing/LambertPathTracingMaterial.js +4 -3
  15. package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +61 -46
  16. package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +2 -11
  17. package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +10 -6
  18. package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +1 -1
  19. package/src/materials/pathtracing/glsl/traceScene.glsl.js +10 -12
  20. package/src/materials/surface/AmbientOcclusionMaterial.js +4 -3
  21. package/src/shader/bsdf/bsdfSampling.glsl.js +7 -7
  22. package/src/shader/common/bvhAnyHit.glsl.js +2 -2
  23. package/src/shader/common/intersectShapes.glsl.js +2 -2
  24. package/src/shader/rand/sobol.glsl.js +3 -3
  25. package/src/shader/sampling/equirectSampling.glsl.js +10 -10
  26. package/src/shader/sampling/lightSampling.glsl.js +30 -37
  27. package/src/shader/structs/fogMaterialBvh.glsl.js +2 -2
  28. package/src/shader/structs/lightsStruct.glsl.js +12 -1
  29. package/src/shader/structs/materialStruct.glsl.js +16 -15
  30. package/src/textures/ProceduralEquirectTexture.js +9 -8
  31. package/src/uniforms/EquirectHdrInfoUniform.js +18 -17
  32. package/src/uniforms/IESProfilesTexture.js +2 -2
  33. package/src/uniforms/LightsInfoUniformStruct.js +4 -2
  34. package/src/uniforms/MaterialsTexture.js +3 -1
  35. package/src/utils/BlurredEnvMapGenerator.js +4 -4
  36. package/src/utils/GeometryPreparationUtils.js +8 -2
  37. package/src/utils/IESLoader.js +7 -5
  38. package/src/utils/TextureUtils.js +15 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-gpu-pathtracer",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "Path tracing renderer and utilities for three.js built on top of three-mesh-bvh.",
5
5
  "module": "src/index.js",
6
6
  "main": "build/index.umd.cjs",
@@ -28,9 +28,6 @@
28
28
  "path",
29
29
  "tracer"
30
30
  ],
31
- "dependencies": {
32
- "three-mesh-bvh": "^0.5.19"
33
- },
34
31
  "devDependencies": {
35
32
  "@lookingglass/webxr": "^0.3.1",
36
33
  "canvas-capture": "^2.0.5",
@@ -44,11 +41,13 @@
44
41
  "puppeteer": "^15.4.0",
45
42
  "rollup": "^2.70.0",
46
43
  "simple-git": "^3.10.0",
47
- "three": "^0.147.0",
44
+ "three": "^0.160.0",
45
+ "three-mesh-bvh": "0.7.0",
48
46
  "yargs": "^17.5.1"
49
47
  },
50
48
  "peerDependencies": {
51
- "three": ">=0.139.2",
49
+ "three": ">=0.151.0",
50
+ "three-mesh-bvh": "0.7.0",
52
51
  "xatlas-web": "^0.1.0"
53
52
  },
54
53
  "scripts": {
@@ -38,7 +38,7 @@ export class DynamicPathTracingSceneGenerator {
38
38
 
39
39
  generate() {
40
40
 
41
- const { objects, staticGeometryGenerator, geometry } = this;
41
+ const { objects, staticGeometryGenerator, geometry, lights } = this;
42
42
  if ( this.bvh === null ) {
43
43
 
44
44
  const attributes = [ 'position', 'normal', 'tangent', 'uv', 'color' ];
@@ -52,9 +52,14 @@ export class DynamicPathTracingSceneGenerator {
52
52
  const normalMapRequired = ! ! c.material.normalMap;
53
53
  setCommonAttributes( c.geometry, { attributes, normalMapRequired } );
54
54
 
55
- } else if ( c.isRectAreaLight || c.isSpotLight ) {
55
+ } else if (
56
+ c.isRectAreaLight ||
57
+ c.isSpotLight ||
58
+ c.isPointLight ||
59
+ c.isDirectionalLight
60
+ ) {
56
61
 
57
- this.lights.push( c );
62
+ lights.push( c );
58
63
 
59
64
  }
60
65
 
@@ -1,4 +1,4 @@
1
- import { RGBAFormat, FloatType, Color, Vector2, WebGLRenderTarget, NoBlending, NormalBlending, Vector4 } from 'three';
1
+ import { RGBAFormat, FloatType, HalfFloatType, Color, Vector2, WebGLRenderTarget, NoBlending, NormalBlending, Vector4 } from 'three';
2
2
  import { FullScreenQuad } from 'three/examples/jsm/postprocessing/Pass.js';
3
3
  import { BlendMaterial } from '../materials/fullscreen/BlendMaterial.js';
4
4
  import { SobolNumberMapGenerator } from '../utils/SobolNumberMapGenerator.js';
@@ -250,18 +250,22 @@ export class PathTracingRenderer {
250
250
  this._currentTile = 0;
251
251
 
252
252
  this._sobolTarget = new SobolNumberMapGenerator().generate( renderer );
253
+
254
+ // will be null if extension not supported
255
+ const floatLinearExtensionSupported = renderer.extensions.get( 'OES_texture_float_linear' );
256
+
253
257
  this._primaryTarget = new WebGLRenderTarget( 1, 1, {
254
258
  format: RGBAFormat,
255
- type: FloatType,
259
+ type: floatLinearExtensionSupported ? FloatType : HalfFloatType,
256
260
  } );
257
261
  this._blendTargets = [
258
262
  new WebGLRenderTarget( 1, 1, {
259
263
  format: RGBAFormat,
260
- type: FloatType,
264
+ type: floatLinearExtensionSupported ? FloatType : HalfFloatType,
261
265
  } ),
262
266
  new WebGLRenderTarget( 1, 1, {
263
267
  format: RGBAFormat,
264
- type: FloatType,
268
+ type: floatLinearExtensionSupported ? FloatType : HalfFloatType,
265
269
  } ),
266
270
  ];
267
271
 
@@ -33,7 +33,12 @@ export class PathTracingSceneGenerator {
33
33
 
34
34
  meshes.push( c );
35
35
 
36
- } else if ( c.isRectAreaLight || c.isSpotLight || c.isDirectionalLight || c.isPointLight ) {
36
+ } else if (
37
+ c.isRectAreaLight ||
38
+ c.isSpotLight ||
39
+ c.isPointLight ||
40
+ c.isDirectionalLight
41
+ ) {
37
42
 
38
43
  lights.push( c );
39
44
 
@@ -198,7 +198,7 @@ export class GraphMaterial extends MaterialBase {
198
198
 
199
199
  }
200
200
 
201
- #include <encodings_fragment>
201
+ #include <colorspace_fragment>
202
202
 
203
203
  }
204
204
 
@@ -37,7 +37,7 @@ export class AlphaDisplayMaterial extends MaterialBase {
37
37
  gl_FragColor = vec4( texture( map, vUv ).a );
38
38
  gl_FragColor.a = 1.0;
39
39
 
40
- #include <encodings_fragment>
40
+ #include <colorspace_fragment>
41
41
 
42
42
  }`
43
43
 
@@ -126,7 +126,7 @@ export class DenoiseMaterial extends MaterialBase {
126
126
 
127
127
  gl_FragColor = smartDeNoise( map, vec2( vUv.x, vUv.y ), sigma, kSigma, threshold );
128
128
  #include <tonemapping_fragment>
129
- #include <encodings_fragment>
129
+ #include <colorspace_fragment>
130
130
  #include <premultiplied_alpha_fragment>
131
131
 
132
132
  }
@@ -69,7 +69,7 @@ export class GradientMapMaterial extends MaterialBase {
69
69
  gl_FragColor.rgb = vec3( mix( minColor, maxColor, t ) );
70
70
  gl_FragColor.a = 1.0;
71
71
 
72
- #include <encodings_fragment>
72
+ #include <colorspace_fragment>
73
73
 
74
74
  }`,
75
75
 
@@ -2,7 +2,7 @@ import { Matrix4, Color } from 'three';
2
2
  import { MaterialBase } from '../MaterialBase.js';
3
3
  import {
4
4
  MeshBVHUniformStruct, FloatVertexAttributeTexture, UIntVertexAttributeTexture,
5
- shaderStructs, shaderIntersectFunction,
5
+ BVHShaderGLSL,
6
6
  } from 'three-mesh-bvh';
7
7
 
8
8
  // uniforms
@@ -85,8 +85,9 @@ export class LambertPathTracingMaterial extends MaterialBase {
85
85
  #include <common>
86
86
  #include <cube_uv_reflection_fragment>
87
87
 
88
- ${ shaderStructs }
89
- ${ shaderIntersectFunction }
88
+ ${ BVHShaderGLSL.common_functions }
89
+ ${ BVHShaderGLSL.bvh_struct_definitions }
90
+ ${ BVHShaderGLSL.bvh_ray_functions }
90
91
 
91
92
  // uniform structs
92
93
  ${ materialStructGLSL }
@@ -2,7 +2,7 @@ import { Matrix4, Vector2 } from 'three';
2
2
  import { MaterialBase } from '../MaterialBase.js';
3
3
  import {
4
4
  MeshBVHUniformStruct, UIntVertexAttributeTexture,
5
- shaderStructs, shaderIntersectFunction,
5
+ BVHShaderGLSL,
6
6
  } from 'three-mesh-bvh';
7
7
 
8
8
  // uniforms
@@ -72,6 +72,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
72
72
  FEATURE_DOF: 1,
73
73
  FEATURE_BACKGROUND_MAP: 0,
74
74
  FEATURE_FOG: 1,
75
+ FEATURE_SOBOL: 0,
75
76
  // 0 = Perspective
76
77
  // 1 = Orthographic
77
78
  // 2 = Equirectangular
@@ -141,13 +142,36 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
141
142
  #include <common>
142
143
 
143
144
  // bvh intersection
144
- ${ shaderStructs }
145
- ${ shaderIntersectFunction }
145
+ ${ BVHShaderGLSL.common_functions }
146
+ ${ BVHShaderGLSL.bvh_struct_definitions }
147
+ ${ BVHShaderGLSL.bvh_ray_functions }
148
+
149
+ // uniform structs
150
+ ${ cameraStructGLSL }
151
+ ${ lightsStructGLSL }
152
+ ${ equirectStructGLSL }
153
+ ${ materialStructGLSL }
146
154
 
147
155
  // random
148
156
  ${ pcgGLSL }
149
- ${ sobolCommonGLSL }
150
- ${ sobolSamplingGLSL }
157
+ #if FEATURE_SOBOL
158
+
159
+ ${ sobolCommonGLSL }
160
+ ${ sobolSamplingGLSL }
161
+
162
+ #else
163
+
164
+ // Using the sobol functions seems to break the the compiler on MacOS
165
+ // - specifically the "sobolReverseBits" function.
166
+ uint sobolPixelIndex = 0u;
167
+ uint sobolPathIndex = 0u;
168
+ uint sobolBounceIndex = 0u;
169
+ float sobol( int v ) { return rand(); }
170
+ vec2 sobol2( int v ) { return rand2(); }
171
+ vec3 sobol3( int v ) { return rand3(); }
172
+ vec4 sobol4( int v ) { return rand4(); }
173
+
174
+ #endif
151
175
 
152
176
  // common
153
177
  ${ arraySamplerTexelFetchGLSL }
@@ -156,20 +180,6 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
156
180
  ${ mathGLSL }
157
181
  ${ intersectShapesGLSL }
158
182
 
159
- // uniform structs
160
- ${ cameraStructGLSL }
161
- ${ lightsStructGLSL }
162
- ${ equirectStructGLSL }
163
- ${ materialStructGLSL }
164
- ${ fogMaterialBvhGLSL }
165
-
166
- // sampling
167
- ${ shapeSamplingGLSL }
168
- ${ bsdfSamplingGLSL }
169
- ${ equirectSamplingGLSL }
170
- ${ lightSamplingGLSL }
171
- ${ fogGLSL }
172
-
173
183
  // environment
174
184
  uniform EquirectHdrInfo envMapInfo;
175
185
  uniform mat4 environmentRotation;
@@ -221,6 +231,14 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
221
231
  mat3 invEnvRotation3x3;
222
232
  float lightsDenom;
223
233
 
234
+ // sampling
235
+ ${ fogMaterialBvhGLSL }
236
+ ${ shapeSamplingGLSL }
237
+ ${ bsdfSamplingGLSL }
238
+ ${ equirectSamplingGLSL }
239
+ ${ lightSamplingGLSL }
240
+ ${ fogGLSL }
241
+
224
242
  float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
225
243
 
226
244
  return clamp(
@@ -260,7 +278,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
260
278
 
261
279
  // init
262
280
  rng_initialize( gl_FragCoord.xy, seed );
263
- sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | uint( gl_FragCoord.y );
281
+ sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | uint( gl_FragCoord.y );
264
282
  sobolPathIndex = uint( seed );
265
283
 
266
284
  // get camera ray
@@ -276,7 +294,6 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
276
294
 
277
295
  // surface results
278
296
  SurfaceHit surfaceHit;
279
- LightRecord lightRec;
280
297
  ScatterRecord scatterRec;
281
298
 
282
299
  // path tracing state
@@ -285,7 +302,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
285
302
  #if FEATURE_FOG
286
303
 
287
304
  state.fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
288
- bvh, ray.origin, - ray.direction,
305
+ ray.origin, - ray.direction,
289
306
  materialIndexAttribute, materials,
290
307
  state.fogMaterial
291
308
  );
@@ -300,44 +317,42 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
300
317
  state.traversals = bounces - i;
301
318
  state.firstRay = i == 0 && state.transmissiveTraversals == transmissiveBounces;
302
319
 
303
- int hitType = traceScene(
304
- ray, bvh, lights, state.fogMaterial,
305
- surfaceHit, lightRec
306
- );
307
-
308
- if ( hitType == LIGHT_HIT ) {
309
-
310
- if ( state.firstRay || state.transmissiveRay ) {
311
-
312
- gl_FragColor.rgb += lightRec.emission * state.throughputColor;
320
+ int hitType = traceScene( ray, state.fogMaterial, surfaceHit );
313
321
 
314
- } else {
315
-
316
- #if FEATURE_MIS
322
+ // check if we intersect any lights and accumulate the light contribution
323
+ // TODO: we can add support for light surface rendering in the else condition if we
324
+ // add the ability to toggle visibility of the the light
325
+ if ( ! state.firstRay && ! state.transmissiveRay ) {
317
326
 
318
- // NOTE: we skip MIS for punctual lights since they are not supported in forward PT case
319
- if ( lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ) {
327
+ LightRecord lightRec;
328
+ float lightDist = hitType == NO_HIT ? INFINITY : surfaceHit.dist;
329
+ for ( uint i = 0u; i < lights.count; i ++ ) {
320
330
 
321
- gl_FragColor.rgb += lightRec.emission * state.throughputColor;
331
+ if (
332
+ intersectLightAtIndex( lights.tex, ray.origin, ray.direction, i, lightRec ) &&
333
+ lightRec.dist < lightDist
334
+ ) {
322
335
 
323
- } else {
336
+ #if FEATURE_MIS
324
337
 
325
338
  // weight the contribution
339
+ // NOTE: Only area lights are supported for forward sampling and can be hit
326
340
  float misWeight = misHeuristic( scatterRec.pdf, lightRec.pdf / lightsDenom );
327
341
  gl_FragColor.rgb += lightRec.emission * state.throughputColor * misWeight;
328
342
 
329
- }
343
+ #else
330
344
 
331
- #else
345
+ gl_FragColor.rgb += lightRec.emission * state.throughputColor;
332
346
 
333
- gl_FragColor.rgb += lightRec.emission * state.throughputColor;
347
+ #endif
334
348
 
335
- #endif
349
+ }
336
350
 
337
351
  }
338
- break;
339
352
 
340
- } else if ( hitType == NO_HIT ) {
353
+ }
354
+
355
+ if ( hitType == NO_HIT ) {
341
356
 
342
357
  if ( state.firstRay || state.transmissiveRay ) {
343
358
 
@@ -350,7 +365,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
350
365
 
351
366
  // get the PDF of the hit envmap point
352
367
  vec3 envColor;
353
- float envPdf = sampleEquirect( envMapInfo, envRotation3x3 * ray.direction, envColor );
368
+ float envPdf = sampleEquirect( envRotation3x3 * ray.direction, envColor );
354
369
  envPdf /= lightsDenom;
355
370
 
356
371
  // and weight the contribution
@@ -3,7 +3,7 @@ export const attenuateHitGLSL = /* glsl */`
3
3
  // step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
4
4
  // returns true if a solid surface was hit
5
5
  bool attenuateHit(
6
- BVH bvh, RenderState state,
6
+ RenderState state,
7
7
  Ray ray, float rayDist,
8
8
  out vec3 color
9
9
  ) {
@@ -17,7 +17,6 @@ export const attenuateHitGLSL = /* glsl */`
17
17
 
18
18
  // hit results
19
19
  SurfaceHit surfaceHit;
20
- LightRecord lightRec;
21
20
 
22
21
  color = vec3( 1.0 );
23
22
 
@@ -25,20 +24,12 @@ export const attenuateHitGLSL = /* glsl */`
25
24
  // and then reset.
26
25
  for ( int i = 0; i < traversals; i ++ ) {
27
26
 
28
- int hitType = traceScene(
29
- ray, bvh, lights, fogMaterial,
30
- surfaceHit, lightRec
31
- );
27
+ int hitType = traceScene( ray, fogMaterial, surfaceHit );
32
28
 
33
29
  if ( hitType == FOG_HIT ) {
34
30
 
35
31
  return true;
36
32
 
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
33
  } else if ( hitType == SURFACE_HIT ) {
43
34
 
44
35
  float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );
@@ -2,6 +2,8 @@ export const directLightContributionGLSL = /*glsl*/`
2
2
 
3
3
  vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {
4
4
 
5
+ vec3 result = vec3( 0.0 );
6
+
5
7
  // uniformly pick a light or environment map
6
8
  if( lightsDenom != 0.0 && sobol( 5 ) < float( lights.count ) / lightsDenom ) {
7
9
 
@@ -23,7 +25,7 @@ export const directLightContributionGLSL = /*glsl*/`
23
25
  if (
24
26
  lightRec.pdf > 0.0 &&
25
27
  isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&
26
- ! attenuateHit( bvh, state, lightRay, lightRec.dist, attenuatedColor )
28
+ ! attenuateHit( state, lightRay, lightRec.dist, attenuatedColor )
27
29
  ) {
28
30
 
29
31
  // get the material pdf
@@ -35,7 +37,7 @@ export const directLightContributionGLSL = /*glsl*/`
35
37
  // weight the direct light contribution
36
38
  float lightPdf = lightRec.pdf / lightsDenom;
37
39
  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;
40
+ result = attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;
39
41
 
40
42
  }
41
43
 
@@ -45,7 +47,7 @@ export const directLightContributionGLSL = /*glsl*/`
45
47
 
46
48
  // find a sample in the environment map to include in the contribution
47
49
  vec3 envColor, envDirection;
48
- float envPdf = sampleEquirectProbability( envMapInfo, sobol2( 7 ), envColor, envDirection );
50
+ float envPdf = sampleEquirectProbability( sobol2( 7 ), envColor, envDirection );
49
51
  envDirection = invEnvRotation3x3 * envDirection;
50
52
 
51
53
  // this env sampling is not set up for transmissive sampling and yields overly bright
@@ -66,7 +68,7 @@ export const directLightContributionGLSL = /*glsl*/`
66
68
  if (
67
69
  envPdf > 0.0 &&
68
70
  isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&
69
- ! attenuateHit( bvh, state, envRay, INFINITY, attenuatedColor )
71
+ ! attenuateHit( state, envRay, INFINITY, attenuatedColor )
70
72
  ) {
71
73
 
72
74
  // get the material pdf
@@ -78,7 +80,7 @@ export const directLightContributionGLSL = /*glsl*/`
78
80
  // weight the direct light contribution
79
81
  envPdf /= lightsDenom;
80
82
  float misWeight = misHeuristic( envPdf, envMaterialPdf );
81
- return attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;
83
+ result = attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;
82
84
 
83
85
  }
84
86
 
@@ -86,7 +88,9 @@ export const directLightContributionGLSL = /*glsl*/`
86
88
 
87
89
  }
88
90
 
89
- return vec3( 0.0 );
91
+ // Function changed to have a single return statement to potentially help with crashes on Mac OS.
92
+ // See issue #470
93
+ return result;
90
94
 
91
95
  }
92
96
 
@@ -6,7 +6,7 @@ export const getSurfaceRecordGLSL = /* glsl */`
6
6
  int getSurfaceRecord(
7
7
  Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,
8
8
  float accumulatedRoughness,
9
- out SurfaceRecord surf
9
+ inout SurfaceRecord surf
10
10
  ) {
11
11
 
12
12
  if ( material.fogVolume ) {
@@ -5,22 +5,26 @@ export const traceSceneGLSL = /* glsl */`
5
5
  #define LIGHT_HIT 2
6
6
  #define FOG_HIT 3
7
7
 
8
+ // Passing the global variable 'lights' into this function caused shader program errors.
9
+ // So global variables like 'lights' and 'bvh' were moved out of the function parameters.
10
+ // For more information, refer to: https://github.com/gkjohnson/three-gpu-pathtracer/pull/457
8
11
  int traceScene(
9
12
 
10
- Ray ray, BVH bvh, LightsInfo lights, Material fogMaterial,
11
- out SurfaceHit surfaceHit, out LightRecord lightRec
13
+ Ray ray, Material fogMaterial, inout SurfaceHit surfaceHit
12
14
 
13
15
  ) {
14
16
 
17
+ int result = NO_HIT;
15
18
  bool hit = bvhIntersectFirstHit( bvh, ray.origin, ray.direction, surfaceHit.faceIndices, surfaceHit.faceNormal, surfaceHit.barycoord, surfaceHit.side, surfaceHit.dist );
16
- bool lightHit = lightsClosestHit( lights.tex, lights.count, ray.origin, ray.direction, lightRec );
17
19
 
18
20
  #if FEATURE_FOG
19
21
 
20
22
  if ( fogMaterial.fogVolume ) {
21
23
 
24
+ // offset the distance so we don't run into issues with particles on the same surface
25
+ // as other objects
22
26
  float particleDist = intersectFogVolume( fogMaterial, sobol( 1 ) );
23
- if ( particleDist + 1e-4 < surfaceHit.dist && ( particleDist + 1e-4 < lightRec.dist || ! lightHit ) ) {
27
+ if ( particleDist + RAY_OFFSET < surfaceHit.dist ) {
24
28
 
25
29
  surfaceHit.side = 1.0;
26
30
  surfaceHit.faceNormal = normalize( - ray.direction );
@@ -33,19 +37,13 @@ export const traceSceneGLSL = /* glsl */`
33
37
 
34
38
  #endif
35
39
 
36
- if ( lightHit && ( lightRec.dist < surfaceHit.dist || ! hit ) ) {
37
-
38
- return LIGHT_HIT;
39
-
40
- }
41
-
42
40
  if ( hit ) {
43
41
 
44
- return SURFACE_HIT;
42
+ result = SURFACE_HIT;
45
43
 
46
44
  }
47
45
 
48
- return NO_HIT;
46
+ return result;
49
47
 
50
48
  }
51
49
 
@@ -1,6 +1,6 @@
1
1
  import { TangentSpaceNormalMap, Vector2 } from 'three';
2
2
  import { MaterialBase } from '../MaterialBase.js';
3
- import { MeshBVHUniformStruct, shaderStructs, shaderIntersectFunction } from 'three-mesh-bvh';
3
+ import { MeshBVHUniformStruct, BVHShaderGLSL } from 'three-mesh-bvh';
4
4
 
5
5
  import { materialStructGLSL } from '../../shader/structs/materialStruct.glsl.js';
6
6
  import { shapeSamplingGLSL } from '../../shader/sampling/shapeSampling.glsl.js';
@@ -97,8 +97,9 @@ export class AmbientOcclusionMaterial extends MaterialBase {
97
97
  #include <cube_uv_reflection_fragment>
98
98
 
99
99
  // bvh
100
- ${ shaderStructs }
101
- ${ shaderIntersectFunction }
100
+ ${ BVHShaderGLSL.common_functions }
101
+ ${ BVHShaderGLSL.bvh_struct_definitions }
102
+ ${ BVHShaderGLSL.bvh_ray_functions }
102
103
 
103
104
  // uniform structs
104
105
  ${ materialStructGLSL }
@@ -80,7 +80,7 @@ export const bsdfSamplingGLSL = /* glsl */`
80
80
  ${ iridescenceGLSL }
81
81
 
82
82
  // diffuse
83
- float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, out vec3 color ) {
83
+ float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
84
84
 
85
85
  // https://schuttejoe.github.io/post/disneybsdf/
86
86
  float fl = schlickFresnel( wi.z, 0.0 );
@@ -111,7 +111,7 @@ export const bsdfSamplingGLSL = /* glsl */`
111
111
  }
112
112
 
113
113
  // specular
114
- float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, out vec3 color ) {
114
+ float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
115
115
 
116
116
  // if roughness is set to 0 then D === NaN which results in black pixels
117
117
  float metalness = surf.metalness;
@@ -158,7 +158,7 @@ export const bsdfSamplingGLSL = /* glsl */`
158
158
 
159
159
  // transmission
160
160
  /*
161
- float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, out vec3 color ) {
161
+ float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
162
162
 
163
163
  // See section 4.2 in https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
164
164
 
@@ -201,7 +201,7 @@ export const bsdfSamplingGLSL = /* glsl */`
201
201
 
202
202
  // TODO: This is just using a basic cosine-weighted specular distribution with an
203
203
  // incorrect PDF value at the moment. Update it to correctly use a GGX distribution
204
- float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, out vec3 color ) {
204
+ float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
205
205
 
206
206
  color = surf.transmission * surf.color;
207
207
 
@@ -292,7 +292,7 @@ export const bsdfSamplingGLSL = /* glsl */`
292
292
  // bsdf
293
293
  void getLobeWeights(
294
294
  vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRecord surf,
295
- out float diffuseWeight, out float specularWeight, out float transmissionWeight, out float clearcoatWeight
295
+ inout float diffuseWeight, inout float specularWeight, inout float transmissionWeight, inout float clearcoatWeight
296
296
  ) {
297
297
 
298
298
  float metalness = surf.metalness;
@@ -316,7 +316,7 @@ export const bsdfSamplingGLSL = /* glsl */`
316
316
 
317
317
  float bsdfEval(
318
318
  vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRecord surf,
319
- float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, out float specularPdf, out vec3 color
319
+ float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, inout float specularPdf, inout vec3 color
320
320
  ) {
321
321
 
322
322
  float metalness = surf.metalness;
@@ -379,7 +379,7 @@ export const bsdfSamplingGLSL = /* glsl */`
379
379
 
380
380
  }
381
381
 
382
- float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, out vec3 color ) {
382
+ float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, inout vec3 color ) {
383
383
 
384
384
  if ( surf.volumeParticle ) {
385
385
 
@@ -1,10 +1,10 @@
1
1
  export const bvhAnyHitGLSL = /* glsl */`
2
2
 
3
3
  bool bvhIntersectAnyHit(
4
- BVH bvh, vec3 rayOrigin, vec3 rayDirection,
4
+ vec3 rayOrigin, vec3 rayDirection,
5
5
 
6
6
  // output variables
7
- out float side, out float dist
7
+ inout float side, inout float dist
8
8
  ) {
9
9
 
10
10
  uvec4 faceIndices;
@@ -3,7 +3,7 @@ export const intersectShapesGLSL = /* glsl */`
3
3
  // Finds the point where the ray intersects the plane defined by u and v and checks if this point
4
4
  // falls in the bounds of the rectangle on that same plane.
5
5
  // Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
6
- bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
6
+ bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
7
7
 
8
8
  float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
9
9
 
@@ -34,7 +34,7 @@ export const intersectShapesGLSL = /* glsl */`
34
34
 
35
35
  // Finds the point where the ray intersects the plane defined by u and v and checks if this point
36
36
  // falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.
37
- bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, out float dist ) {
37
+ bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
38
38
 
39
39
  float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );
40
40
 
@@ -214,9 +214,9 @@ export const sobolSamplingGLSL = /* glsl */`
214
214
 
215
215
  // Seeds
216
216
  uniform sampler2D sobolTexture;
217
- uint sobolPixelIndex;
218
- uint sobolPathIndex;
219
- uint sobolBounceIndex;
217
+ uint sobolPixelIndex = 0u;
218
+ uint sobolPathIndex = 0u;
219
+ uint sobolBounceIndex = 0u;
220
220
 
221
221
  uint sobolGetSeed( uint bounce, uint effect ) {
222
222