three-gpu-pathtracer 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/build/index.module.js +1202 -471
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +1200 -470
- package/build/index.umd.cjs.map +1 -1
- package/package.json +5 -6
- package/src/core/DynamicPathTracingSceneGenerator.js +80 -35
- package/src/core/PathTracingRenderer.js +36 -38
- package/src/core/PathTracingSceneGenerator.js +11 -55
- package/src/materials/debug/GraphMaterial.js +1 -1
- package/src/materials/fullscreen/AlphaDisplayMaterial.js +1 -1
- package/src/materials/fullscreen/DenoiseMaterial.js +1 -1
- package/src/materials/fullscreen/GradientMapMaterial.js +1 -1
- package/src/materials/pathtracing/LambertPathTracingMaterial.js +5 -4
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +87 -50
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +21 -20
- package/src/materials/pathtracing/glsl/cameraUtils.glsl.js +2 -2
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +12 -8
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +3 -2
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +11 -13
- package/src/materials/surface/AmbientOcclusionMaterial.js +4 -3
- package/src/shader/bsdf/bsdfSampling.glsl.js +21 -17
- package/src/shader/common/bvhAnyHit.glsl.js +2 -2
- package/src/shader/common/fresnel.glsl.js +15 -9
- package/src/shader/common/intersectShapes.glsl.js +2 -2
- package/src/shader/rand/pcg.glsl.js +4 -4
- package/src/shader/rand/sobol.glsl.js +3 -3
- package/src/shader/rand/stratifiedTexture.glsl.js +45 -0
- package/src/shader/sampling/equirectSampling.glsl.js +10 -10
- package/src/shader/sampling/lightSampling.glsl.js +30 -37
- package/src/shader/structs/fogMaterialBvh.glsl.js +2 -2
- package/src/shader/structs/lightsStruct.glsl.js +15 -6
- package/src/shader/structs/materialStruct.glsl.js +16 -15
- package/src/textures/BlueNoiseTexture.js +87 -0
- package/src/textures/ProceduralEquirectTexture.js +6 -6
- package/src/textures/blueNoise/BlueNoiseGenerator.js +115 -0
- package/src/textures/blueNoise/BlueNoiseSamples.js +214 -0
- package/src/textures/blueNoise/utils.js +24 -0
- package/src/uniforms/EquirectHdrInfoUniform.js +59 -21
- package/src/uniforms/IESProfilesTexture.js +2 -2
- package/src/uniforms/LightsInfoUniformStruct.js +15 -9
- package/src/uniforms/MaterialsTexture.js +3 -1
- package/src/uniforms/RenderTarget2DArray.js +50 -3
- package/src/uniforms/StratifiedSamplesTexture.js +49 -0
- package/src/uniforms/stratified/StratifiedSampler.js +73 -0
- package/src/uniforms/stratified/StratifiedSamplerCombined.js +59 -0
- package/src/uniforms/utils.js +1 -1
- package/src/utils/BlurredEnvMapGenerator.js +4 -4
- package/src/utils/GeometryPreparationUtils.js +8 -95
- package/src/utils/IESLoader.js +7 -5
- package/src/utils/TextureUtils.js +15 -0
- package/src/workers/PathTracingSceneWorker.js +18 -8
|
@@ -2,7 +2,7 @@ import { Matrix4, Vector2 } from 'three';
|
|
|
2
2
|
import { MaterialBase } from '../MaterialBase.js';
|
|
3
3
|
import {
|
|
4
4
|
MeshBVHUniformStruct, UIntVertexAttributeTexture,
|
|
5
|
-
|
|
5
|
+
BVHShaderGLSL,
|
|
6
6
|
} from 'three-mesh-bvh';
|
|
7
7
|
|
|
8
8
|
// uniforms
|
|
@@ -48,6 +48,9 @@ import { attenuateHitGLSL } from './glsl/attenuateHit.glsl.js';
|
|
|
48
48
|
import { traceSceneGLSL } from './glsl/traceScene.glsl.js';
|
|
49
49
|
import { getSurfaceRecordGLSL } from './glsl/getSurfaceRecord.glsl.js';
|
|
50
50
|
import { directLightContributionGLSL } from './glsl/directLightContribution.glsl.js';
|
|
51
|
+
import { stratifiedTextureGLSL } from '../../shader/rand/stratifiedTexture.glsl.js';
|
|
52
|
+
import { StratifiedSamplesTexture } from '../../uniforms/StratifiedSamplesTexture.js';
|
|
53
|
+
import { BlueNoiseTexture } from '../../textures/BlueNoiseTexture.js';
|
|
51
54
|
|
|
52
55
|
export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
53
56
|
|
|
@@ -72,6 +75,12 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
72
75
|
FEATURE_DOF: 1,
|
|
73
76
|
FEATURE_BACKGROUND_MAP: 0,
|
|
74
77
|
FEATURE_FOG: 1,
|
|
78
|
+
|
|
79
|
+
// 0 = PCG
|
|
80
|
+
// 1 = Sobol
|
|
81
|
+
// 2 = Stratified List
|
|
82
|
+
RANDOM_TYPE: 2,
|
|
83
|
+
|
|
75
84
|
// 0 = Perspective
|
|
76
85
|
// 1 = Orthographic
|
|
77
86
|
// 2 = Equirectangular
|
|
@@ -113,6 +122,8 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
113
122
|
|
|
114
123
|
backgroundAlpha: { value: 1.0 },
|
|
115
124
|
sobolTexture: { value: null },
|
|
125
|
+
stratifiedTexture: { value: new StratifiedSamplesTexture() },
|
|
126
|
+
stratifiedOffsetTexture: { value: new BlueNoiseTexture( 64, 1 ) },
|
|
116
127
|
},
|
|
117
128
|
|
|
118
129
|
vertexShader: /* glsl */`
|
|
@@ -141,13 +152,48 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
141
152
|
#include <common>
|
|
142
153
|
|
|
143
154
|
// bvh intersection
|
|
144
|
-
${
|
|
145
|
-
${
|
|
155
|
+
${ BVHShaderGLSL.common_functions }
|
|
156
|
+
${ BVHShaderGLSL.bvh_struct_definitions }
|
|
157
|
+
${ BVHShaderGLSL.bvh_ray_functions }
|
|
158
|
+
|
|
159
|
+
// uniform structs
|
|
160
|
+
${ cameraStructGLSL }
|
|
161
|
+
${ lightsStructGLSL }
|
|
162
|
+
${ equirectStructGLSL }
|
|
163
|
+
${ materialStructGLSL }
|
|
146
164
|
|
|
147
165
|
// random
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
166
|
+
#if RANDOM_TYPE == 2 // Stratified List
|
|
167
|
+
|
|
168
|
+
${ stratifiedTextureGLSL }
|
|
169
|
+
|
|
170
|
+
#elif RANDOM_TYPE == 1 // Sobol
|
|
171
|
+
|
|
172
|
+
${ pcgGLSL }
|
|
173
|
+
${ sobolCommonGLSL }
|
|
174
|
+
${ sobolSamplingGLSL }
|
|
175
|
+
|
|
176
|
+
#define rand(v) sobol(v)
|
|
177
|
+
#define rand2(v) sobol2(v)
|
|
178
|
+
#define rand3(v) sobol3(v)
|
|
179
|
+
#define rand4(v) sobol4(v)
|
|
180
|
+
|
|
181
|
+
#else // PCG
|
|
182
|
+
|
|
183
|
+
${ pcgGLSL }
|
|
184
|
+
|
|
185
|
+
// Using the sobol functions seems to break the the compiler on MacOS
|
|
186
|
+
// - specifically the "sobolReverseBits" function.
|
|
187
|
+
uint sobolPixelIndex = 0u;
|
|
188
|
+
uint sobolPathIndex = 0u;
|
|
189
|
+
uint sobolBounceIndex = 0u;
|
|
190
|
+
|
|
191
|
+
#define rand(v) pcgRand()
|
|
192
|
+
#define rand2(v) pcgRand2()
|
|
193
|
+
#define rand3(v) pcgRand3()
|
|
194
|
+
#define rand4(v) pcgRand4()
|
|
195
|
+
|
|
196
|
+
#endif
|
|
151
197
|
|
|
152
198
|
// common
|
|
153
199
|
${ arraySamplerTexelFetchGLSL }
|
|
@@ -156,20 +202,6 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
156
202
|
${ mathGLSL }
|
|
157
203
|
${ intersectShapesGLSL }
|
|
158
204
|
|
|
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
205
|
// environment
|
|
174
206
|
uniform EquirectHdrInfo envMapInfo;
|
|
175
207
|
uniform mat4 environmentRotation;
|
|
@@ -221,6 +253,14 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
221
253
|
mat3 invEnvRotation3x3;
|
|
222
254
|
float lightsDenom;
|
|
223
255
|
|
|
256
|
+
// sampling
|
|
257
|
+
${ fogMaterialBvhGLSL }
|
|
258
|
+
${ shapeSamplingGLSL }
|
|
259
|
+
${ bsdfSamplingGLSL }
|
|
260
|
+
${ equirectSamplingGLSL }
|
|
261
|
+
${ lightSamplingGLSL }
|
|
262
|
+
${ fogGLSL }
|
|
263
|
+
|
|
224
264
|
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
225
265
|
|
|
226
266
|
return clamp(
|
|
@@ -260,7 +300,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
260
300
|
|
|
261
301
|
// init
|
|
262
302
|
rng_initialize( gl_FragCoord.xy, seed );
|
|
263
|
-
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) |
|
|
303
|
+
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | uint( gl_FragCoord.y );
|
|
264
304
|
sobolPathIndex = uint( seed );
|
|
265
305
|
|
|
266
306
|
// get camera ray
|
|
@@ -276,7 +316,6 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
276
316
|
|
|
277
317
|
// surface results
|
|
278
318
|
SurfaceHit surfaceHit;
|
|
279
|
-
LightRecord lightRec;
|
|
280
319
|
ScatterRecord scatterRec;
|
|
281
320
|
|
|
282
321
|
// path tracing state
|
|
@@ -285,7 +324,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
285
324
|
#if FEATURE_FOG
|
|
286
325
|
|
|
287
326
|
state.fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
|
|
288
|
-
|
|
327
|
+
ray.origin, - ray.direction,
|
|
289
328
|
materialIndexAttribute, materials,
|
|
290
329
|
state.fogMaterial
|
|
291
330
|
);
|
|
@@ -300,48 +339,46 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
300
339
|
state.traversals = bounces - i;
|
|
301
340
|
state.firstRay = i == 0 && state.transmissiveTraversals == transmissiveBounces;
|
|
302
341
|
|
|
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 ) {
|
|
342
|
+
int hitType = traceScene( ray, state.fogMaterial, surfaceHit );
|
|
311
343
|
|
|
312
|
-
|
|
344
|
+
// check if we intersect any lights and accumulate the light contribution
|
|
345
|
+
// TODO: we can add support for light surface rendering in the else condition if we
|
|
346
|
+
// add the ability to toggle visibility of the the light
|
|
347
|
+
if ( ! state.firstRay && ! state.transmissiveRay ) {
|
|
313
348
|
|
|
314
|
-
|
|
349
|
+
LightRecord lightRec;
|
|
350
|
+
float lightDist = hitType == NO_HIT ? INFINITY : surfaceHit.dist;
|
|
351
|
+
for ( uint i = 0u; i < lights.count; i ++ ) {
|
|
315
352
|
|
|
316
|
-
|
|
353
|
+
if (
|
|
354
|
+
intersectLightAtIndex( lights.tex, ray.origin, ray.direction, i, lightRec ) &&
|
|
355
|
+
lightRec.dist < lightDist
|
|
356
|
+
) {
|
|
317
357
|
|
|
318
|
-
|
|
319
|
-
if ( lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ) {
|
|
320
|
-
|
|
321
|
-
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
322
|
-
|
|
323
|
-
} else {
|
|
358
|
+
#if FEATURE_MIS
|
|
324
359
|
|
|
325
360
|
// weight the contribution
|
|
361
|
+
// NOTE: Only area lights are supported for forward sampling and can be hit
|
|
326
362
|
float misWeight = misHeuristic( scatterRec.pdf, lightRec.pdf / lightsDenom );
|
|
327
363
|
gl_FragColor.rgb += lightRec.emission * state.throughputColor * misWeight;
|
|
328
364
|
|
|
329
|
-
|
|
365
|
+
#else
|
|
330
366
|
|
|
331
|
-
|
|
367
|
+
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
332
368
|
|
|
333
|
-
|
|
369
|
+
#endif
|
|
334
370
|
|
|
335
|
-
|
|
371
|
+
}
|
|
336
372
|
|
|
337
373
|
}
|
|
338
|
-
break;
|
|
339
374
|
|
|
340
|
-
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if ( hitType == NO_HIT ) {
|
|
341
378
|
|
|
342
379
|
if ( state.firstRay || state.transmissiveRay ) {
|
|
343
380
|
|
|
344
|
-
gl_FragColor.rgb += sampleBackground( envRotation3x3 * ray.direction,
|
|
381
|
+
gl_FragColor.rgb += sampleBackground( envRotation3x3 * ray.direction, rand2( 2 ) ) * state.throughputColor;
|
|
345
382
|
gl_FragColor.a = backgroundAlpha;
|
|
346
383
|
|
|
347
384
|
} else {
|
|
@@ -350,7 +387,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
350
387
|
|
|
351
388
|
// get the PDF of the hit envmap point
|
|
352
389
|
vec3 envColor;
|
|
353
|
-
float envPdf = sampleEquirect(
|
|
390
|
+
float envPdf = sampleEquirect( envRotation3x3 * ray.direction, envColor );
|
|
354
391
|
envPdf /= lightsDenom;
|
|
355
392
|
|
|
356
393
|
// and weight the contribution
|
|
@@ -432,7 +469,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
432
469
|
}
|
|
433
470
|
|
|
434
471
|
scatterRec = bsdfSample( - ray.direction, surf );
|
|
435
|
-
state.isShadowRay = scatterRec.specularPdf <
|
|
472
|
+
state.isShadowRay = scatterRec.specularPdf < rand( 4 );
|
|
436
473
|
|
|
437
474
|
bool isBelowSurface = ! surf.volumeParticle && dot( scatterRec.direction, surf.faceNormal ) < 0.0;
|
|
438
475
|
vec3 hitPoint = stepRayOrigin( ray.origin, ray.direction, isBelowSurface ? - surf.faceNormal : surf.faceNormal, surfaceHit.dist );
|
|
@@ -502,7 +539,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
|
|
|
502
539
|
rrProb = sqrt( rrProb );
|
|
503
540
|
rrProb = max( rrProb, depthProb );
|
|
504
541
|
rrProb = min( rrProb, 1.0 );
|
|
505
|
-
if (
|
|
542
|
+
if ( rand( 8 ) > rrProb ) {
|
|
506
543
|
|
|
507
544
|
break;
|
|
508
545
|
|
|
@@ -3,11 +3,14 @@ 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
|
-
|
|
6
|
+
RenderState state,
|
|
7
7
|
Ray ray, float rayDist,
|
|
8
8
|
out vec3 color
|
|
9
9
|
) {
|
|
10
10
|
|
|
11
|
+
// store the original bounce index so we can reset it after
|
|
12
|
+
uint originalBounceIndex = sobolBounceIndex;
|
|
13
|
+
|
|
11
14
|
int traversals = state.traversals;
|
|
12
15
|
int transmissiveTraversals = state.transmissiveTraversals;
|
|
13
16
|
bool isShadowRay = state.isShadowRay;
|
|
@@ -17,34 +20,28 @@ export const attenuateHitGLSL = /* glsl */`
|
|
|
17
20
|
|
|
18
21
|
// hit results
|
|
19
22
|
SurfaceHit surfaceHit;
|
|
20
|
-
LightRecord lightRec;
|
|
21
23
|
|
|
22
24
|
color = vec3( 1.0 );
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
// and then reset.
|
|
26
|
+
bool result = true;
|
|
26
27
|
for ( int i = 0; i < traversals; i ++ ) {
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
ray, bvh, lights, fogMaterial,
|
|
30
|
-
surfaceHit, lightRec
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
if ( hitType == FOG_HIT ) {
|
|
29
|
+
sobolBounceIndex ++;
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
int hitType = traceScene( ray, fogMaterial, surfaceHit );
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
if ( hitType == FOG_HIT ) {
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
result = true;
|
|
36
|
+
break;
|
|
41
37
|
|
|
42
38
|
} else if ( hitType == SURFACE_HIT ) {
|
|
43
39
|
|
|
44
40
|
float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );
|
|
45
41
|
if ( totalDist > rayDist ) {
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
result = false;
|
|
44
|
+
break;
|
|
48
45
|
|
|
49
46
|
}
|
|
50
47
|
|
|
@@ -126,7 +123,7 @@ export const attenuateHitGLSL = /* glsl */`
|
|
|
126
123
|
bool useAlphaTest = alphaTest != 0.0;
|
|
127
124
|
float transmissionFactor = ( 1.0 - metalness ) * transmission;
|
|
128
125
|
if (
|
|
129
|
-
transmissionFactor < rand() && ! (
|
|
126
|
+
transmissionFactor < rand( 9 ) && ! (
|
|
130
127
|
// material sidedness
|
|
131
128
|
material.side != 0.0 && surfaceHit.side == material.side
|
|
132
129
|
|
|
@@ -134,11 +131,12 @@ export const attenuateHitGLSL = /* glsl */`
|
|
|
134
131
|
|| useAlphaTest && albedo.a < alphaTest
|
|
135
132
|
|
|
136
133
|
// opacity
|
|
137
|
-
|| material.transparent && ! useAlphaTest && albedo.a < rand()
|
|
134
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand( 10 )
|
|
138
135
|
)
|
|
139
136
|
) {
|
|
140
137
|
|
|
141
|
-
|
|
138
|
+
result = true;
|
|
139
|
+
break;
|
|
142
140
|
|
|
143
141
|
}
|
|
144
142
|
|
|
@@ -164,13 +162,16 @@ export const attenuateHitGLSL = /* glsl */`
|
|
|
164
162
|
|
|
165
163
|
} else {
|
|
166
164
|
|
|
167
|
-
|
|
165
|
+
result = false;
|
|
166
|
+
break;
|
|
168
167
|
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
}
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
// reset the bounce index
|
|
173
|
+
sobolBounceIndex = originalBounceIndex;
|
|
174
|
+
return result;
|
|
174
175
|
|
|
175
176
|
}
|
|
176
177
|
|
|
@@ -12,7 +12,7 @@ export const cameraUtilsGLSL = /* glsl */`
|
|
|
12
12
|
|
|
13
13
|
// Jitter the camera ray by finding a uv coordinate at a random sample
|
|
14
14
|
// around this pixel's UV coordinate for AA
|
|
15
|
-
vec2 ruv =
|
|
15
|
+
vec2 ruv = rand2( 0 );
|
|
16
16
|
vec2 jitteredUv = vUv + vec2( tentFilter( ruv.x ) * ssd.x, tentFilter( ruv.y ) * ssd.y );
|
|
17
17
|
Ray ray;
|
|
18
18
|
|
|
@@ -57,7 +57,7 @@ export const cameraUtilsGLSL = /* glsl */`
|
|
|
57
57
|
|
|
58
58
|
// get the aperture sample
|
|
59
59
|
// if blades === 0 then we assume a circle
|
|
60
|
-
vec3 shapeUVW=
|
|
60
|
+
vec3 shapeUVW= rand3( 1 );
|
|
61
61
|
int blades = physicalCamera.apertureBlades;
|
|
62
62
|
float anamorphicRatio = physicalCamera.anamorphicRatio;
|
|
63
63
|
vec2 apertureSample = blades == 0 ? sampleCircle( shapeUVW.xy ) : sampleRegularPolygon( blades, shapeUVW );
|
|
@@ -2,11 +2,13 @@ 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
|
-
if( lightsDenom != 0.0 &&
|
|
8
|
+
if( lightsDenom != 0.0 && rand( 5 ) < float( lights.count ) / lightsDenom ) {
|
|
7
9
|
|
|
8
10
|
// sample a light or environment
|
|
9
|
-
LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin,
|
|
11
|
+
LightRecord lightRec = randomLightSample( lights.tex, iesProfiles, lights.count, rayOrigin, rand3( 6 ) );
|
|
10
12
|
|
|
11
13
|
bool isSampleBelowSurface = ! surf.volumeParticle && dot( surf.faceNormal, lightRec.direction ) < 0.0;
|
|
12
14
|
if ( isSampleBelowSurface ) {
|
|
@@ -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(
|
|
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
|
-
|
|
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(
|
|
50
|
+
float envPdf = sampleEquirectProbability( rand2( 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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
9
|
+
inout SurfaceRecord surf
|
|
10
10
|
) {
|
|
11
11
|
|
|
12
12
|
if ( material.fogVolume ) {
|
|
@@ -36,6 +36,7 @@ export const getSurfaceRecordGLSL = /* glsl */`
|
|
|
36
36
|
|
|
37
37
|
vec3 uvPrime = material.mapTransform * vec3( uv, 1 );
|
|
38
38
|
albedo *= texture2D( textures, vec3( uvPrime.xy, material.map ) );
|
|
39
|
+
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
if ( material.vertexColors ) {
|
|
@@ -67,7 +68,7 @@ export const getSurfaceRecordGLSL = /* glsl */`
|
|
|
67
68
|
|| useAlphaTest && albedo.a < alphaTest
|
|
68
69
|
|
|
69
70
|
// opacity
|
|
70
|
-
|| material.transparent && ! useAlphaTest && albedo.a <
|
|
71
|
+
|| material.transparent && ! useAlphaTest && albedo.a < rand( 3 )
|
|
71
72
|
) {
|
|
72
73
|
|
|
73
74
|
return SKIP_SURFACE;
|
|
@@ -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,
|
|
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
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
// offset the distance so we don't run into issues with particles on the same surface
|
|
25
|
+
// as other objects
|
|
26
|
+
float particleDist = intersectFogVolume( fogMaterial, rand( 1 ) );
|
|
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
|
-
|
|
42
|
+
result = SURFACE_HIT;
|
|
45
43
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
|
-
return
|
|
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,
|
|
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
|
-
${
|
|
101
|
-
${
|
|
100
|
+
${ BVHShaderGLSL.common_functions }
|
|
101
|
+
${ BVHShaderGLSL.bvh_struct_definitions }
|
|
102
|
+
${ BVHShaderGLSL.bvh_ray_functions }
|
|
102
103
|
|
|
103
104
|
// uniform structs
|
|
104
105
|
${ materialStructGLSL }
|