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/build/index.umd.cjs
CHANGED
|
@@ -340,9 +340,9 @@
|
|
|
340
340
|
|
|
341
341
|
// Seeds
|
|
342
342
|
uniform sampler2D sobolTexture;
|
|
343
|
-
uint sobolPixelIndex;
|
|
344
|
-
uint sobolPathIndex;
|
|
345
|
-
uint sobolBounceIndex;
|
|
343
|
+
uint sobolPixelIndex = 0u;
|
|
344
|
+
uint sobolPathIndex = 0u;
|
|
345
|
+
uint sobolBounceIndex = 0u;
|
|
346
346
|
|
|
347
347
|
uint sobolGetSeed( uint bounce, uint effect ) {
|
|
348
348
|
|
|
@@ -704,18 +704,22 @@
|
|
|
704
704
|
this._currentTile = 0;
|
|
705
705
|
|
|
706
706
|
this._sobolTarget = new SobolNumberMapGenerator().generate( renderer );
|
|
707
|
+
|
|
708
|
+
// will be null if extension not supported
|
|
709
|
+
const floatLinearExtensionSupported = renderer.extensions.get( 'OES_texture_float_linear' );
|
|
710
|
+
|
|
707
711
|
this._primaryTarget = new three.WebGLRenderTarget( 1, 1, {
|
|
708
712
|
format: three.RGBAFormat,
|
|
709
|
-
type: three.FloatType,
|
|
713
|
+
type: floatLinearExtensionSupported ? three.FloatType : three.HalfFloatType,
|
|
710
714
|
} );
|
|
711
715
|
this._blendTargets = [
|
|
712
716
|
new three.WebGLRenderTarget( 1, 1, {
|
|
713
717
|
format: three.RGBAFormat,
|
|
714
|
-
type: three.FloatType,
|
|
718
|
+
type: floatLinearExtensionSupported ? three.FloatType : three.HalfFloatType,
|
|
715
719
|
} ),
|
|
716
720
|
new three.WebGLRenderTarget( 1, 1, {
|
|
717
721
|
format: three.RGBAFormat,
|
|
718
|
-
type: three.FloatType,
|
|
722
|
+
type: floatLinearExtensionSupported ? three.FloatType : three.HalfFloatType,
|
|
719
723
|
} ),
|
|
720
724
|
];
|
|
721
725
|
|
|
@@ -1196,6 +1200,12 @@
|
|
|
1196
1200
|
const geometry = options.cloneGeometry ? originalGeometry.clone() : originalGeometry;
|
|
1197
1201
|
geometry.applyMatrix4( mesh.matrixWorld );
|
|
1198
1202
|
|
|
1203
|
+
if ( mesh.matrixWorld.determinant() < 0 ) {
|
|
1204
|
+
|
|
1205
|
+
geometry.index.array.reverse();
|
|
1206
|
+
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1199
1209
|
// ensure our geometry has common attributes
|
|
1200
1210
|
setCommonAttributes( geometry, {
|
|
1201
1211
|
attributes: options.attributes,
|
|
@@ -1227,7 +1237,7 @@
|
|
|
1227
1237
|
|
|
1228
1238
|
} );
|
|
1229
1239
|
|
|
1230
|
-
const geometry = BufferGeometryUtils_js.
|
|
1240
|
+
const geometry = BufferGeometryUtils_js.mergeGeometries( transformedGeometry, false );
|
|
1231
1241
|
const textures = Array.from( textureSet );
|
|
1232
1242
|
return { geometry, materials, textures };
|
|
1233
1243
|
|
|
@@ -1264,7 +1274,12 @@
|
|
|
1264
1274
|
|
|
1265
1275
|
meshes.push( c );
|
|
1266
1276
|
|
|
1267
|
-
} else if (
|
|
1277
|
+
} else if (
|
|
1278
|
+
c.isRectAreaLight ||
|
|
1279
|
+
c.isSpotLight ||
|
|
1280
|
+
c.isPointLight ||
|
|
1281
|
+
c.isDirectionalLight
|
|
1282
|
+
) {
|
|
1268
1283
|
|
|
1269
1284
|
lights.push( c );
|
|
1270
1285
|
|
|
@@ -1335,7 +1350,7 @@
|
|
|
1335
1350
|
|
|
1336
1351
|
generate() {
|
|
1337
1352
|
|
|
1338
|
-
const { objects, staticGeometryGenerator, geometry } = this;
|
|
1353
|
+
const { objects, staticGeometryGenerator, geometry, lights } = this;
|
|
1339
1354
|
if ( this.bvh === null ) {
|
|
1340
1355
|
|
|
1341
1356
|
const attributes = [ 'position', 'normal', 'tangent', 'uv', 'color' ];
|
|
@@ -1349,9 +1364,14 @@
|
|
|
1349
1364
|
const normalMapRequired = ! ! c.material.normalMap;
|
|
1350
1365
|
setCommonAttributes( c.geometry, { attributes, normalMapRequired } );
|
|
1351
1366
|
|
|
1352
|
-
} else if (
|
|
1367
|
+
} else if (
|
|
1368
|
+
c.isRectAreaLight ||
|
|
1369
|
+
c.isSpotLight ||
|
|
1370
|
+
c.isPointLight ||
|
|
1371
|
+
c.isDirectionalLight
|
|
1372
|
+
) {
|
|
1353
1373
|
|
|
1354
|
-
|
|
1374
|
+
lights.push( c );
|
|
1355
1375
|
|
|
1356
1376
|
}
|
|
1357
1377
|
|
|
@@ -1776,11 +1796,11 @@
|
|
|
1776
1796
|
const _color = new three.Color();
|
|
1777
1797
|
class ProceduralEquirectTexture extends three.DataTexture {
|
|
1778
1798
|
|
|
1779
|
-
constructor( width, height ) {
|
|
1799
|
+
constructor( width = 512, height = 512 ) {
|
|
1780
1800
|
|
|
1781
1801
|
super(
|
|
1782
|
-
new
|
|
1783
|
-
width, height, three.RGBAFormat, three.
|
|
1802
|
+
new Uint16Array( width * height * 4 ),
|
|
1803
|
+
width, height, three.RGBAFormat, three.HalfFloatType, three.EquirectangularReflectionMapping,
|
|
1784
1804
|
three.RepeatWrapping, three.ClampToEdgeWrapping, three.LinearFilter, three.LinearFilter,
|
|
1785
1805
|
);
|
|
1786
1806
|
|
|
@@ -1812,10 +1832,10 @@
|
|
|
1812
1832
|
|
|
1813
1833
|
const i = y * width + x;
|
|
1814
1834
|
const i4 = 4 * i;
|
|
1815
|
-
data[ i4 + 0 ] = _color.r;
|
|
1816
|
-
data[ i4 + 1 ] = _color.g;
|
|
1817
|
-
data[ i4 + 2 ] = _color.b;
|
|
1818
|
-
data[ i4 + 3 ] = 1.0;
|
|
1835
|
+
data[ i4 + 0 ] = three.DataUtils.toHalfFloat( _color.r );
|
|
1836
|
+
data[ i4 + 1 ] = three.DataUtils.toHalfFloat( _color.g );
|
|
1837
|
+
data[ i4 + 2 ] = three.DataUtils.toHalfFloat( _color.b );
|
|
1838
|
+
data[ i4 + 3 ] = three.DataUtils.toHalfFloat( 1.0 );
|
|
1819
1839
|
|
|
1820
1840
|
}
|
|
1821
1841
|
|
|
@@ -1949,6 +1969,8 @@
|
|
|
1949
1969
|
this.type = three.FloatType;
|
|
1950
1970
|
this.wrapS = three.ClampToEdgeWrapping;
|
|
1951
1971
|
this.wrapT = three.ClampToEdgeWrapping;
|
|
1972
|
+
this.minFilter = three.NearestFilter;
|
|
1973
|
+
this.magFilter = three.NearestFilter;
|
|
1952
1974
|
this.generateMipmaps = false;
|
|
1953
1975
|
this.threeCompatibilityTransforms = false;
|
|
1954
1976
|
this.features = new MaterialFeatures();
|
|
@@ -2483,6 +2505,19 @@
|
|
|
2483
2505
|
|
|
2484
2506
|
}
|
|
2485
2507
|
|
|
2508
|
+
function toHalfFloatArray( f32Array ) {
|
|
2509
|
+
|
|
2510
|
+
const f16Array = new Uint16Array( f32Array.length );
|
|
2511
|
+
for ( let i = 0, n = f32Array.length; i < n; ++ i ) {
|
|
2512
|
+
|
|
2513
|
+
f16Array[ i ] = three.DataUtils.toHalfFloat( f32Array[ i ] );
|
|
2514
|
+
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
return f16Array;
|
|
2518
|
+
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2486
2521
|
function binarySearchFindClosestIndexOf( array, targetValue, offset = 0, count = array.length ) {
|
|
2487
2522
|
|
|
2488
2523
|
let lower = offset;
|
|
@@ -2532,15 +2567,15 @@
|
|
|
2532
2567
|
let newData = data;
|
|
2533
2568
|
if ( map.type === three.HalfFloatType ) {
|
|
2534
2569
|
|
|
2535
|
-
newData = new
|
|
2570
|
+
newData = new Uint16Array( data.length );
|
|
2536
2571
|
for ( const i in data ) {
|
|
2537
2572
|
|
|
2538
|
-
newData[ i ] =
|
|
2573
|
+
newData[ i ] = data[ i ];
|
|
2539
2574
|
|
|
2540
2575
|
}
|
|
2541
2576
|
|
|
2542
2577
|
map.image.data = newData;
|
|
2543
|
-
map.type = three.
|
|
2578
|
+
map.type = three.HalfFloatType;
|
|
2544
2579
|
|
|
2545
2580
|
}
|
|
2546
2581
|
|
|
@@ -2581,8 +2616,8 @@
|
|
|
2581
2616
|
|
|
2582
2617
|
// Default to a white texture and associated weights so we don't
|
|
2583
2618
|
// just render black initially.
|
|
2584
|
-
const whiteTex = new three.DataTexture( new Float32Array( [ 1, 1, 1, 1 ] ), 1, 1 );
|
|
2585
|
-
whiteTex.type = three.
|
|
2619
|
+
const whiteTex = new three.DataTexture( toHalfFloatArray( new Float32Array( [ 1, 1, 1, 1 ] ) ), 1, 1 );
|
|
2620
|
+
whiteTex.type = three.HalfFloatType;
|
|
2586
2621
|
whiteTex.format = three.RGBAFormat;
|
|
2587
2622
|
whiteTex.minFilter = three.LinearFilter;
|
|
2588
2623
|
whiteTex.magFilter = three.LinearFilter;
|
|
@@ -2593,8 +2628,8 @@
|
|
|
2593
2628
|
|
|
2594
2629
|
// Stores a map of [0, 1] value -> cumulative importance row & pdf
|
|
2595
2630
|
// used to sampling a random value to a relevant row to sample from
|
|
2596
|
-
const marginalWeights = new three.DataTexture( new Float32Array( [ 0, 1 ] ), 1, 2 );
|
|
2597
|
-
marginalWeights.type = three.
|
|
2631
|
+
const marginalWeights = new three.DataTexture( toHalfFloatArray( new Float32Array( [ 0, 1 ] ) ), 1, 2 );
|
|
2632
|
+
marginalWeights.type = three.HalfFloatType;
|
|
2598
2633
|
marginalWeights.format = three.RedFormat;
|
|
2599
2634
|
marginalWeights.minFilter = three.LinearFilter;
|
|
2600
2635
|
marginalWeights.magFilter = three.LinearFilter;
|
|
@@ -2603,8 +2638,8 @@
|
|
|
2603
2638
|
|
|
2604
2639
|
// Stores a map of [0, 1] value -> cumulative importance column & pdf
|
|
2605
2640
|
// used to sampling a random value to a relevant pixel to sample from
|
|
2606
|
-
const conditionalWeights = new three.DataTexture( new Float32Array( [ 0, 0, 1, 1 ] ), 2, 2 );
|
|
2607
|
-
conditionalWeights.type = three.
|
|
2641
|
+
const conditionalWeights = new three.DataTexture( toHalfFloatArray( new Float32Array( [ 0, 0, 1, 1 ] ) ), 2, 2 );
|
|
2642
|
+
conditionalWeights.type = three.HalfFloatType;
|
|
2608
2643
|
conditionalWeights.format = three.RedFormat;
|
|
2609
2644
|
conditionalWeights.minFilter = three.LinearFilter;
|
|
2610
2645
|
conditionalWeights.magFilter = three.LinearFilter;
|
|
@@ -2654,9 +2689,9 @@
|
|
|
2654
2689
|
for ( let x = 0; x < width; x ++ ) {
|
|
2655
2690
|
|
|
2656
2691
|
const i = y * width + x;
|
|
2657
|
-
const r = data[ 4 * i + 0 ];
|
|
2658
|
-
const g = data[ 4 * i + 1 ];
|
|
2659
|
-
const b = data[ 4 * i + 2 ];
|
|
2692
|
+
const r = three.DataUtils.fromHalfFloat( data[ 4 * i + 0 ] );
|
|
2693
|
+
const g = three.DataUtils.fromHalfFloat( data[ 4 * i + 1 ] );
|
|
2694
|
+
const b = three.DataUtils.fromHalfFloat( data[ 4 * i + 2 ] );
|
|
2660
2695
|
|
|
2661
2696
|
// the probability of the pixel being selected in this row is the
|
|
2662
2697
|
// scale of the luminance relative to the rest of the pixels.
|
|
@@ -2708,8 +2743,8 @@
|
|
|
2708
2743
|
// the marginal and conditional data. These will be used to sample with a random number
|
|
2709
2744
|
// to retrieve a uv value to sample in the environment map.
|
|
2710
2745
|
// These values continually increase so it's okay to interpolate between them.
|
|
2711
|
-
const marginalDataArray = new
|
|
2712
|
-
const conditionalDataArray = new
|
|
2746
|
+
const marginalDataArray = new Uint16Array( height );
|
|
2747
|
+
const conditionalDataArray = new Uint16Array( width * height );
|
|
2713
2748
|
|
|
2714
2749
|
// we add a half texel offset so we're sampling the center of the pixel
|
|
2715
2750
|
for ( let i = 0; i < height; i ++ ) {
|
|
@@ -2717,7 +2752,7 @@
|
|
|
2717
2752
|
const dist = ( i + 1 ) / height;
|
|
2718
2753
|
const row = binarySearchFindClosestIndexOf( cdfMarginal, dist );
|
|
2719
2754
|
|
|
2720
|
-
marginalDataArray[ i ] = ( row + 0.5 ) / height;
|
|
2755
|
+
marginalDataArray[ i ] = three.DataUtils.toHalfFloat( ( row + 0.5 ) / height );
|
|
2721
2756
|
|
|
2722
2757
|
}
|
|
2723
2758
|
|
|
@@ -2729,7 +2764,7 @@
|
|
|
2729
2764
|
const dist = ( x + 1 ) / width;
|
|
2730
2765
|
const col = binarySearchFindClosestIndexOf( cdfConditional, dist, y * width, width );
|
|
2731
2766
|
|
|
2732
|
-
conditionalDataArray[ i ] = ( col + 0.5 ) / width;
|
|
2767
|
+
conditionalDataArray[ i ] = three.DataUtils.toHalfFloat( ( col + 0.5 ) / width );
|
|
2733
2768
|
|
|
2734
2769
|
}
|
|
2735
2770
|
|
|
@@ -2803,6 +2838,8 @@
|
|
|
2803
2838
|
tex.wrapS = three.ClampToEdgeWrapping;
|
|
2804
2839
|
tex.wrapT = three.ClampToEdgeWrapping;
|
|
2805
2840
|
tex.generateMipmaps = false;
|
|
2841
|
+
tex.minFilter = three.NearestFilter;
|
|
2842
|
+
tex.magFilter = three.NearestFilter;
|
|
2806
2843
|
|
|
2807
2844
|
this.tex = tex;
|
|
2808
2845
|
this.count = 0;
|
|
@@ -2833,7 +2870,7 @@
|
|
|
2833
2870
|
const worldQuaternion = new three.Quaternion();
|
|
2834
2871
|
const eye = new three.Vector3();
|
|
2835
2872
|
const target = new three.Vector3();
|
|
2836
|
-
const up = new three.Vector3();
|
|
2873
|
+
const up = new three.Vector3( 0, 1, 0 );
|
|
2837
2874
|
|
|
2838
2875
|
for ( let i = 0, l = lights.length; i < l; i ++ ) {
|
|
2839
2876
|
|
|
@@ -3276,7 +3313,7 @@
|
|
|
3276
3313
|
loader.setPath( this.path );
|
|
3277
3314
|
loader.setRequestHeader( this.requestHeader );
|
|
3278
3315
|
|
|
3279
|
-
const texture = new three.DataTexture( null, 360, 180, three.RedFormat, three.
|
|
3316
|
+
const texture = new three.DataTexture( null, 360, 180, three.RedFormat, three.HalfFloatType );
|
|
3280
3317
|
texture.minFilter = three.LinearFilter;
|
|
3281
3318
|
texture.magFilter = three.LinearFilter;
|
|
3282
3319
|
|
|
@@ -3284,7 +3321,7 @@
|
|
|
3284
3321
|
|
|
3285
3322
|
const iesLamp = new IESLamp( text );
|
|
3286
3323
|
|
|
3287
|
-
texture.image.data = this._getIESValues( iesLamp );
|
|
3324
|
+
texture.image.data = toHalfFloatArray( this._getIESValues( iesLamp ) );
|
|
3288
3325
|
texture.needsUpdate = true;
|
|
3289
3326
|
|
|
3290
3327
|
if ( onLoad !== undefined ) {
|
|
@@ -3302,10 +3339,10 @@
|
|
|
3302
3339
|
parse( text ) {
|
|
3303
3340
|
|
|
3304
3341
|
const iesLamp = new IESLamp( text );
|
|
3305
|
-
const texture = new three.DataTexture( null, 360, 180, three.RedFormat, three.
|
|
3342
|
+
const texture = new three.DataTexture( null, 360, 180, three.RedFormat, three.HalfFloatType );
|
|
3306
3343
|
texture.minFilter = three.LinearFilter;
|
|
3307
3344
|
texture.magFilter = three.LinearFilter;
|
|
3308
|
-
texture.image.data = this._getIESValues( iesLamp );
|
|
3345
|
+
texture.image.data = toHalfFloatArray( this._getIESValues( iesLamp ) );
|
|
3309
3346
|
texture.needsUpdate = true;
|
|
3310
3347
|
|
|
3311
3348
|
return texture;
|
|
@@ -3323,7 +3360,7 @@
|
|
|
3323
3360
|
|
|
3324
3361
|
const tex = this.texture;
|
|
3325
3362
|
tex.format = three.RGBAFormat;
|
|
3326
|
-
tex.type = three.
|
|
3363
|
+
tex.type = three.HalfFloatType;
|
|
3327
3364
|
tex.minFilter = three.LinearFilter;
|
|
3328
3365
|
tex.magFilter = three.LinearFilter;
|
|
3329
3366
|
tex.wrapS = three.ClampToEdgeWrapping;
|
|
@@ -3574,7 +3611,7 @@
|
|
|
3574
3611
|
this.renderer = renderer;
|
|
3575
3612
|
this.pmremGenerator = new three.PMREMGenerator( renderer );
|
|
3576
3613
|
this.copyQuad = new Pass_js.FullScreenQuad( new PMREMCopyMaterial() );
|
|
3577
|
-
this.renderTarget = new three.WebGLRenderTarget( 1, 1, { type: three.
|
|
3614
|
+
this.renderTarget = new three.WebGLRenderTarget( 1, 1, { type: three.HalfFloatType, format: three.RGBAFormat } );
|
|
3578
3615
|
|
|
3579
3616
|
}
|
|
3580
3617
|
|
|
@@ -3611,10 +3648,10 @@
|
|
|
3611
3648
|
renderer.autoClear = prevClear;
|
|
3612
3649
|
|
|
3613
3650
|
// read the data back
|
|
3614
|
-
const buffer = new
|
|
3651
|
+
const buffer = new Uint16Array( width * height * 4 );
|
|
3615
3652
|
renderer.readRenderTargetPixels( renderTarget, 0, 0, width, height, buffer );
|
|
3616
3653
|
|
|
3617
|
-
const result = new three.DataTexture( buffer, width, height, three.RGBAFormat, three.
|
|
3654
|
+
const result = new three.DataTexture( buffer, width, height, three.RGBAFormat, three.HalfFloatType );
|
|
3618
3655
|
result.minFilter = texture.minFilter;
|
|
3619
3656
|
result.magFilter = texture.magFilter;
|
|
3620
3657
|
result.wrapS = texture.wrapS;
|
|
@@ -3756,7 +3793,7 @@
|
|
|
3756
3793
|
|
|
3757
3794
|
gl_FragColor = smartDeNoise( map, vec2( vUv.x, vUv.y ), sigma, kSigma, threshold );
|
|
3758
3795
|
#include <tonemapping_fragment>
|
|
3759
|
-
#include <
|
|
3796
|
+
#include <colorspace_fragment>
|
|
3760
3797
|
#include <premultiplied_alpha_fragment>
|
|
3761
3798
|
|
|
3762
3799
|
}
|
|
@@ -3839,7 +3876,7 @@
|
|
|
3839
3876
|
gl_FragColor.rgb = vec3( mix( minColor, maxColor, t ) );
|
|
3840
3877
|
gl_FragColor.a = 1.0;
|
|
3841
3878
|
|
|
3842
|
-
#include <
|
|
3879
|
+
#include <colorspace_fragment>
|
|
3843
3880
|
|
|
3844
3881
|
}`,
|
|
3845
3882
|
|
|
@@ -4048,7 +4085,7 @@
|
|
|
4048
4085
|
|
|
4049
4086
|
}
|
|
4050
4087
|
|
|
4051
|
-
#include <
|
|
4088
|
+
#include <colorspace_fragment>
|
|
4052
4089
|
|
|
4053
4090
|
}
|
|
4054
4091
|
|
|
@@ -4390,7 +4427,18 @@
|
|
|
4390
4427
|
|
|
4391
4428
|
l.coneCos = s5.r;
|
|
4392
4429
|
l.penumbraCos = s5.g;
|
|
4393
|
-
l.iesProfile = int( round
|
|
4430
|
+
l.iesProfile = int( round( s5.b ) );
|
|
4431
|
+
|
|
4432
|
+
} else {
|
|
4433
|
+
|
|
4434
|
+
l.radius = 0.0;
|
|
4435
|
+
l.near = 0.0;
|
|
4436
|
+
l.decay = 0.0;
|
|
4437
|
+
l.distance = 0.0;
|
|
4438
|
+
|
|
4439
|
+
l.coneCos = 0.0;
|
|
4440
|
+
l.penumbraCos = 0.0;
|
|
4441
|
+
l.iesProfile = - 1;
|
|
4394
4442
|
|
|
4395
4443
|
}
|
|
4396
4444
|
|
|
@@ -4586,21 +4634,22 @@
|
|
|
4586
4634
|
|
|
4587
4635
|
uint firstTextureTransformIdx = i + 15u;
|
|
4588
4636
|
|
|
4589
|
-
|
|
4590
|
-
m.
|
|
4591
|
-
m.
|
|
4592
|
-
m.
|
|
4593
|
-
m.
|
|
4594
|
-
m.
|
|
4595
|
-
m.
|
|
4596
|
-
m.
|
|
4597
|
-
m.
|
|
4598
|
-
m.
|
|
4599
|
-
m.
|
|
4600
|
-
m.
|
|
4601
|
-
m.
|
|
4602
|
-
m.
|
|
4603
|
-
m.
|
|
4637
|
+
// mat3( 1.0 ) is an identity matrix
|
|
4638
|
+
m.mapTransform = m.map == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx );
|
|
4639
|
+
m.metalnessMapTransform = m.metalnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 2u );
|
|
4640
|
+
m.roughnessMapTransform = m.roughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 4u );
|
|
4641
|
+
m.transmissionMapTransform = m.transmissionMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 6u );
|
|
4642
|
+
m.emissiveMapTransform = m.emissiveMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 8u );
|
|
4643
|
+
m.normalMapTransform = m.normalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 10u );
|
|
4644
|
+
m.clearcoatMapTransform = m.clearcoatMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 12u );
|
|
4645
|
+
m.clearcoatNormalMapTransform = m.clearcoatNormalMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 14u );
|
|
4646
|
+
m.clearcoatRoughnessMapTransform = m.clearcoatRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 16u );
|
|
4647
|
+
m.sheenColorMapTransform = m.sheenColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 18u );
|
|
4648
|
+
m.sheenRoughnessMapTransform = m.sheenRoughnessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 20u );
|
|
4649
|
+
m.iridescenceMapTransform = m.iridescenceMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 22u );
|
|
4650
|
+
m.iridescenceThicknessMapTransform = m.iridescenceThicknessMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 24u );
|
|
4651
|
+
m.specularColorMapTransform = m.specularColorMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 26u );
|
|
4652
|
+
m.specularIntensityMapTransform = m.specularIntensityMap == - 1 ? mat3( 1.0 ) : readTextureTransform( tex, firstTextureTransformIdx + 28u );
|
|
4604
4653
|
|
|
4605
4654
|
return m;
|
|
4606
4655
|
|
|
@@ -4625,9 +4674,9 @@ bool isMaterialFogVolume( sampler2D materials, uint materialIndex ) {
|
|
|
4625
4674
|
|
|
4626
4675
|
// returns true if we're within the first fog volume we hit
|
|
4627
4676
|
bool bvhIntersectFogVolumeHit(
|
|
4628
|
-
|
|
4677
|
+
vec3 rayOrigin, vec3 rayDirection,
|
|
4629
4678
|
usampler2D materialIndexAttribute, sampler2D materials,
|
|
4630
|
-
|
|
4679
|
+
inout Material material
|
|
4631
4680
|
) {
|
|
4632
4681
|
|
|
4633
4682
|
material.fogVolume = false;
|
|
@@ -5087,7 +5136,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5087
5136
|
${ iridescenceGLSL }
|
|
5088
5137
|
|
|
5089
5138
|
// diffuse
|
|
5090
|
-
float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf,
|
|
5139
|
+
float diffuseEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
5091
5140
|
|
|
5092
5141
|
// https://schuttejoe.github.io/post/disneybsdf/
|
|
5093
5142
|
float fl = schlickFresnel( wi.z, 0.0 );
|
|
@@ -5118,7 +5167,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5118
5167
|
}
|
|
5119
5168
|
|
|
5120
5169
|
// specular
|
|
5121
|
-
float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf,
|
|
5170
|
+
float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
5122
5171
|
|
|
5123
5172
|
// if roughness is set to 0 then D === NaN which results in black pixels
|
|
5124
5173
|
float metalness = surf.metalness;
|
|
@@ -5165,7 +5214,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5165
5214
|
|
|
5166
5215
|
// transmission
|
|
5167
5216
|
/*
|
|
5168
|
-
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf,
|
|
5217
|
+
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
5169
5218
|
|
|
5170
5219
|
// See section 4.2 in https://www.cs.cornell.edu/~srm/publications/EGSR07-btdf.pdf
|
|
5171
5220
|
|
|
@@ -5208,7 +5257,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5208
5257
|
|
|
5209
5258
|
// TODO: This is just using a basic cosine-weighted specular distribution with an
|
|
5210
5259
|
// incorrect PDF value at the moment. Update it to correctly use a GGX distribution
|
|
5211
|
-
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf,
|
|
5260
|
+
float transmissionEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRecord surf, inout vec3 color ) {
|
|
5212
5261
|
|
|
5213
5262
|
color = surf.transmission * surf.color;
|
|
5214
5263
|
|
|
@@ -5299,7 +5348,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5299
5348
|
// bsdf
|
|
5300
5349
|
void getLobeWeights(
|
|
5301
5350
|
vec3 wo, vec3 wi, vec3 wh, vec3 clearcoatWo, SurfaceRecord surf,
|
|
5302
|
-
|
|
5351
|
+
inout float diffuseWeight, inout float specularWeight, inout float transmissionWeight, inout float clearcoatWeight
|
|
5303
5352
|
) {
|
|
5304
5353
|
|
|
5305
5354
|
float metalness = surf.metalness;
|
|
@@ -5323,7 +5372,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5323
5372
|
|
|
5324
5373
|
float bsdfEval(
|
|
5325
5374
|
vec3 wo, vec3 clearcoatWo, vec3 wi, vec3 clearcoatWi, SurfaceRecord surf,
|
|
5326
|
-
float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight,
|
|
5375
|
+
float diffuseWeight, float specularWeight, float transmissionWeight, float clearcoatWeight, inout float specularPdf, inout vec3 color
|
|
5327
5376
|
) {
|
|
5328
5377
|
|
|
5329
5378
|
float metalness = surf.metalness;
|
|
@@ -5386,7 +5435,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5386
5435
|
|
|
5387
5436
|
}
|
|
5388
5437
|
|
|
5389
|
-
float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf,
|
|
5438
|
+
float bsdfResult( vec3 worldWo, vec3 worldWi, SurfaceRecord surf, inout vec3 color ) {
|
|
5390
5439
|
|
|
5391
5440
|
if ( surf.volumeParticle ) {
|
|
5392
5441
|
|
|
@@ -5554,14 +5603,14 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5554
5603
|
}
|
|
5555
5604
|
|
|
5556
5605
|
// samples the color given env map with CDF and returns the pdf of the direction
|
|
5557
|
-
float sampleEquirect(
|
|
5606
|
+
float sampleEquirect( vec3 direction, inout vec3 color ) {
|
|
5558
5607
|
|
|
5559
5608
|
vec2 uv = equirectDirectionToUv( direction );
|
|
5560
|
-
color = texture2D(
|
|
5609
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
5561
5610
|
|
|
5562
|
-
float totalSum =
|
|
5611
|
+
float totalSum = envMapInfo.totalSum;
|
|
5563
5612
|
float lum = luminance( color );
|
|
5564
|
-
ivec2 resolution = textureSize(
|
|
5613
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
5565
5614
|
float pdf = lum / totalSum;
|
|
5566
5615
|
|
|
5567
5616
|
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
@@ -5569,20 +5618,20 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5569
5618
|
}
|
|
5570
5619
|
|
|
5571
5620
|
// samples a direction of the envmap with color and retrieves pdf
|
|
5572
|
-
float sampleEquirectProbability(
|
|
5621
|
+
float sampleEquirectProbability( vec2 r, inout vec3 color, inout vec3 direction ) {
|
|
5573
5622
|
|
|
5574
5623
|
// sample env map cdf
|
|
5575
|
-
float v = texture2D(
|
|
5576
|
-
float u = texture2D(
|
|
5624
|
+
float v = texture2D( envMapInfo.marginalWeights, vec2( r.x, 0.0 ) ).x;
|
|
5625
|
+
float u = texture2D( envMapInfo.conditionalWeights, vec2( r.y, v ) ).x;
|
|
5577
5626
|
vec2 uv = vec2( u, v );
|
|
5578
5627
|
|
|
5579
5628
|
vec3 derivedDirection = equirectUvToDirection( uv );
|
|
5580
5629
|
direction = derivedDirection;
|
|
5581
|
-
color = texture2D(
|
|
5630
|
+
color = texture2D( envMapInfo.map, uv ).rgb;
|
|
5582
5631
|
|
|
5583
|
-
float totalSum =
|
|
5632
|
+
float totalSum = envMapInfo.totalSum;
|
|
5584
5633
|
float lum = luminance( color );
|
|
5585
|
-
ivec2 resolution = textureSize(
|
|
5634
|
+
ivec2 resolution = textureSize( envMapInfo.map, 0 );
|
|
5586
5635
|
float pdf = lum / totalSum;
|
|
5587
5636
|
|
|
5588
5637
|
return float( resolution.x * resolution.y ) * pdf * equirectDirectionPdf( direction );
|
|
@@ -5635,24 +5684,17 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5635
5684
|
|
|
5636
5685
|
};
|
|
5637
5686
|
|
|
5638
|
-
bool
|
|
5687
|
+
bool intersectLightAtIndex( sampler2D lights, vec3 rayOrigin, vec3 rayDirection, uint l, inout LightRecord lightRec ) {
|
|
5639
5688
|
|
|
5640
5689
|
bool didHit = false;
|
|
5641
|
-
|
|
5642
|
-
for ( l = 0u; l < lightCount; l ++ ) {
|
|
5643
|
-
|
|
5644
|
-
Light light = readLightInfo( lights, l );
|
|
5645
|
-
|
|
5646
|
-
vec3 u = light.u;
|
|
5647
|
-
vec3 v = light.v;
|
|
5648
|
-
|
|
5649
|
-
// check for backface
|
|
5650
|
-
vec3 normal = normalize( cross( u, v ) );
|
|
5651
|
-
if ( dot( normal, rayDirection ) < 0.0 ) {
|
|
5690
|
+
Light light = readLightInfo( lights, l );
|
|
5652
5691
|
|
|
5653
|
-
|
|
5692
|
+
vec3 u = light.u;
|
|
5693
|
+
vec3 v = light.v;
|
|
5654
5694
|
|
|
5655
|
-
|
|
5695
|
+
// check for backface
|
|
5696
|
+
vec3 normal = normalize( cross( u, v ) );
|
|
5697
|
+
if ( dot( normal, rayDirection ) > 0.0 ) {
|
|
5656
5698
|
|
|
5657
5699
|
u *= 1.0 / dot( u, u );
|
|
5658
5700
|
v *= 1.0 / dot( v, v );
|
|
@@ -5665,17 +5707,13 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5665
5707
|
( light.type == CIRC_AREA_LIGHT_TYPE && intersectsCircle( light.position, normal, u, v, rayOrigin, rayDirection, dist ) )
|
|
5666
5708
|
) {
|
|
5667
5709
|
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
lightRec.direction = rayDirection;
|
|
5676
|
-
lightRec.type = light.type;
|
|
5677
|
-
|
|
5678
|
-
}
|
|
5710
|
+
float cosTheta = dot( rayDirection, normal );
|
|
5711
|
+
didHit = true;
|
|
5712
|
+
lightRec.dist = dist;
|
|
5713
|
+
lightRec.pdf = ( dist * dist ) / ( light.area * cosTheta );
|
|
5714
|
+
lightRec.emission = light.color * light.intensity;
|
|
5715
|
+
lightRec.direction = rayDirection;
|
|
5716
|
+
lightRec.type = light.type;
|
|
5679
5717
|
|
|
5680
5718
|
}
|
|
5681
5719
|
|
|
@@ -5687,11 +5725,6 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5687
5725
|
|
|
5688
5726
|
LightRecord randomAreaLightSample( Light light, vec3 rayOrigin, vec2 ruv ) {
|
|
5689
5727
|
|
|
5690
|
-
LightRecord lightRec;
|
|
5691
|
-
lightRec.type = light.type;
|
|
5692
|
-
|
|
5693
|
-
lightRec.emission = light.color * light.intensity;
|
|
5694
|
-
|
|
5695
5728
|
vec3 randomPos;
|
|
5696
5729
|
if( light.type == RECT_AREA_LIGHT_TYPE ) {
|
|
5697
5730
|
|
|
@@ -5712,12 +5745,17 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5712
5745
|
|
|
5713
5746
|
vec3 toLight = randomPos - rayOrigin;
|
|
5714
5747
|
float lightDistSq = dot( toLight, toLight );
|
|
5715
|
-
|
|
5748
|
+
float dist = sqrt( lightDistSq );
|
|
5749
|
+
vec3 direction = toLight / dist;
|
|
5750
|
+
vec3 lightNormal = normalize( cross( light.u, light.v ) );
|
|
5716
5751
|
|
|
5717
|
-
|
|
5752
|
+
LightRecord lightRec;
|
|
5753
|
+
lightRec.type = light.type;
|
|
5754
|
+
lightRec.emission = light.color * light.intensity;
|
|
5755
|
+
lightRec.dist = dist;
|
|
5718
5756
|
lightRec.direction = direction;
|
|
5719
5757
|
|
|
5720
|
-
|
|
5758
|
+
// TODO: the denominator is potentially zero
|
|
5721
5759
|
lightRec.pdf = lightDistSq / ( light.area * dot( direction, lightNormal ) );
|
|
5722
5760
|
|
|
5723
5761
|
return lightRec;
|
|
@@ -5765,13 +5803,15 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5765
5803
|
|
|
5766
5804
|
LightRecord randomLightSample( sampler2D lights, sampler2DArray iesProfiles, uint lightCount, vec3 rayOrigin, vec3 ruv ) {
|
|
5767
5805
|
|
|
5806
|
+
LightRecord result;
|
|
5807
|
+
|
|
5768
5808
|
// pick a random light
|
|
5769
5809
|
uint l = uint( ruv.x * float( lightCount ) );
|
|
5770
5810
|
Light light = readLightInfo( lights, l );
|
|
5771
5811
|
|
|
5772
5812
|
if ( light.type == SPOT_LIGHT_TYPE ) {
|
|
5773
5813
|
|
|
5774
|
-
|
|
5814
|
+
result = randomSpotLightSample( light, iesProfiles, rayOrigin, ruv.yz );
|
|
5775
5815
|
|
|
5776
5816
|
} else if ( light.type == POINT_LIGHT_TYPE ) {
|
|
5777
5817
|
|
|
@@ -5791,7 +5831,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5791
5831
|
rec.pdf = 1.0;
|
|
5792
5832
|
rec.emission = light.color * light.intensity * distanceFalloff;
|
|
5793
5833
|
rec.type = light.type;
|
|
5794
|
-
|
|
5834
|
+
result = rec;
|
|
5795
5835
|
|
|
5796
5836
|
} else if ( light.type == DIR_LIGHT_TYPE ) {
|
|
5797
5837
|
|
|
@@ -5802,15 +5842,17 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5802
5842
|
rec.emission = light.color * light.intensity;
|
|
5803
5843
|
rec.type = light.type;
|
|
5804
5844
|
|
|
5805
|
-
|
|
5845
|
+
result = rec;
|
|
5806
5846
|
|
|
5807
5847
|
} else {
|
|
5808
5848
|
|
|
5809
5849
|
// sample the light
|
|
5810
|
-
|
|
5850
|
+
result = randomAreaLightSample( light, rayOrigin, ruv.yz );
|
|
5811
5851
|
|
|
5812
5852
|
}
|
|
5813
5853
|
|
|
5854
|
+
return result;
|
|
5855
|
+
|
|
5814
5856
|
}
|
|
5815
5857
|
|
|
5816
5858
|
`;
|
|
@@ -5907,7 +5949,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5907
5949
|
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
5908
5950
|
// falls in the bounds of the rectangle on that same plane.
|
|
5909
5951
|
// Plane intersection: https://lousodrome.net/blog/light/2020/07/03/intersection-of-a-ray-and-a-plane/
|
|
5910
|
-
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection,
|
|
5952
|
+
bool intersectsRectangle( vec3 center, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
|
|
5911
5953
|
|
|
5912
5954
|
float t = dot( center - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
5913
5955
|
|
|
@@ -5938,7 +5980,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
5938
5980
|
|
|
5939
5981
|
// Finds the point where the ray intersects the plane defined by u and v and checks if this point
|
|
5940
5982
|
// falls in the bounds of the circle on that same plane. See above URL for a description of the plane intersection algorithm.
|
|
5941
|
-
bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection,
|
|
5983
|
+
bool intersectsCircle( vec3 position, vec3 normal, vec3 u, vec3 v, vec3 rayOrigin, vec3 rayDirection, inout float dist ) {
|
|
5942
5984
|
|
|
5943
5985
|
float t = dot( position - rayOrigin, normal ) / dot( rayDirection, normal );
|
|
5944
5986
|
|
|
@@ -6370,7 +6412,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6370
6412
|
// step through multiple surface hits and accumulate color attenuation based on transmissive surfaces
|
|
6371
6413
|
// returns true if a solid surface was hit
|
|
6372
6414
|
bool attenuateHit(
|
|
6373
|
-
|
|
6415
|
+
RenderState state,
|
|
6374
6416
|
Ray ray, float rayDist,
|
|
6375
6417
|
out vec3 color
|
|
6376
6418
|
) {
|
|
@@ -6384,7 +6426,6 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6384
6426
|
|
|
6385
6427
|
// hit results
|
|
6386
6428
|
SurfaceHit surfaceHit;
|
|
6387
|
-
LightRecord lightRec;
|
|
6388
6429
|
|
|
6389
6430
|
color = vec3( 1.0 );
|
|
6390
6431
|
|
|
@@ -6392,20 +6433,12 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6392
6433
|
// and then reset.
|
|
6393
6434
|
for ( int i = 0; i < traversals; i ++ ) {
|
|
6394
6435
|
|
|
6395
|
-
int hitType = traceScene(
|
|
6396
|
-
ray, bvh, lights, fogMaterial,
|
|
6397
|
-
surfaceHit, lightRec
|
|
6398
|
-
);
|
|
6436
|
+
int hitType = traceScene( ray, fogMaterial, surfaceHit );
|
|
6399
6437
|
|
|
6400
6438
|
if ( hitType == FOG_HIT ) {
|
|
6401
6439
|
|
|
6402
6440
|
return true;
|
|
6403
6441
|
|
|
6404
|
-
} else if ( hitType == LIGHT_HIT ) {
|
|
6405
|
-
|
|
6406
|
-
float totalDist = distance( startPoint, ray.origin + ray.direction * lightRec.dist );
|
|
6407
|
-
return totalDist < rayDist - max( totalDist, rayDist ) * 1e-4;
|
|
6408
|
-
|
|
6409
6442
|
} else if ( hitType == SURFACE_HIT ) {
|
|
6410
6443
|
|
|
6411
6444
|
float totalDist = distance( startPoint, ray.origin + ray.direction * surfaceHit.dist );
|
|
@@ -6550,22 +6583,26 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6550
6583
|
#define LIGHT_HIT 2
|
|
6551
6584
|
#define FOG_HIT 3
|
|
6552
6585
|
|
|
6586
|
+
// Passing the global variable 'lights' into this function caused shader program errors.
|
|
6587
|
+
// So global variables like 'lights' and 'bvh' were moved out of the function parameters.
|
|
6588
|
+
// For more information, refer to: https://github.com/gkjohnson/three-gpu-pathtracer/pull/457
|
|
6553
6589
|
int traceScene(
|
|
6554
6590
|
|
|
6555
|
-
Ray ray,
|
|
6556
|
-
out SurfaceHit surfaceHit, out LightRecord lightRec
|
|
6591
|
+
Ray ray, Material fogMaterial, inout SurfaceHit surfaceHit
|
|
6557
6592
|
|
|
6558
6593
|
) {
|
|
6559
6594
|
|
|
6595
|
+
int result = NO_HIT;
|
|
6560
6596
|
bool hit = bvhIntersectFirstHit( bvh, ray.origin, ray.direction, surfaceHit.faceIndices, surfaceHit.faceNormal, surfaceHit.barycoord, surfaceHit.side, surfaceHit.dist );
|
|
6561
|
-
bool lightHit = lightsClosestHit( lights.tex, lights.count, ray.origin, ray.direction, lightRec );
|
|
6562
6597
|
|
|
6563
6598
|
#if FEATURE_FOG
|
|
6564
6599
|
|
|
6565
6600
|
if ( fogMaterial.fogVolume ) {
|
|
6566
6601
|
|
|
6602
|
+
// offset the distance so we don't run into issues with particles on the same surface
|
|
6603
|
+
// as other objects
|
|
6567
6604
|
float particleDist = intersectFogVolume( fogMaterial, sobol( 1 ) );
|
|
6568
|
-
if ( particleDist +
|
|
6605
|
+
if ( particleDist + RAY_OFFSET < surfaceHit.dist ) {
|
|
6569
6606
|
|
|
6570
6607
|
surfaceHit.side = 1.0;
|
|
6571
6608
|
surfaceHit.faceNormal = normalize( - ray.direction );
|
|
@@ -6578,19 +6615,13 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6578
6615
|
|
|
6579
6616
|
#endif
|
|
6580
6617
|
|
|
6581
|
-
if ( lightHit && ( lightRec.dist < surfaceHit.dist || ! hit ) ) {
|
|
6582
|
-
|
|
6583
|
-
return LIGHT_HIT;
|
|
6584
|
-
|
|
6585
|
-
}
|
|
6586
|
-
|
|
6587
6618
|
if ( hit ) {
|
|
6588
6619
|
|
|
6589
|
-
|
|
6620
|
+
result = SURFACE_HIT;
|
|
6590
6621
|
|
|
6591
6622
|
}
|
|
6592
6623
|
|
|
6593
|
-
return
|
|
6624
|
+
return result;
|
|
6594
6625
|
|
|
6595
6626
|
}
|
|
6596
6627
|
|
|
@@ -6603,7 +6634,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6603
6634
|
int getSurfaceRecord(
|
|
6604
6635
|
Material material, SurfaceHit surfaceHit, sampler2DArray attributesArray,
|
|
6605
6636
|
float accumulatedRoughness,
|
|
6606
|
-
|
|
6637
|
+
inout SurfaceRecord surf
|
|
6607
6638
|
) {
|
|
6608
6639
|
|
|
6609
6640
|
if ( material.fogVolume ) {
|
|
@@ -6923,6 +6954,8 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6923
6954
|
|
|
6924
6955
|
vec3 directLightContribution( vec3 worldWo, SurfaceRecord surf, RenderState state, vec3 rayOrigin ) {
|
|
6925
6956
|
|
|
6957
|
+
vec3 result = vec3( 0.0 );
|
|
6958
|
+
|
|
6926
6959
|
// uniformly pick a light or environment map
|
|
6927
6960
|
if( lightsDenom != 0.0 && sobol( 5 ) < float( lights.count ) / lightsDenom ) {
|
|
6928
6961
|
|
|
@@ -6944,7 +6977,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6944
6977
|
if (
|
|
6945
6978
|
lightRec.pdf > 0.0 &&
|
|
6946
6979
|
isDirectionValid( lightRec.direction, surf.normal, surf.faceNormal ) &&
|
|
6947
|
-
! attenuateHit(
|
|
6980
|
+
! attenuateHit( state, lightRay, lightRec.dist, attenuatedColor )
|
|
6948
6981
|
) {
|
|
6949
6982
|
|
|
6950
6983
|
// get the material pdf
|
|
@@ -6956,7 +6989,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6956
6989
|
// weight the direct light contribution
|
|
6957
6990
|
float lightPdf = lightRec.pdf / lightsDenom;
|
|
6958
6991
|
float misWeight = lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ? 1.0 : misHeuristic( lightPdf, lightMaterialPdf );
|
|
6959
|
-
|
|
6992
|
+
result = attenuatedColor * lightRec.emission * state.throughputColor * sampleColor * misWeight / lightPdf;
|
|
6960
6993
|
|
|
6961
6994
|
}
|
|
6962
6995
|
|
|
@@ -6966,7 +6999,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6966
6999
|
|
|
6967
7000
|
// find a sample in the environment map to include in the contribution
|
|
6968
7001
|
vec3 envColor, envDirection;
|
|
6969
|
-
float envPdf = sampleEquirectProbability(
|
|
7002
|
+
float envPdf = sampleEquirectProbability( sobol2( 7 ), envColor, envDirection );
|
|
6970
7003
|
envDirection = invEnvRotation3x3 * envDirection;
|
|
6971
7004
|
|
|
6972
7005
|
// this env sampling is not set up for transmissive sampling and yields overly bright
|
|
@@ -6987,7 +7020,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6987
7020
|
if (
|
|
6988
7021
|
envPdf > 0.0 &&
|
|
6989
7022
|
isDirectionValid( envDirection, surf.normal, surf.faceNormal ) &&
|
|
6990
|
-
! attenuateHit(
|
|
7023
|
+
! attenuateHit( state, envRay, INFINITY, attenuatedColor )
|
|
6991
7024
|
) {
|
|
6992
7025
|
|
|
6993
7026
|
// get the material pdf
|
|
@@ -6999,7 +7032,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
6999
7032
|
// weight the direct light contribution
|
|
7000
7033
|
envPdf /= lightsDenom;
|
|
7001
7034
|
float misWeight = misHeuristic( envPdf, envMaterialPdf );
|
|
7002
|
-
|
|
7035
|
+
result = attenuatedColor * environmentIntensity * envColor * state.throughputColor * sampleColor * misWeight / envPdf;
|
|
7003
7036
|
|
|
7004
7037
|
}
|
|
7005
7038
|
|
|
@@ -7007,7 +7040,9 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7007
7040
|
|
|
7008
7041
|
}
|
|
7009
7042
|
|
|
7010
|
-
return
|
|
7043
|
+
// Function changed to have a single return statement to potentially help with crashes on Mac OS.
|
|
7044
|
+
// See issue #470
|
|
7045
|
+
return result;
|
|
7011
7046
|
|
|
7012
7047
|
}
|
|
7013
7048
|
|
|
@@ -7036,6 +7071,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7036
7071
|
FEATURE_DOF: 1,
|
|
7037
7072
|
FEATURE_BACKGROUND_MAP: 0,
|
|
7038
7073
|
FEATURE_FOG: 1,
|
|
7074
|
+
FEATURE_SOBOL: 0,
|
|
7039
7075
|
// 0 = Perspective
|
|
7040
7076
|
// 1 = Orthographic
|
|
7041
7077
|
// 2 = Equirectangular
|
|
@@ -7105,13 +7141,36 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7105
7141
|
#include <common>
|
|
7106
7142
|
|
|
7107
7143
|
// bvh intersection
|
|
7108
|
-
${ threeMeshBvh.
|
|
7109
|
-
${ threeMeshBvh.
|
|
7144
|
+
${ threeMeshBvh.BVHShaderGLSL.common_functions }
|
|
7145
|
+
${ threeMeshBvh.BVHShaderGLSL.bvh_struct_definitions }
|
|
7146
|
+
${ threeMeshBvh.BVHShaderGLSL.bvh_ray_functions }
|
|
7147
|
+
|
|
7148
|
+
// uniform structs
|
|
7149
|
+
${ cameraStructGLSL }
|
|
7150
|
+
${ lightsStructGLSL }
|
|
7151
|
+
${ equirectStructGLSL }
|
|
7152
|
+
${ materialStructGLSL }
|
|
7110
7153
|
|
|
7111
7154
|
// random
|
|
7112
7155
|
${ pcgGLSL }
|
|
7113
|
-
|
|
7114
|
-
|
|
7156
|
+
#if FEATURE_SOBOL
|
|
7157
|
+
|
|
7158
|
+
${ sobolCommonGLSL }
|
|
7159
|
+
${ sobolSamplingGLSL }
|
|
7160
|
+
|
|
7161
|
+
#else
|
|
7162
|
+
|
|
7163
|
+
// Using the sobol functions seems to break the the compiler on MacOS
|
|
7164
|
+
// - specifically the "sobolReverseBits" function.
|
|
7165
|
+
uint sobolPixelIndex = 0u;
|
|
7166
|
+
uint sobolPathIndex = 0u;
|
|
7167
|
+
uint sobolBounceIndex = 0u;
|
|
7168
|
+
float sobol( int v ) { return rand(); }
|
|
7169
|
+
vec2 sobol2( int v ) { return rand2(); }
|
|
7170
|
+
vec3 sobol3( int v ) { return rand3(); }
|
|
7171
|
+
vec4 sobol4( int v ) { return rand4(); }
|
|
7172
|
+
|
|
7173
|
+
#endif
|
|
7115
7174
|
|
|
7116
7175
|
// common
|
|
7117
7176
|
${ arraySamplerTexelFetchGLSL }
|
|
@@ -7120,20 +7179,6 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7120
7179
|
${ mathGLSL }
|
|
7121
7180
|
${ intersectShapesGLSL }
|
|
7122
7181
|
|
|
7123
|
-
// uniform structs
|
|
7124
|
-
${ cameraStructGLSL }
|
|
7125
|
-
${ lightsStructGLSL }
|
|
7126
|
-
${ equirectStructGLSL }
|
|
7127
|
-
${ materialStructGLSL }
|
|
7128
|
-
${ fogMaterialBvhGLSL }
|
|
7129
|
-
|
|
7130
|
-
// sampling
|
|
7131
|
-
${ shapeSamplingGLSL }
|
|
7132
|
-
${ bsdfSamplingGLSL }
|
|
7133
|
-
${ equirectSamplingGLSL }
|
|
7134
|
-
${ lightSamplingGLSL }
|
|
7135
|
-
${ fogGLSL }
|
|
7136
|
-
|
|
7137
7182
|
// environment
|
|
7138
7183
|
uniform EquirectHdrInfo envMapInfo;
|
|
7139
7184
|
uniform mat4 environmentRotation;
|
|
@@ -7185,6 +7230,14 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7185
7230
|
mat3 invEnvRotation3x3;
|
|
7186
7231
|
float lightsDenom;
|
|
7187
7232
|
|
|
7233
|
+
// sampling
|
|
7234
|
+
${ fogMaterialBvhGLSL }
|
|
7235
|
+
${ shapeSamplingGLSL }
|
|
7236
|
+
${ bsdfSamplingGLSL }
|
|
7237
|
+
${ equirectSamplingGLSL }
|
|
7238
|
+
${ lightSamplingGLSL }
|
|
7239
|
+
${ fogGLSL }
|
|
7240
|
+
|
|
7188
7241
|
float applyFilteredGlossy( float roughness, float accumulatedRoughness ) {
|
|
7189
7242
|
|
|
7190
7243
|
return clamp(
|
|
@@ -7224,7 +7277,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7224
7277
|
|
|
7225
7278
|
// init
|
|
7226
7279
|
rng_initialize( gl_FragCoord.xy, seed );
|
|
7227
|
-
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) |
|
|
7280
|
+
sobolPixelIndex = ( uint( gl_FragCoord.x ) << 16 ) | uint( gl_FragCoord.y );
|
|
7228
7281
|
sobolPathIndex = uint( seed );
|
|
7229
7282
|
|
|
7230
7283
|
// get camera ray
|
|
@@ -7240,7 +7293,6 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7240
7293
|
|
|
7241
7294
|
// surface results
|
|
7242
7295
|
SurfaceHit surfaceHit;
|
|
7243
|
-
LightRecord lightRec;
|
|
7244
7296
|
ScatterRecord scatterRec;
|
|
7245
7297
|
|
|
7246
7298
|
// path tracing state
|
|
@@ -7249,7 +7301,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7249
7301
|
#if FEATURE_FOG
|
|
7250
7302
|
|
|
7251
7303
|
state.fogMaterial.fogVolume = bvhIntersectFogVolumeHit(
|
|
7252
|
-
|
|
7304
|
+
ray.origin, - ray.direction,
|
|
7253
7305
|
materialIndexAttribute, materials,
|
|
7254
7306
|
state.fogMaterial
|
|
7255
7307
|
);
|
|
@@ -7264,44 +7316,42 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7264
7316
|
state.traversals = bounces - i;
|
|
7265
7317
|
state.firstRay = i == 0 && state.transmissiveTraversals == transmissiveBounces;
|
|
7266
7318
|
|
|
7267
|
-
int hitType = traceScene(
|
|
7268
|
-
ray, bvh, lights, state.fogMaterial,
|
|
7269
|
-
surfaceHit, lightRec
|
|
7270
|
-
);
|
|
7319
|
+
int hitType = traceScene( ray, state.fogMaterial, surfaceHit );
|
|
7271
7320
|
|
|
7272
|
-
if
|
|
7321
|
+
// check if we intersect any lights and accumulate the light contribution
|
|
7322
|
+
// TODO: we can add support for light surface rendering in the else condition if we
|
|
7323
|
+
// add the ability to toggle visibility of the the light
|
|
7324
|
+
if ( ! state.firstRay && ! state.transmissiveRay ) {
|
|
7273
7325
|
|
|
7274
|
-
|
|
7326
|
+
LightRecord lightRec;
|
|
7327
|
+
float lightDist = hitType == NO_HIT ? INFINITY : surfaceHit.dist;
|
|
7328
|
+
for ( uint i = 0u; i < lights.count; i ++ ) {
|
|
7275
7329
|
|
|
7276
|
-
|
|
7330
|
+
if (
|
|
7331
|
+
intersectLightAtIndex( lights.tex, ray.origin, ray.direction, i, lightRec ) &&
|
|
7332
|
+
lightRec.dist < lightDist
|
|
7333
|
+
) {
|
|
7277
7334
|
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
#if FEATURE_MIS
|
|
7281
|
-
|
|
7282
|
-
// NOTE: we skip MIS for punctual lights since they are not supported in forward PT case
|
|
7283
|
-
if ( lightRec.type == SPOT_LIGHT_TYPE || lightRec.type == DIR_LIGHT_TYPE || lightRec.type == POINT_LIGHT_TYPE ) {
|
|
7284
|
-
|
|
7285
|
-
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
7286
|
-
|
|
7287
|
-
} else {
|
|
7335
|
+
#if FEATURE_MIS
|
|
7288
7336
|
|
|
7289
7337
|
// weight the contribution
|
|
7338
|
+
// NOTE: Only area lights are supported for forward sampling and can be hit
|
|
7290
7339
|
float misWeight = misHeuristic( scatterRec.pdf, lightRec.pdf / lightsDenom );
|
|
7291
7340
|
gl_FragColor.rgb += lightRec.emission * state.throughputColor * misWeight;
|
|
7292
7341
|
|
|
7293
|
-
|
|
7342
|
+
#else
|
|
7294
7343
|
|
|
7295
|
-
|
|
7344
|
+
gl_FragColor.rgb += lightRec.emission * state.throughputColor;
|
|
7296
7345
|
|
|
7297
|
-
|
|
7346
|
+
#endif
|
|
7298
7347
|
|
|
7299
|
-
|
|
7348
|
+
}
|
|
7300
7349
|
|
|
7301
7350
|
}
|
|
7302
|
-
break;
|
|
7303
7351
|
|
|
7304
|
-
}
|
|
7352
|
+
}
|
|
7353
|
+
|
|
7354
|
+
if ( hitType == NO_HIT ) {
|
|
7305
7355
|
|
|
7306
7356
|
if ( state.firstRay || state.transmissiveRay ) {
|
|
7307
7357
|
|
|
@@ -7314,7 +7364,7 @@ bool bvhIntersectFogVolumeHit(
|
|
|
7314
7364
|
|
|
7315
7365
|
// get the PDF of the hit envmap point
|
|
7316
7366
|
vec3 envColor;
|
|
7317
|
-
float envPdf = sampleEquirect(
|
|
7367
|
+
float envPdf = sampleEquirect( envRotation3x3 * ray.direction, envColor );
|
|
7318
7368
|
envPdf /= lightsDenom;
|
|
7319
7369
|
|
|
7320
7370
|
// and weight the contribution
|