rayzee 8.8.2 → 9.1.0
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 +210 -20
- package/dist/{NeuralRetouch-CYOJ21Wn.js → NeuralRetouch-BRquqfmZ.js} +1 -1
- package/dist/{NeuralSuperRes-Dc6jRYke.js → NeuralSuperRes-CbNvQjCw.js} +5 -2
- package/dist/{ToneMapGPU-BVE852iN.js → ToneMapGPU-DpUZDMbQ.js} +2 -1
- package/dist/rayzee.es.js +10795 -5324
- package/dist/rayzee.umd.js +279 -268
- package/package.json +1 -1
- package/src/AssetConfig.js +4 -0
- package/src/EngineDefaults.js +60 -76
- package/src/EngineEvents.js +7 -0
- package/src/EngineIssues.js +6 -0
- package/src/Headless.js +3 -1
- package/src/Passes/AIUpscaler.js +2 -1
- package/src/Passes/OIDNDenoiser.js +3 -6
- package/src/Passes/OIDNTemporalHistory.js +25 -7
- package/src/PathTracerApp.js +313 -25
- package/src/Processor/ArchiveCache.js +120 -0
- package/src/Processor/ArchiveReader.js +179 -32
- package/src/Processor/AssetLoader.js +523 -76
- package/src/Processor/AtmosphereModel.js +465 -0
- package/src/Processor/BVHBuilder.js +4 -1
- package/src/Processor/BVHLeafFold.js +100 -0
- package/src/Processor/BVHRefitter.js +98 -214
- package/src/Processor/ChunkedRecords.js +189 -4
- package/src/Processor/EmissiveTriangleBuilder.js +8 -0
- package/src/Processor/GeometryExtractor.js +238 -40
- package/src/Processor/InstanceTable.js +55 -37
- package/src/Processor/PBRT/PBRTCurves.js +104 -27
- package/src/Processor/PBRT/PBRTParser.js +132 -22
- package/src/Processor/PBRT/PBRTSceneBuilder.js +210 -55
- package/src/Processor/PBRT/buffers.js +27 -0
- package/src/Processor/PBRT/index.js +55 -15
- package/src/Processor/PackedRayBuffer.js +10 -13
- package/src/Processor/ParallelBVHBuilder.js +36 -15
- package/src/Processor/PhysicalSky.js +308 -0
- package/src/Processor/QueueManager.js +1 -0
- package/src/Processor/SceneProcessor.js +1132 -181
- package/src/Processor/SplitBLAS.js +249 -0
- package/src/Processor/SunPosition.js +41 -0
- package/src/Processor/TextureCreator.js +21 -0
- package/src/Processor/Workers/AIUpscalerWorker.js +79 -52
- package/src/Processor/Workers/BVHWorker.js +17 -13
- package/src/Processor/ZipReader.js +207 -0
- package/src/RenderSettings.js +49 -8
- package/src/SceneState/SceneState.js +367 -0
- package/src/SceneState/portable.js +52 -0
- package/src/Stages/MotionVector.js +8 -42
- package/src/Stages/NRD.js +30 -21
- package/src/Stages/NormalDepth.js +12 -23
- package/src/Stages/PathTracer.js +114 -6
- package/src/Stages/PathTracerStage.js +251 -104
- package/src/Storage/BLASCache.js +190 -0
- package/src/Storage/CDFCache.js +77 -0
- package/src/Storage/DownloadCache.js +266 -0
- package/src/Storage/GeometrySpill.js +217 -0
- package/src/Storage/SceneGraphCodec.js +503 -0
- package/src/Storage/SpillStore.js +112 -0
- package/src/Storage/StorageManager.js +934 -0
- package/src/Storage/StorageOps.js +137 -0
- package/src/Storage/StorageWorker.js +37 -0
- package/src/Storage/events.js +29 -0
- package/src/Storage/identity.js +77 -0
- package/src/Storage/index.js +9 -0
- package/src/Storage/inlineTransport.js +24 -0
- package/src/Storage/locks.js +99 -0
- package/src/Storage/openStorage.js +87 -0
- package/src/Storage/sceneCachePolicy.js +12 -0
- package/src/Storage/shared.js +9 -0
- package/src/Storage/transport.js +62 -0
- package/src/TSL/Atmosphere.js +684 -0
- package/src/TSL/BVHTraversal.js +288 -239
- package/src/TSL/CameraRay.js +99 -14
- package/src/TSL/Common.js +11 -2
- package/src/TSL/DebugKernel.js +2 -2
- package/src/TSL/Displacement.js +6 -6
- package/src/TSL/EmissiveSampling.js +5 -5
- package/src/TSL/EnvironmentCDF.js +176 -0
- package/src/TSL/GenerateKernel.js +5 -5
- package/src/TSL/HitFacet.js +4 -4
- package/src/TSL/LightsDirect.js +8 -8
- package/src/TSL/LightsSampling.js +55 -37
- package/src/TSL/Random.js +1 -0
- package/src/TSL/ShadeKernel.js +75 -19
- package/src/TSL/Sun.js +40 -0
- package/src/TSL/TextureSampling.js +6 -7
- package/src/index.js +22 -0
- package/src/managers/CameraManager.js +412 -56
- package/src/managers/DenoisingManager.js +4 -3
- package/src/managers/EnvironmentManager.js +263 -33
- package/src/managers/GoboManager.js +19 -8
- package/src/managers/IESManager.js +3 -3
- package/src/managers/InteractionManager.js +30 -2
- package/src/managers/LightManager.js +98 -5
- package/src/managers/MaterialDataManager.js +22 -2
- package/src/managers/TransformManager.js +26 -0
- package/src/managers/UniformManager.js +11 -7
- package/src/managers/VideoRenderManager.js +38 -17
- package/src/managers/ViewCamera.js +77 -0
- package/src/managers/WalkControls.js +262 -0
- package/src/managers/helpers/OutlineHelper.js +22 -2
- package/src/managers/timeline/CameraTrack.js +235 -0
- package/src/managers/timeline/TimelineManager.js +146 -0
- package/src/version.js +3 -0
- package/src/Processor/ProceduralSky.js +0 -291
|
@@ -88,6 +88,7 @@ import {
|
|
|
88
88
|
sampleEquirectProbability,
|
|
89
89
|
} from './Environment.js';
|
|
90
90
|
import { shadowTerminatorOrigin } from './ShadowTerminator.js';
|
|
91
|
+
import { sunRadianceToward, sampleSunDisc } from './Sun.js';
|
|
91
92
|
|
|
92
93
|
const TWO_PI = 2.0 * PI;
|
|
93
94
|
|
|
@@ -798,6 +799,8 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
798
799
|
// The facet on the viewer's side, which shadow rays are offset off, and the shadow terminator lift
|
|
799
800
|
// (ShadowTerminator.js) for the light and environment ones
|
|
800
801
|
terminatorLift, facetNormal, terminatorCutoff,
|
|
802
|
+
// The physical sky's sun (Sun.js); its BSDF-sampled partner is the miss branch in ShadeKernel.
|
|
803
|
+
hasSun, sunDirection, sunRadiance, sunParams,
|
|
801
804
|
] ) => {
|
|
802
805
|
|
|
803
806
|
const totalContribution = vec3( 0.0 ).toVar();
|
|
@@ -987,55 +990,71 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
987
990
|
|
|
988
991
|
} );
|
|
989
992
|
// =====================================================================
|
|
990
|
-
// DETERMINISTIC ENVIRONMENT NEE
|
|
991
|
-
//
|
|
992
|
-
// estimator together with the implicit miss check in the main loop.
|
|
993
|
+
// DETERMINISTIC ENVIRONMENT NEE — the map, then the physical sky's sun, each MIS'd with its
|
|
994
|
+
// partner at the miss. One loop, so the shadow ray and BSDF evaluation are emitted once.
|
|
993
995
|
// =====================================================================
|
|
994
996
|
|
|
995
997
|
If( enableEnvironmentLight, () => {
|
|
996
998
|
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
+
const passes = select( hasSun.greaterThan( int( 0 ) ), int( 2 ), int( 1 ) );
|
|
1000
|
+
Loop( { start: int( 0 ), end: passes, type: 'int', condition: '<', name: 'envPass' }, ( { envPass } ) => {
|
|
999
1001
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
).toVar();
|
|
1002
|
+
const isSun = envPass.equal( int( 1 ) ).toVar();
|
|
1003
|
+
const radiance = vec3( 0.0 ).toVar();
|
|
1004
|
+
const direction = vec3( 0.0, 1.0, 0.0 ).toVar();
|
|
1005
|
+
const lightPdf = float( 0.0 ).toVar();
|
|
1005
1006
|
|
|
1006
|
-
|
|
1007
|
-
const envPdf = envSampleResult.w.toVar();
|
|
1007
|
+
If( isSun, () => {
|
|
1008
1008
|
|
|
1009
|
-
|
|
1009
|
+
const sunXi = getRandomSample2D( pixelCoord, int( 0 ), dimBase.add( int( 9 ) ), rngState, resolution, frame );
|
|
1010
|
+
direction.assign( sampleSunDisc( sunDirection, sunParams, sunXi ) );
|
|
1011
|
+
radiance.assign( sunRadianceToward( direction, sunDirection, sunRadiance, sunParams ).mul( environmentIntensity ) );
|
|
1012
|
+
lightPdf.assign( select( radiance.x.add( radiance.y ).add( radiance.z ).greaterThan( 0.0 ), float( 1.0 ).div( sunParams.y ), float( 0.0 ) ) );
|
|
1010
1013
|
|
|
1011
|
-
|
|
1014
|
+
} ).Else( () => {
|
|
1012
1015
|
|
|
1013
|
-
|
|
1016
|
+
const envRandom = getRandomSample2D( pixelCoord, int( 0 ), dimBase.add( int( 1 ) ), rngState, resolution, frame ).toVar();
|
|
1017
|
+
const envColor = vec3( 0.0 ).toVar();
|
|
1018
|
+
const envSampleResult = sampleEquirectProbability(
|
|
1019
|
+
envTexture, envCDFTexture,
|
|
1020
|
+
envMatrix, environmentIntensity, envTotalSum, envCompensationDelta, envResolution, envRandom, envColor
|
|
1021
|
+
).toVar();
|
|
1022
|
+
direction.assign( envSampleResult.xyz );
|
|
1023
|
+
radiance.assign( envColor );
|
|
1024
|
+
lightPdf.assign( envSampleResult.w );
|
|
1014
1025
|
|
|
1015
|
-
|
|
1026
|
+
} );
|
|
1016
1027
|
|
|
1017
|
-
|
|
1028
|
+
If( lightPdf.greaterThan( 0.0 ), () => {
|
|
1018
1029
|
|
|
1019
|
-
|
|
1020
|
-
// discrete-light path above.
|
|
1021
|
-
const envDots = DotProducts.wrap( computeDotProductsAniso( hitNormal, viewDir, envDirection, material ) );
|
|
1022
|
-
const brdfValue = evaluateMaterialResponseFromDots( material, envDots );
|
|
1023
|
-
const bPdf = calculateMaterialPDFFromDots( material, envDots ).toVar();
|
|
1024
|
-
|
|
1025
|
-
// Balance heuristic for env MIS — optimal for MIS-compensated PDFs (Karlík et al. 2019).
|
|
1026
|
-
// The implicit path uses material combinedPdf as prevBouncePdf at the miss check.
|
|
1027
|
-
const misW = select(
|
|
1028
|
-
bPdf.greaterThan( 0.0 ),
|
|
1029
|
-
balanceHeuristic( { pdf1: envPdf, pdf2: bPdf } ),
|
|
1030
|
-
float( 1.0 )
|
|
1031
|
-
).toVar();
|
|
1032
|
-
|
|
1033
|
-
// Base contribution WITHOUT visibility (deterministic estimator; no stochastic scaling).
|
|
1034
|
-
const baseContribution = envColor.mul( brdfValue ).mul( NoL ).mul( misW ).div( max( envPdf, 1e-10 ) );
|
|
1035
|
-
totalContribution.addAssign( baseContribution.mul( visibility ) );
|
|
1036
|
-
If( wantUnoccluded, () => {
|
|
1030
|
+
const NoL = max( float( 0.0 ), dot( hitNormal, direction ) ).toVar();
|
|
1037
1031
|
|
|
1038
|
-
|
|
1032
|
+
If( NoL.greaterThan( 0.0 ).and( isDirectionValid( { direction, surfaceNormal: geomNormal } ) ), () => {
|
|
1033
|
+
|
|
1034
|
+
const visibility = shadow( lightShadowOrigin( direction ), direction, float( 1e20 ) );
|
|
1035
|
+
|
|
1036
|
+
If( visibility.greaterThan( 0.0 ).or( wantUnoccluded ), () => {
|
|
1037
|
+
|
|
1038
|
+
const envDots = DotProducts.wrap( computeDotProductsAniso( hitNormal, viewDir, direction, material ) );
|
|
1039
|
+
const brdfValue = evaluateMaterialResponseFromDots( material, envDots );
|
|
1040
|
+
const bPdf = calculateMaterialPDFFromDots( material, envDots ).toVar();
|
|
1041
|
+
|
|
1042
|
+
// The map pairs with the balance heuristic — optimal for its MIS-compensated pdf
|
|
1043
|
+
// (Karlík et al. 2019); the sun, a small bright source, with the power heuristic.
|
|
1044
|
+
const misW = select(
|
|
1045
|
+
bPdf.greaterThan( 0.0 ),
|
|
1046
|
+
select( isSun, powerHeuristic( { pdf1: lightPdf, pdf2: bPdf } ), balanceHeuristic( { pdf1: lightPdf, pdf2: bPdf } ) ),
|
|
1047
|
+
float( 1.0 )
|
|
1048
|
+
).toVar();
|
|
1049
|
+
|
|
1050
|
+
// Base contribution WITHOUT visibility (deterministic estimator; no stochastic scaling).
|
|
1051
|
+
const baseContribution = radiance.mul( brdfValue ).mul( NoL ).mul( misW ).div( max( lightPdf, 1e-10 ) );
|
|
1052
|
+
totalContribution.addAssign( baseContribution.mul( visibility ) );
|
|
1053
|
+
If( wantUnoccluded, () => {
|
|
1054
|
+
|
|
1055
|
+
unoccludedContribution.addAssign( baseContribution );
|
|
1056
|
+
|
|
1057
|
+
} );
|
|
1039
1058
|
|
|
1040
1059
|
} );
|
|
1041
1060
|
|
|
@@ -1047,7 +1066,6 @@ export const calculateDirectLightingUnified = Fn( ( [
|
|
|
1047
1066
|
|
|
1048
1067
|
} );
|
|
1049
1068
|
|
|
1050
|
-
|
|
1051
1069
|
// EMISSIVE TRIANGLE DIRECT LIGHTING
|
|
1052
1070
|
// NOTE: Emissive triangle sampling is handled separately in pathtracer_core.fs
|
|
1053
1071
|
// to bypass firefly suppression. Do not add it here to avoid double-counting.
|
package/src/TSL/Random.js
CHANGED
|
@@ -132,6 +132,7 @@ export const RandomPointInCircle = ( rngState ) => {
|
|
|
132
132
|
// +6 subsurface HG scatter dir (ShadeKernel)
|
|
133
133
|
// +7 ground-catcher cosine BSDF (ShadeKernel)
|
|
134
134
|
// +8 indirect-strategy direction (LightsIndirect)
|
|
135
|
+
// +9 physical-sky sun disc (LightsSampling)
|
|
135
136
|
// 1D +0 (free — was the {lights,BRDF} stochastic strategy pick)
|
|
136
137
|
// +1 emissive-triangle pick (EmissiveSampling / LightBVHSampling)
|
|
137
138
|
// +2 BSDF lobe selection (ShadeKernel)
|
package/src/TSL/ShadeKernel.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ShadeKernel.js — wavefront material eval + bounce generation. 256×1 workgroup, 1D dispatch.
|
|
3
|
-
* 10 storage-buffer bindings: bvh,
|
|
4
|
-
* (at the device per-stage limit of 10; envCDF is a texture, not a storage buffer).
|
|
3
|
+
* 10 storage-buffer bindings: bvh, triGeo, triShade, mat, light, ray, hit (+ RNG state), gBuffer,
|
|
4
|
+
* counters, activeIndices (at the device per-stage limit of 10; envCDF is a texture, not a storage buffer).
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
Fn, float, vec2, vec3, vec4, int, uint,
|
|
9
9
|
bool as tslBool,
|
|
10
|
-
If, Loop, normalize, max, min, exp, log, clamp, dot, length, select, smoothstep,
|
|
10
|
+
If, Loop, normalize, max, min, exp, log, clamp, dot, length, select, smoothstep, acos,
|
|
11
11
|
instanceIndex,
|
|
12
12
|
sampler,
|
|
13
13
|
atomicAdd, atomicLoad, atomicStore, uintBitsToFloat,
|
|
@@ -28,6 +28,7 @@ import { handleMaterialTransparency, MaterialInteractionResult } from './Materia
|
|
|
28
28
|
import { sampleChromaticCollision, sampleHenyeyGreenstein, subsurfaceCoefficients, CollisionSample, MediumCoeffs } from './Subsurface.js';
|
|
29
29
|
import { calculateIndirectLighting } from './LightsIndirect.js';
|
|
30
30
|
import { IndirectLightingResult, sampleCone } from './LightsCore.js';
|
|
31
|
+
import { sunRadianceToward } from './Sun.js';
|
|
31
32
|
import { regularizePathContribution, generateSampledDirection, computeNDCDepth, handleRussianRoulette } from './PathTracerCore.js';
|
|
32
33
|
import { evaluateSpecularDFG, baseFresnelParams } from './MaterialProperties.js';
|
|
33
34
|
import { NRD_HIT_DIST_A, NRD_HIT_DIST_B } from '../EngineDefaults.js';
|
|
@@ -63,6 +64,7 @@ import {
|
|
|
63
64
|
writeGBuffer, writeGBufferHitDist, readGBuffer, gbDecodeNormalDepth,
|
|
64
65
|
readRayRadiance,
|
|
65
66
|
readFeatureThroughput, writeFeatureThroughput,
|
|
67
|
+
readRngState, writeRngState,
|
|
66
68
|
} from '../Processor/PackedRayBuffer.js';
|
|
67
69
|
|
|
68
70
|
const WG_SIZE = 256;
|
|
@@ -79,7 +81,7 @@ export function buildShadeKernel( params ) {
|
|
|
79
81
|
bvhBuffer, triangleBuffer, materialBuffer,
|
|
80
82
|
envCDFTexture,
|
|
81
83
|
lightBuffer,
|
|
82
|
-
rayBufferRW,
|
|
84
|
+
rayBufferRW, hitBufferRW, gBufferRW,
|
|
83
85
|
counters,
|
|
84
86
|
activeIndicesRO,
|
|
85
87
|
envTexture, environmentIntensity, envMatrix,
|
|
@@ -111,6 +113,7 @@ export function buildShadeKernel( params ) {
|
|
|
111
113
|
// Aux G-buffer (normal/depth/albedo + surface ID) feeds only the denoiser/OIDN MRT. Gated by a
|
|
112
114
|
// live uniform (1 = denoiser on) so the wavefront skips these writes when nothing consumes them.
|
|
113
115
|
auxGBufferEnabled,
|
|
116
|
+
hasSun, sunDirection, sunRadiance, sunParams,
|
|
114
117
|
} = params;
|
|
115
118
|
|
|
116
119
|
const auxOn = auxGBufferEnabled.greaterThan( uint( 0 ) );
|
|
@@ -196,7 +199,7 @@ export function buildShadeKernel( params ) {
|
|
|
196
199
|
const currentRadiance = readRayRadiance( rayBufferRW, rayID ).toVar();
|
|
197
200
|
// One ray per pixel: rayID is the pixel index.
|
|
198
201
|
const pixelIndex = rayID;
|
|
199
|
-
const rngState =
|
|
202
|
+
const rngState = readRngState( hitBufferRW, rayID ).toVar();
|
|
200
203
|
|
|
201
204
|
// STBN keyed on (GLOBAL pixel, dimension, frame). pixelIndex is the LOCAL path slot; the global pixel
|
|
202
205
|
// = chunkRowBase·W + localSlot, so the blue-noise pattern stays spatially aligned across row-band chunks
|
|
@@ -216,13 +219,13 @@ export function buildShadeKernel( params ) {
|
|
|
216
219
|
// deferring continue (a missed persist = stale tint). 1 = untinted (direct hit → today's albedo).
|
|
217
220
|
const featCarry = readFeatureThroughput( rayBufferRW, rayID ).toVar();
|
|
218
221
|
|
|
219
|
-
const hitDist = readHitDistance(
|
|
220
|
-
const hitNormal = readHitNormal(
|
|
222
|
+
const hitDist = readHitDistance( hitBufferRW, rayID ).toVar();
|
|
223
|
+
const hitNormal = readHitNormal( hitBufferRW, rayID ).toVar();
|
|
221
224
|
// hitInfo.uv is the interpolated texture UV (not barycentrics)
|
|
222
|
-
const hitUV = readHitBarycentrics(
|
|
223
|
-
const hitMatIdx = readHitMaterialIndex(
|
|
224
|
-
const hitTriIdx = readHitTriangleIndex(
|
|
225
|
-
const hitInstance = readHitInstanceLeaf(
|
|
225
|
+
const hitUV = readHitBarycentrics( hitBufferRW, rayID ).toVar();
|
|
226
|
+
const hitMatIdx = readHitMaterialIndex( hitBufferRW, rayID ).toVar();
|
|
227
|
+
const hitTriIdx = readHitTriangleIndex( hitBufferRW, rayID ).toVar();
|
|
228
|
+
const hitInstance = readHitInstanceLeaf( hitBufferRW, rayID ).toVar();
|
|
226
229
|
|
|
227
230
|
// per-ray camera-bounce depth — advances ONLY on opaque scatter (free bounces don't); drives termination (maxBounces). Megakernel: effectiveBounces.
|
|
228
231
|
const cameraDepth = readPathBounces( rayBufferRW, rayID ).toVar();
|
|
@@ -287,6 +290,7 @@ export function buildShadeKernel( params ) {
|
|
|
287
290
|
enableEnvironmentLight,
|
|
288
291
|
tslBool( true ), // wantUnoccluded
|
|
289
292
|
vec3( 0.0 ), planeN, float( 0.0 ),
|
|
293
|
+
hasSun, sunDirection, sunRadiance, sunParams,
|
|
290
294
|
) ).toVar();
|
|
291
295
|
|
|
292
296
|
const lumShad = max( dot( dual.shadowed, REC709_LUMINANCE_COEFFICIENTS ), float( 0.0 ) );
|
|
@@ -357,7 +361,7 @@ export function buildShadeKernel( params ) {
|
|
|
357
361
|
writeRayRadiance( rayBufferRW, rayID, vec4( outRgb, outAlpha ) );
|
|
358
362
|
// DDFA: the plane's aux (written above) is a committed surface — lock it (cosmetic; ray dies here).
|
|
359
363
|
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitOr( uint( RAY_FLAG.AUX_LOCKED ) ).bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
360
|
-
|
|
364
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
361
365
|
Return();
|
|
362
366
|
|
|
363
367
|
} );
|
|
@@ -469,6 +473,53 @@ export function buildShadeKernel( params ) {
|
|
|
469
473
|
currentRadiance.w
|
|
470
474
|
) );
|
|
471
475
|
|
|
476
|
+
// The sun disc; on a redirected ray, the partner of the sending vertex's sun NEE. A blurred
|
|
477
|
+
// backdrop gets a smooth falloff: a hard-edged cone reads as a white coin.
|
|
478
|
+
If( hasSun, () => {
|
|
479
|
+
|
|
480
|
+
const sunL = vec3( 0.0 ).toVar();
|
|
481
|
+
If( isBackdropView.and( backgroundBlurriness.greaterThan( 0.0 ) ), () => {
|
|
482
|
+
|
|
483
|
+
const blurAngle = backgroundBlurriness.mul( 1.3 ).toVar();
|
|
484
|
+
const angle = acos( clamp( dot( normalize( envDir ), sunDirection ), - 1.0, 1.0 ) );
|
|
485
|
+
If( angle.lessThan( blurAngle ), () => {
|
|
486
|
+
|
|
487
|
+
const falloff = float( 1.0 ).sub( angle.div( blurAngle ).pow( 2 ) ).pow( 2 );
|
|
488
|
+
// ∫ falloff dΩ = π θb² / 3 for a small cone.
|
|
489
|
+
sunL.assign( sunRadiance.mul( environmentIntensity ).mul( sunParams.y ).mul( falloff ).mul( 3 / Math.PI ).div( blurAngle.mul( blurAngle ) ) );
|
|
490
|
+
|
|
491
|
+
} );
|
|
492
|
+
|
|
493
|
+
} ).Else( () => {
|
|
494
|
+
|
|
495
|
+
sunL.assign( sunRadianceToward( normalize( envDir ), sunDirection, sunRadiance, sunParams ).mul( environmentIntensity ) );
|
|
496
|
+
|
|
497
|
+
} );
|
|
498
|
+
If( sunL.x.add( sunL.y ).add( sunL.z ).greaterThan( 0.0 ), () => {
|
|
499
|
+
|
|
500
|
+
const sunW = float( 1.0 ).toVar();
|
|
501
|
+
If( isBackdropView.not().and( flags.bitAnd( uint( RAY_FLAG.SUN_NEE ) ).notEqual( uint( 0 ) ) ), () => {
|
|
502
|
+
|
|
503
|
+
sunW.assign( powerHeuristic( { pdf1: readRayPdf( rayBufferRW, rayID ), pdf2: float( 1.0 ).div( sunParams.y ) } ) );
|
|
504
|
+
|
|
505
|
+
} );
|
|
506
|
+
const vertex = max( bounceIndex.sub( 1 ), int( 0 ) );
|
|
507
|
+
const sunScale = select( isBackdropView, backgroundIntensity,
|
|
508
|
+
sunW.mul( select( vertex.greaterThan( int( 0 ) ), globalIlluminationIntensity, float( 1.0 ) ) ) );
|
|
509
|
+
currentRadiance.assign( vec4(
|
|
510
|
+
currentRadiance.xyz.add(
|
|
511
|
+
regularizePathContribution(
|
|
512
|
+
throughput.mul( sunL ).mul( sunScale ),
|
|
513
|
+
select( isBackdropView, float( 0.0 ), float( vertex ) ), fireflyThreshold, int( accumFrame ),
|
|
514
|
+
),
|
|
515
|
+
),
|
|
516
|
+
currentRadiance.w
|
|
517
|
+
) );
|
|
518
|
+
|
|
519
|
+
} );
|
|
520
|
+
|
|
521
|
+
} );
|
|
522
|
+
|
|
472
523
|
} );
|
|
473
524
|
|
|
474
525
|
// Solid-color backdrop ('color' mode): a primary ray that doesn't show the env image and isn't
|
|
@@ -577,7 +628,7 @@ export function buildShadeKernel( params ) {
|
|
|
577
628
|
|
|
578
629
|
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
579
630
|
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
580
|
-
|
|
631
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
581
632
|
Return();
|
|
582
633
|
|
|
583
634
|
} );
|
|
@@ -594,7 +645,7 @@ export function buildShadeKernel( params ) {
|
|
|
594
645
|
// fires the next hit's env/emissive MIS, down-weighting SSS-then-env/emitter views.
|
|
595
646
|
writeRayThroughputPdf( rayBufferRW, rayID, throughput, readRayPdf( rayBufferRW, rayID ) );
|
|
596
647
|
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
597
|
-
|
|
648
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
598
649
|
Return();
|
|
599
650
|
|
|
600
651
|
} );
|
|
@@ -735,7 +786,7 @@ export function buildShadeKernel( params ) {
|
|
|
735
786
|
|
|
736
787
|
writeRayRadiance( rayBufferRW, rayID, currentRadiance );
|
|
737
788
|
writeRayDirFlags( rayBufferRW, rayID, direction, flags.bitAnd( uint( ~ RAY_FLAG.ACTIVE ) ) );
|
|
738
|
-
|
|
789
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
739
790
|
|
|
740
791
|
};
|
|
741
792
|
|
|
@@ -935,7 +986,7 @@ export function buildShadeKernel( params ) {
|
|
|
935
986
|
throughput.mulAssign( interaction.throughput );
|
|
936
987
|
|
|
937
988
|
// Off the side of the facet the new ray leaves on: reflection stays, transmission and alpha skip cross.
|
|
938
|
-
const Ng = unpackHitFacet( readHitFacet(
|
|
989
|
+
const Ng = unpackHitFacet( readHitFacet( hitBufferRW, rayID ) ).faceN;
|
|
939
990
|
const newOrigin = offsetRayOrigin( hitPoint, select( dot( Ng, interaction.direction ).lessThan( 0.0 ), Ng.negate(), Ng ) );
|
|
940
991
|
|
|
941
992
|
// SSS = free bounce (depth unchanged); transmission advances camera-bounce depth.
|
|
@@ -979,7 +1030,7 @@ export function buildShadeKernel( params ) {
|
|
|
979
1030
|
writeFeatureThroughput( rayBufferRW, rayID, featCarry );
|
|
980
1031
|
|
|
981
1032
|
} );
|
|
982
|
-
|
|
1033
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
983
1034
|
Return();
|
|
984
1035
|
|
|
985
1036
|
} );
|
|
@@ -1066,7 +1117,7 @@ export function buildShadeKernel( params ) {
|
|
|
1066
1117
|
const Ngeo = normalize( hitNormal );
|
|
1067
1118
|
const NgeoFF = select( dot( Ngeo, V ).lessThan( 0.0 ), Ngeo.negate(), Ngeo ).toVar();
|
|
1068
1119
|
// The facet on the viewer's side: every ray spawned from here is offset off it (HitFacet.js).
|
|
1069
|
-
const facet = unpackHitFacet( readHitFacet(
|
|
1120
|
+
const facet = unpackHitFacet( readHitFacet( hitBufferRW, rayID ) );
|
|
1070
1121
|
const facetN = facet.faceN.toVar();
|
|
1071
1122
|
const terminatorLift = Ngeo.mul( facet.liftScale );
|
|
1072
1123
|
const lightShadowOrigin = L => shadowTerminatorOrigin( {
|
|
@@ -1188,6 +1239,7 @@ export function buildShadeKernel( params ) {
|
|
|
1188
1239
|
enableEnvironmentLight,
|
|
1189
1240
|
tslBool( false ), // wantUnoccluded: false on real surfaces — dead-codes the unoccluded sum
|
|
1190
1241
|
terminatorLift, facetN, shadowTerminatorOffset,
|
|
1242
|
+
hasSun, sunDirection, sunRadiance, sunParams,
|
|
1191
1243
|
) ).shadowed.toVar();
|
|
1192
1244
|
|
|
1193
1245
|
const giScale = select( bounceIndex.greaterThan( 0 ), globalIlluminationIntensity, float( 1.0 ) );
|
|
@@ -1367,6 +1419,10 @@ export function buildShadeKernel( params ) {
|
|
|
1367
1419
|
|
|
1368
1420
|
const newOrigin = offsetRayOrigin( hitPoint, select( dot( facetN, bounceDir ).lessThan( 0.0 ), facetN.negate(), facetN ) );
|
|
1369
1421
|
|
|
1422
|
+
// Whether this vertex's sun NEE could have drawn bounceDir, so a sun hit at the miss knows its MIS partner.
|
|
1423
|
+
const sunNEE = brdfIsTransmission.not().and( dot( N, bounceDir ).greaterThan( 0.0 ) );
|
|
1424
|
+
flags.assign( flags.sub( flags.bitAnd( uint( RAY_FLAG.SUN_NEE ) ) ).bitOr( select( sunNEE, uint( RAY_FLAG.SUN_NEE ), uint( 0 ) ) ) );
|
|
1425
|
+
|
|
1370
1426
|
// Opaque scatter: the only bounce that advances camera depth.
|
|
1371
1427
|
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth.add( 1 ), sssSteps, transparentCount );
|
|
1372
1428
|
writeRayDirFlags( rayBufferRW, rayID, bounceDir, flags );
|
|
@@ -1379,7 +1435,7 @@ export function buildShadeKernel( params ) {
|
|
|
1379
1435
|
writeFeatureThroughput( rayBufferRW, rayID, featCarry );
|
|
1380
1436
|
|
|
1381
1437
|
} );
|
|
1382
|
-
|
|
1438
|
+
writeRngState( hitBufferRW, rayID, rngState );
|
|
1383
1439
|
|
|
1384
1440
|
} );
|
|
1385
1441
|
|
package/src/TSL/Sun.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Fn, float, vec3, sqrt, max, dot, cross, pow, cos, sin, abs, normalize, select, If } from 'three/tsl';
|
|
2
|
+
|
|
3
|
+
import { LIMB_DARKENING_EXPONENT } from '../Processor/AtmosphereModel.js';
|
|
4
|
+
|
|
5
|
+
const LIMB_EXPONENT = vec3( ...LIMB_DARKENING_EXPONENT );
|
|
6
|
+
// µ^α averages to 2 / (α + 2) over the disc, so this keeps the mean at `sunRadiance`.
|
|
7
|
+
const LIMB_NORM = vec3( ...LIMB_DARKENING_EXPONENT.map( a => ( a + 2 ) / 2 ) );
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Radiance the physical sky's sun sends along `dir`: limb darkened, and nothing below the sky's
|
|
11
|
+
* horizon. `sunParams` = ( cos half-angle, solid angle, 1 / sin² half-angle, horizon dip sin ).
|
|
12
|
+
*/
|
|
13
|
+
export const sunRadianceToward = /*@__PURE__*/ Fn( ( [ dir, sunDirection, sunRadiance, sunParams ] ) => {
|
|
14
|
+
|
|
15
|
+
const out = vec3( 0 ).toVar();
|
|
16
|
+
If( dot( dir, sunDirection ).greaterThanEqual( sunParams.x ).and( dir.y.greaterThanEqual( sunParams.w.negate() ) ), () => {
|
|
17
|
+
|
|
18
|
+
const c = cross( dir, sunDirection );
|
|
19
|
+
const mu = sqrt( max( float( 1 ).sub( dot( c, c ).mul( sunParams.z ) ), 1e-8 ) );
|
|
20
|
+
out.assign( sunRadiance.mul( pow( vec3( mu ), LIMB_EXPONENT ) ).mul( LIMB_NORM ) );
|
|
21
|
+
|
|
22
|
+
} );
|
|
23
|
+
return out;
|
|
24
|
+
|
|
25
|
+
} );
|
|
26
|
+
|
|
27
|
+
/** A direction uniform in solid angle over the sun disc. */
|
|
28
|
+
export const sampleSunDisc = /*@__PURE__*/ Fn( ( [ sunDirection, sunParams, xi ] ) => {
|
|
29
|
+
|
|
30
|
+
// 1 − cosθ straight from the solid angle: 1 − cos(half-angle) cancels to nothing in f32.
|
|
31
|
+
const oneMinusCos = xi.x.mul( sunParams.y.mul( 1 / ( 2 * Math.PI ) ) );
|
|
32
|
+
const cosT = float( 1 ).sub( oneMinusCos );
|
|
33
|
+
const sinT = sqrt( max( oneMinusCos.mul( float( 2 ).sub( oneMinusCos ) ), 0 ) );
|
|
34
|
+
const phi = xi.y.mul( 2 * Math.PI );
|
|
35
|
+
const w = sunDirection;
|
|
36
|
+
const u = normalize( cross( select( abs( w.x ).greaterThan( 0.9 ), vec3( 0, 1, 0 ), vec3( 1, 0, 0 ) ), w ) );
|
|
37
|
+
const v = cross( w, u );
|
|
38
|
+
return normalize( w.mul( cosT ).add( u.mul( cos( phi ) ).add( v.mul( sin( phi ) ) ).mul( sinT ) ) );
|
|
39
|
+
|
|
40
|
+
} );
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
MaterialSamples,
|
|
7
7
|
ExtMapResult,
|
|
8
8
|
} from './Struct.js';
|
|
9
|
-
import {
|
|
9
|
+
import { instanceRows, instanceDirToWorld, triangleRow } from './Common.js';
|
|
10
10
|
import { TEXTURE_CONSTANTS } from '../EngineDefaults.js';
|
|
11
11
|
|
|
12
12
|
// ================================================================================
|
|
@@ -414,13 +414,12 @@ const uvTransformJacobian = /*@__PURE__*/ wgslFn( `
|
|
|
414
414
|
*/
|
|
415
415
|
export const triangleUVTangent = Fn( ( [ triangleBuffer, triIndex, geometryNormal, transform, bvhBuffer, instanceLeaf ] ) => {
|
|
416
416
|
|
|
417
|
-
const
|
|
418
|
-
const
|
|
419
|
-
const
|
|
420
|
-
const e2 = uintBitsToFloat( getDatafromStorageBuffer( triangleBuffer, triIndex, int( 2 ), S ).xyz ).sub( pA );
|
|
417
|
+
const pA = uintBitsToFloat( triangleRow( triangleBuffer, triIndex, 0 ).xyz );
|
|
418
|
+
const e1 = uintBitsToFloat( triangleRow( triangleBuffer, triIndex, 1 ).xyz ).sub( pA );
|
|
419
|
+
const e2 = uintBitsToFloat( triangleRow( triangleBuffer, triIndex, 2 ).xyz ).sub( pA );
|
|
421
420
|
|
|
422
|
-
const uvAB = uintBitsToFloat(
|
|
423
|
-
const uvC = uintBitsToFloat(
|
|
421
|
+
const uvAB = uintBitsToFloat( triangleRow( triangleBuffer, triIndex, 3 ) );
|
|
422
|
+
const uvC = uintBitsToFloat( triangleRow( triangleBuffer, triIndex, 4 ).xy );
|
|
424
423
|
const d1 = uvAB.zw.sub( uvAB.xy );
|
|
425
424
|
const d2 = uvC.sub( uvAB.xy );
|
|
426
425
|
|
package/src/index.js
CHANGED
|
@@ -26,6 +26,22 @@ export { SETTING_SOURCE } from './RenderSettings.js';
|
|
|
26
26
|
// Asset URL / cache namespace overrides (call before constructing PathTracerApp)
|
|
27
27
|
export { configureAssets, getAssetConfig } from './AssetConfig.js';
|
|
28
28
|
|
|
29
|
+
// On-disk storage (origin private file system): caches, and areas a host defines for its own data
|
|
30
|
+
export {
|
|
31
|
+
openStorage, StorageManager, STORAGE_KIND, ENGINE_AREAS, fileIdentity, identityKey, sameIdentity,
|
|
32
|
+
DownloadCache, DOWNLOAD_POLICY, fetchFile, nameFromUrl, cachedObjectURL, acquireLock, heldLockNames,
|
|
33
|
+
} from './Storage/index.js';
|
|
34
|
+
|
|
35
|
+
// Archives read in place: one entry at a time, never the whole file in memory
|
|
36
|
+
export { openZip, readZipDirectory } from './Processor/ZipReader.js';
|
|
37
|
+
|
|
38
|
+
// Engine package version, as built
|
|
39
|
+
export { VERSION } from './version.js';
|
|
40
|
+
|
|
41
|
+
// A loaded scene's edits as plain data (app.exportSceneState / importSceneState)
|
|
42
|
+
export { SCENE_STATE_VERSION } from './SceneState/SceneState.js';
|
|
43
|
+
export { toPortable, fromPortable } from './SceneState/portable.js';
|
|
44
|
+
|
|
29
45
|
// glTF alphaMode derivation — the one definition, shared with hosts that edit materials
|
|
30
46
|
export { deriveAlphaMode, MATERIAL_VALUE_SOURCE } from './Processor/GeometryExtractor.js';
|
|
31
47
|
|
|
@@ -47,6 +63,7 @@ export {
|
|
|
47
63
|
CAMERA_PRESETS,
|
|
48
64
|
CAMERA_RANGES,
|
|
49
65
|
SKY_PRESETS,
|
|
66
|
+
DEFAULT_SUN_PATH,
|
|
50
67
|
AUTO_FOCUS_MODES,
|
|
51
68
|
AF_DEFAULTS,
|
|
52
69
|
TRIANGLE_DATA_LAYOUT,
|
|
@@ -61,6 +78,7 @@ export {
|
|
|
61
78
|
RENDER_PROFILES,
|
|
62
79
|
getRenderProfile,
|
|
63
80
|
} from './EngineDefaults.js';
|
|
81
|
+
export { sunPosition, timeForSunElevation, dayOfYearForMonth } from './Processor/SunPosition.js';
|
|
64
82
|
|
|
65
83
|
// Settings & managers (for advanced consumers)
|
|
66
84
|
export { RenderSettings } from './RenderSettings.js';
|
|
@@ -96,6 +114,10 @@ export { TransformManager } from './managers/TransformManager.js';
|
|
|
96
114
|
// Video rendering
|
|
97
115
|
export { VideoRenderManager } from './managers/VideoRenderManager.js';
|
|
98
116
|
|
|
117
|
+
// Authored animation: keyframed tracks on one timeline (engine.timeline)
|
|
118
|
+
export { TimelineManager } from './managers/timeline/TimelineManager.js';
|
|
119
|
+
export { CameraTrack } from './managers/timeline/CameraTrack.js';
|
|
120
|
+
|
|
99
121
|
// Interaction
|
|
100
122
|
export { InteractionManager } from './managers/InteractionManager.js';
|
|
101
123
|
|