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.
- package/README.md +3 -1
- package/build/index.module.js +248 -198
- package/build/index.module.js.map +1 -1
- package/build/index.umd.cjs +245 -195
- package/build/index.umd.cjs.map +1 -1
- package/package.json +5 -6
- package/src/core/DynamicPathTracingSceneGenerator.js +8 -3
- package/src/core/PathTracingRenderer.js +8 -4
- package/src/core/PathTracingSceneGenerator.js +6 -1
- 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 +4 -3
- package/src/materials/pathtracing/PhysicalPathTracingMaterial.js +61 -46
- package/src/materials/pathtracing/glsl/attenuateHit.glsl.js +2 -11
- package/src/materials/pathtracing/glsl/directLightContribution.glsl.js +10 -6
- package/src/materials/pathtracing/glsl/getSurfaceRecord.glsl.js +1 -1
- package/src/materials/pathtracing/glsl/traceScene.glsl.js +10 -12
- package/src/materials/surface/AmbientOcclusionMaterial.js +4 -3
- package/src/shader/bsdf/bsdfSampling.glsl.js +7 -7
- package/src/shader/common/bvhAnyHit.glsl.js +2 -2
- package/src/shader/common/intersectShapes.glsl.js +2 -2
- package/src/shader/rand/sobol.glsl.js +3 -3
- 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 +12 -1
- package/src/shader/structs/materialStruct.glsl.js +16 -15
- package/src/textures/ProceduralEquirectTexture.js +9 -8
- package/src/uniforms/EquirectHdrInfoUniform.js +18 -17
- package/src/uniforms/IESProfilesTexture.js +2 -2
- package/src/uniforms/LightsInfoUniformStruct.js +4 -2
- package/src/uniforms/MaterialsTexture.js +3 -1
- package/src/utils/BlurredEnvMapGenerator.js +4 -4
- package/src/utils/GeometryPreparationUtils.js +8 -2
- package/src/utils/IESLoader.js +7 -5
- 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.
|
|
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.
|
|
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.
|
|
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 (
|
|
55
|
+
} else if (
|
|
56
|
+
c.isRectAreaLight ||
|
|
57
|
+
c.isSpotLight ||
|
|
58
|
+
c.isPointLight ||
|
|
59
|
+
c.isDirectionalLight
|
|
60
|
+
) {
|
|
56
61
|
|
|
57
|
-
|
|
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 (
|
|
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
|
|
|
@@ -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 <
|
|
129
|
+
#include <colorspace_fragment>
|
|
130
130
|
#include <premultiplied_alpha_fragment>
|
|
131
131
|
|
|
132
132
|
}
|
|
@@ -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
|
-
|
|
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
|
-
${
|
|
89
|
-
${
|
|
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
|
-
|
|
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
|
-
${
|
|
145
|
-
${
|
|
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
|
-
|
|
150
|
-
|
|
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 ) |
|
|
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
|
-
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
319
|
-
|
|
327
|
+
LightRecord lightRec;
|
|
328
|
+
float lightDist = hitType == NO_HIT ? INFINITY : surfaceHit.dist;
|
|
329
|
+
for ( uint i = 0u; i < lights.count; i ++ ) {
|
|
320
330
|
|
|
321
|
-
|
|
331
|
+
if (
|
|
332
|
+
intersectLightAtIndex( lights.tex, ray.origin, ray.direction, i, lightRec ) &&
|
|
333
|
+
lightRec.dist < lightDist
|
|
334
|
+
) {
|
|
322
335
|
|
|
323
|
-
|
|
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
|
-
|
|
345
|
+
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
332
346
|
|
|
333
|
-
|
|
347
|
+
#endif
|
|
334
348
|
|
|
335
|
-
|
|
349
|
+
}
|
|
336
350
|
|
|
337
351
|
}
|
|
338
|
-
break;
|
|
339
352
|
|
|
340
|
-
}
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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( 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(
|
|
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 ) {
|
|
@@ -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
|
|
|
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 +
|
|
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 }
|
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
4
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
5
5
|
|
|
6
6
|
// output variables
|
|
7
|
-
|
|
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,
|
|
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,
|
|
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
|
|