rayzee 8.8.1 → 9.0.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 +71 -12
- package/dist/{NeuralSuperRes-Dc6jRYke.js → NeuralSuperRes-CQLCLpcC.js} +2 -0
- package/dist/rayzee.es.js +3572 -3111
- package/dist/rayzee.umd.js +110 -99
- package/package.json +1 -1
- package/src/EngineDefaults.js +21 -19
- package/src/EngineEvents.js +4 -0
- package/src/Passes/OIDNTemporalHistory.js +25 -7
- package/src/PathTracerApp.js +23 -6
- package/src/Processor/AssetLoader.js +9 -0
- package/src/Processor/PBRT/PBRTSceneBuilder.js +18 -6
- package/src/RenderSettings.js +11 -8
- package/src/Stages/MotionVector.js +8 -42
- package/src/Stages/NRD.js +30 -21
- package/src/Stages/NormalDepth.js +5 -17
- package/src/Stages/PathTracer.js +6 -2
- package/src/Stages/PathTracerStage.js +2 -0
- package/src/TSL/CameraRay.js +99 -14
- package/src/TSL/DebugKernel.js +2 -2
- package/src/TSL/GenerateKernel.js +2 -2
- package/src/index.js +4 -0
- package/src/managers/CameraManager.js +244 -56
- package/src/managers/DenoisingManager.js +4 -3
- package/src/managers/InteractionManager.js +30 -2
- package/src/managers/UniformManager.js +6 -4
- package/src/managers/VideoRenderManager.js +35 -16
- 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 +213 -0
- package/src/managers/timeline/TimelineManager.js +132 -0
package/src/Stages/NRD.js
CHANGED
|
@@ -6,7 +6,7 @@ import { DataTexture, HalfFloatType, FloatType, RGBAFormat, LinearFilter, Matrix
|
|
|
6
6
|
import { RenderStage, StageExecutionMode } from '../Pipeline/RenderStage.js';
|
|
7
7
|
import { createStorageTexture } from '../Processor/StorageTexturePool.js';
|
|
8
8
|
import { sanitizeRGB, sanitize1, FP16_MAX } from '../TSL/Common.js';
|
|
9
|
-
import {
|
|
9
|
+
import { cameraRayPoint, cameraRayUniforms, isOrthographic } from '../TSL/CameraRay.js';
|
|
10
10
|
import {
|
|
11
11
|
ALBEDO_EPS, GBUFFER_MISS_THRESHOLD as MISS_THRESHOLD, NRD_DEFAULTS,
|
|
12
12
|
NRD_HIT_DIST_A, NRD_HIT_DIST_B,
|
|
@@ -168,10 +168,10 @@ export class NRD extends RenderStage {
|
|
|
168
168
|
this.prevCamView = uniform( new Matrix4(), 'mat4' );
|
|
169
169
|
this.camPos = uniform( new Vector3(), 'vec3' );
|
|
170
170
|
this.prevCamPos = uniform( new Vector3(), 'vec3' );
|
|
171
|
-
|
|
172
|
-
this.
|
|
173
|
-
this.
|
|
174
|
-
this.
|
|
171
|
+
// Surface to camera while orthographic, where it is the same for every pixel.
|
|
172
|
+
this.viewVector = uniform( new Vector3(), 'vec3' );
|
|
173
|
+
this.prevViewVector = uniform( new Vector3(), 'vec3' );
|
|
174
|
+
this.cameraRay = cameraRayUniforms();
|
|
175
175
|
|
|
176
176
|
// Declared here, valued by _syncUniforms below — which is the only place a setting becomes a
|
|
177
177
|
// uniform, so there is no second copy of the defaults to keep in step.
|
|
@@ -322,11 +322,20 @@ export class NRD extends RenderStage {
|
|
|
322
322
|
// Same ray the depth was measured along — NormalDepth generates it with this helper too.
|
|
323
323
|
_worldPosAt( uv, dist, cwm, cpi ) {
|
|
324
324
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
325
|
+
return cameraRayPoint( uv, dist, cwm, cpi, this.cameraRay );
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// NRD's gOrthoMode: a constant view vector, and a pixel's footprint that no longer grows with depth.
|
|
330
|
+
_viewVector( X, camPos, orthoV ) {
|
|
331
|
+
|
|
332
|
+
return select( isOrthographic( this.cameraRay.cameraProjection ), orthoV, normalize( camPos.sub( X ) ) );
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
_frustumSize( viewZ ) {
|
|
337
|
+
|
|
338
|
+
return this.minRectDimMulUnproject.mul( select( isOrthographic( this.cameraRay.cameraProjection ), float( 1.0 ), viewZ ) );
|
|
330
339
|
|
|
331
340
|
}
|
|
332
341
|
|
|
@@ -547,9 +556,9 @@ export class NRD extends RenderStage {
|
|
|
547
556
|
|
|
548
557
|
If( maxRadiusU.greaterThan( 0.0 ), () => {
|
|
549
558
|
|
|
550
|
-
const V =
|
|
559
|
+
const V = this._viewVector( X, camPos, this.viewVector );
|
|
551
560
|
const NoV = dot( N, V ).abs().toVar();
|
|
552
|
-
const frustumSize = this.
|
|
561
|
+
const frustumSize = this._frustumSize( viewZ ).toVar();
|
|
553
562
|
|
|
554
563
|
const k = inputFrames.add( 1.0 );
|
|
555
564
|
const accumSpeedEff = isPre
|
|
@@ -701,9 +710,9 @@ export class NRD extends RenderStage {
|
|
|
701
710
|
const pixelUv = this._pixelUv( gx, gy );
|
|
702
711
|
const X = this._worldPosAt( pixelUv, dist, cwm, cpi ).toVar();
|
|
703
712
|
const viewZ = camView.mul( vec4( X, 1.0 ) ).z.abs().toVar();
|
|
704
|
-
const V =
|
|
713
|
+
const V = this._viewVector( X, camPos, this.viewVector );
|
|
705
714
|
const NoV = dot( N, V ).abs().toVar();
|
|
706
|
-
const frustumSize = this.
|
|
715
|
+
const frustumSize = this._frustumSize( viewZ ).toVar();
|
|
707
716
|
|
|
708
717
|
// Unnormalized, as NRD requires — its length carries the normal variance. A miss neighbour's
|
|
709
718
|
// shadingNormal is a literal (0,0,0), which decodes to a fixed fake direction, so substitute
|
|
@@ -753,7 +762,7 @@ export class NRD extends RenderStage {
|
|
|
753
762
|
|
|
754
763
|
const accumSpeed = this._applyCustomWeights( prevAccum, occW, float( 0.0 ) ).toVar();
|
|
755
764
|
|
|
756
|
-
const Vprev =
|
|
765
|
+
const Vprev = this._viewVector( X, prevCamPos, this.prevViewVector );
|
|
757
766
|
const NoVprev = dot( N, Vprev ).abs();
|
|
758
767
|
const sizeQuality = NoVprev.add( 1e-3 ).div( NoV.add( 1e-3 ) ).toVar();
|
|
759
768
|
sizeQuality.assign( mix( float( 0.1 ), float( 1.0 ), saturate( sizeQuality.mul( sizeQuality ) ) ) );
|
|
@@ -853,7 +862,7 @@ export class NRD extends RenderStage {
|
|
|
853
862
|
const pixelUv = this._pixelUv( gx, gy );
|
|
854
863
|
const X = this._worldPosAt( pixelUv, dist, cwm, cpi ).toVar();
|
|
855
864
|
const viewZ = camView.mul( vec4( X, 1.0 ) ).z.abs();
|
|
856
|
-
const frustumSize = this.
|
|
865
|
+
const frustumSize = this._frustumSize( viewZ ).toVar();
|
|
857
866
|
|
|
858
867
|
const diff = textureLoad( inTex, coord ).toVar();
|
|
859
868
|
const nonLinear = float( 1.0 ).div( frameNumEff.add( 1.0 ) ).toVar();
|
|
@@ -1200,6 +1209,7 @@ export class NRD extends RenderStage {
|
|
|
1200
1209
|
|
|
1201
1210
|
this.prevCamView.value.copy( this.camView.value );
|
|
1202
1211
|
this.prevCamPos.value.copy( this.camPos.value );
|
|
1212
|
+
this.prevViewVector.value.copy( this.viewVector.value );
|
|
1203
1213
|
|
|
1204
1214
|
}
|
|
1205
1215
|
|
|
@@ -1207,20 +1217,19 @@ export class NRD extends RenderStage {
|
|
|
1207
1217
|
this.camProjInv.value.copy( projInv );
|
|
1208
1218
|
this.camView.value.copy( view );
|
|
1209
1219
|
this.camPos.value.setFromMatrixPosition( world );
|
|
1210
|
-
this.
|
|
1211
|
-
this.
|
|
1212
|
-
this.panoLatRange.value.copy( pt.uniforms.get( 'panoLatRange' ).value );
|
|
1213
|
-
this.panoLevelHorizon.value = pt.uniforms.get( 'panoLevelHorizon' ).value;
|
|
1220
|
+
this.viewVector.value.setFromMatrixColumn( world, 2 ).normalize();
|
|
1221
|
+
this.cameraRay.sync( pt.uniforms );
|
|
1214
1222
|
|
|
1215
1223
|
if ( ! this._camInitialized ) {
|
|
1216
1224
|
|
|
1217
1225
|
this.prevCamView.value.copy( view );
|
|
1218
1226
|
this.prevCamPos.value.copy( this.camPos.value );
|
|
1227
|
+
this.prevViewVector.value.copy( this.viewVector.value );
|
|
1219
1228
|
this._camInitialized = true;
|
|
1220
1229
|
|
|
1221
1230
|
}
|
|
1222
1231
|
|
|
1223
|
-
// NRD gUnproject; frustum size follows the shorter edge.
|
|
1232
|
+
// NRD gUnproject; frustum size follows the shorter edge. Orthographic, it is world units per pixel.
|
|
1224
1233
|
const projY = proj.elements[ 5 ] || 1;
|
|
1225
1234
|
const unproject = 1 / ( 0.5 * this.resH.value * projY );
|
|
1226
1235
|
this.minRectDimMulUnproject.value = Math.min( this.resW.value, this.resH.value ) * unproject;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fn, vec2,
|
|
1
|
+
import { Fn, vec2, vec4, float, int, uint, uvec2, uvec4, uniform, min, storage, If,
|
|
2
2
|
textureStore, workgroupId, localId } from 'three/tsl';
|
|
3
3
|
import { RenderTarget, StorageTexture } from 'three/webgpu';
|
|
4
4
|
import { HalfFloatType, RGBAFormat, RedIntegerFormat, UnsignedIntType, NearestFilter, Matrix4, Box2, Vector2 } from 'three';
|
|
@@ -6,7 +6,7 @@ import { RenderStage, StageExecutionMode } from '../Pipeline/RenderStage.js';
|
|
|
6
6
|
import { MAX_STORAGE_TEXTURE_SIZE } from '../EngineDefaults.js';
|
|
7
7
|
import { Ray, HitInfo, RayTracingMaterial, UVCache } from '../TSL/Struct.js';
|
|
8
8
|
import { traverseBVH } from '../TSL/BVHTraversal.js';
|
|
9
|
-
import {
|
|
9
|
+
import { cameraRayOf, cameraRayUniforms } from '../TSL/CameraRay.js';
|
|
10
10
|
import { getMaterial } from '../TSL/Common.js';
|
|
11
11
|
import { computeUVCache, processNormal, processBump, processMetalnessRoughness, triangleUVTangent, buildBucketTextureNodes, refreshBucketTextureNodes, setMaterialBucketTextures } from '../TSL/TextureSampling.js';
|
|
12
12
|
|
|
@@ -53,10 +53,7 @@ export class NormalDepth extends RenderStage {
|
|
|
53
53
|
this.cameraProjectionMatrixInverse = uniform( new Matrix4(), 'mat4' );
|
|
54
54
|
// Mirrored from the path tracer each frame — these rays must use the same camera model
|
|
55
55
|
// as the colour buffer or the denoiser's normal/depth edge-stops fight the image.
|
|
56
|
-
this.
|
|
57
|
-
this.panoLonRange = uniform( new Vector2(), 'vec2' );
|
|
58
|
-
this.panoLatRange = uniform( new Vector2(), 'vec2' );
|
|
59
|
-
this.panoLevelHorizon = uniform( 1, 'int' );
|
|
56
|
+
this.cameraRay = cameraRayUniforms();
|
|
60
57
|
this.resolutionWidth = uniform( options.width || 1 );
|
|
61
58
|
this.resolutionHeight = uniform( options.height || 1 );
|
|
62
59
|
|
|
@@ -236,13 +233,7 @@ export class NormalDepth extends RenderStage {
|
|
|
236
233
|
// No jitter — deterministic per-pixel ray so the temporal gate
|
|
237
234
|
// sees stable per-pixel normals across frames.
|
|
238
235
|
const uv = vec2( float( gx ).add( 0.5 ).div( resW ), float( gy ).add( 0.5 ).div( resH ) );
|
|
239
|
-
const
|
|
240
|
-
uv, camWorldMat, camProjInvMat,
|
|
241
|
-
this.cameraProjection, this.panoLonRange, this.panoLatRange, this.panoLevelHorizon
|
|
242
|
-
);
|
|
243
|
-
const rayOrigin = vec3( camWorldMat[ 3 ] );
|
|
244
|
-
|
|
245
|
-
const ray = Ray( { origin: rayOrigin, direction: rayDirWorld } );
|
|
236
|
+
const ray = Ray( cameraRayOf( uv, camWorldMat, camProjInvMat, this.cameraRay ) );
|
|
246
237
|
const hit = HitInfo.wrap( traverseBVH( ray, bvhStorage, triStorage ) );
|
|
247
238
|
|
|
248
239
|
const encodedNormal = hit.normal.mul( 0.5 ).add( 0.5 );
|
|
@@ -339,10 +330,7 @@ export class NormalDepth extends RenderStage {
|
|
|
339
330
|
|
|
340
331
|
this.cameraWorldMatrix.value.copy( pt.uniforms.get( 'cameraWorldMatrix' ).value );
|
|
341
332
|
this.cameraProjectionMatrixInverse.value.copy( pt.uniforms.get( 'cameraProjectionMatrixInverse' ).value );
|
|
342
|
-
this.
|
|
343
|
-
this.panoLonRange.value.copy( pt.uniforms.get( 'panoLonRange' ).value );
|
|
344
|
-
this.panoLatRange.value.copy( pt.uniforms.get( 'panoLatRange' ).value );
|
|
345
|
-
this.panoLevelHorizon.value = pt.uniforms.get( 'panoLevelHorizon' ).value;
|
|
333
|
+
this.cameraRay.sync( pt.uniforms );
|
|
346
334
|
|
|
347
335
|
}
|
|
348
336
|
|
package/src/Stages/PathTracer.js
CHANGED
|
@@ -1163,9 +1163,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1163
1163
|
focalLength: this.focalLength,
|
|
1164
1164
|
aperture: this.aperture,
|
|
1165
1165
|
focusDistance: this.focusDistance,
|
|
1166
|
-
|
|
1166
|
+
unitsPerMetre: this.unitsPerMetre,
|
|
1167
1167
|
apertureScale: this.apertureScale,
|
|
1168
1168
|
anamorphicRatio: this.anamorphicRatio,
|
|
1169
|
+
dofMode: this.dofMode,
|
|
1170
|
+
dofBlur: this.dofBlur,
|
|
1169
1171
|
renderWidth: this._wfRenderWidth,
|
|
1170
1172
|
renderHeight: this._wfRenderHeight,
|
|
1171
1173
|
chunkRowBase: this._wfChunkRowBase,
|
|
@@ -1643,9 +1645,11 @@ export class PathTracer extends PathTracerStage {
|
|
|
1643
1645
|
focalLength: this.focalLength,
|
|
1644
1646
|
aperture: this.aperture,
|
|
1645
1647
|
focusDistance: this.focusDistance,
|
|
1646
|
-
|
|
1648
|
+
unitsPerMetre: this.unitsPerMetre,
|
|
1647
1649
|
apertureScale: this.apertureScale,
|
|
1648
1650
|
anamorphicRatio: this.anamorphicRatio,
|
|
1651
|
+
dofMode: this.dofMode,
|
|
1652
|
+
dofBlur: this.dofBlur,
|
|
1649
1653
|
bvhBuffer: freshBvh,
|
|
1650
1654
|
triangleBuffer: freshTri,
|
|
1651
1655
|
materialBuffer: freshMat,
|
|
@@ -1013,6 +1013,8 @@ export class PathTracerStage extends RenderStage {
|
|
|
1013
1013
|
|
|
1014
1014
|
if ( ! attr ) return;
|
|
1015
1015
|
attr.array.set( data );
|
|
1016
|
+
// A pending update range would cut this full upload down to that range.
|
|
1017
|
+
attr.clearUpdateRanges();
|
|
1016
1018
|
attr.needsUpdate = true;
|
|
1017
1019
|
|
|
1018
1020
|
}
|
package/src/TSL/CameraRay.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CameraRay.js — primary camera ray generation.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* cameraProjectionMatrixInverse),
|
|
6
|
-
* kernel, so switching modes writes a uniform and resets
|
|
4
|
+
* Three projections behind one `cameraProjection` uniform (CAMERA_PROJECTION_IDS): pinhole (NDC through
|
|
5
|
+
* cameraProjectionMatrixInverse), equirectangular 360 panorama, and orthographic (parallel rays from the
|
|
6
|
+
* camera's image plane). All live in the same kernel, so switching modes writes a uniform and resets
|
|
7
|
+
* accumulation — it never recompiles WGSL.
|
|
7
8
|
*
|
|
8
9
|
* Equirect mapping, for uv ∈ [0,1] with v = 0 at the top row:
|
|
9
10
|
* lon = mix( lonMin, lonMax, u ), lat = mix( latMax, latMin, v )
|
|
@@ -12,15 +13,81 @@
|
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import {
|
|
15
|
-
Fn, vec3, vec4, float, int,
|
|
16
|
-
If, normalize, mat3, mix, sin, cos, cross, dot,
|
|
16
|
+
Fn, vec3, vec4, float, int, uniform,
|
|
17
|
+
If, normalize, mat3, mix, sin, cos, cross, dot, select,
|
|
17
18
|
} from 'three/tsl';
|
|
19
|
+
import { Vector2 } from 'three';
|
|
18
20
|
|
|
19
21
|
import { Ray } from './Struct.js';
|
|
20
22
|
import { constructTBN } from './Common.js';
|
|
21
23
|
import { RandomPointInCircle } from './Random.js';
|
|
24
|
+
import { CAMERA_PROJECTION_IDS } from '../EngineDefaults.js';
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
const PANORAMA = int( CAMERA_PROJECTION_IDS.equirectangular );
|
|
27
|
+
const ORTHOGRAPHIC = int( CAMERA_PROJECTION_IDS.orthographic );
|
|
28
|
+
|
|
29
|
+
export const isOrthographic = cameraProjection => cameraProjection.equal( ORTHOGRAPHIC );
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The projection uniforms a stage re-tracing the path tracer's primary rays needs. `sync` copies the path
|
|
33
|
+
* tracer's, once a frame.
|
|
34
|
+
*/
|
|
35
|
+
export function cameraRayUniforms() {
|
|
36
|
+
|
|
37
|
+
const u = {
|
|
38
|
+
cameraProjection: uniform( 0, 'int' ),
|
|
39
|
+
panoLonRange: uniform( new Vector2(), 'vec2' ),
|
|
40
|
+
panoLatRange: uniform( new Vector2(), 'vec2' ),
|
|
41
|
+
panoLevelHorizon: uniform( 1, 'int' ),
|
|
42
|
+
/** @param {import('../managers/UniformManager.js').UniformManager} source */
|
|
43
|
+
sync( source ) {
|
|
44
|
+
|
|
45
|
+
u.cameraProjection.value = source.get( 'cameraProjection' ).value;
|
|
46
|
+
u.panoLonRange.value.copy( source.get( 'panoLonRange' ).value );
|
|
47
|
+
u.panoLatRange.value.copy( source.get( 'panoLatRange' ).value );
|
|
48
|
+
u.panoLevelHorizon.value = source.get( 'panoLevelHorizon' ).value;
|
|
49
|
+
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
return u;
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Pixel uv's primary ray, for a stage holding {@link cameraRayUniforms}. */
|
|
57
|
+
export const cameraRayOf = ( uv01, cameraWorldMatrix, cameraProjectionMatrixInverse, u ) => ( {
|
|
58
|
+
origin: cameraRayOrigin( uv01, cameraWorldMatrix, cameraProjectionMatrixInverse, u.cameraProjection ),
|
|
59
|
+
direction: cameraRayDirection(
|
|
60
|
+
uv01, cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
61
|
+
u.cameraProjection, u.panoLonRange, u.panoLatRange, u.panoLevelHorizon
|
|
62
|
+
),
|
|
63
|
+
} );
|
|
64
|
+
|
|
65
|
+
/** The point `distance` along pixel uv's primary ray — where a depth the path tracer measured lies. */
|
|
66
|
+
export const cameraRayPoint = ( uv01, distance, cameraWorldMatrix, cameraProjectionMatrixInverse, u ) => {
|
|
67
|
+
|
|
68
|
+
const { origin, direction } = cameraRayOf( uv01, cameraWorldMatrix, cameraProjectionMatrixInverse, u );
|
|
69
|
+
return origin.add( direction.mul( distance ) );
|
|
70
|
+
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/** World-space primary ray origin for pixel uv: the camera, or its image plane when orthographic. */
|
|
74
|
+
export const cameraRayOrigin = Fn( ( [ uv01, cameraWorldMatrix, cameraProjectionMatrixInverse, cameraProjection ] ) => {
|
|
75
|
+
|
|
76
|
+
const origin = vec3( cameraWorldMatrix[ 3 ] ).toVar();
|
|
77
|
+
|
|
78
|
+
If( isOrthographic( cameraProjection ), () => {
|
|
79
|
+
|
|
80
|
+
// An orthographic inverse maps x and y alone, whatever the depth.
|
|
81
|
+
const onPlane = cameraProjectionMatrixInverse.mul( vec4( uv01.x.mul( 2.0 ).sub( 1.0 ), float( 1.0 ).sub( uv01.y.mul( 2.0 ) ), 0.0, 1.0 ) );
|
|
82
|
+
origin.assign( cameraWorldMatrix.mul( vec4( onPlane.xy, 0.0, 1.0 ) ).xyz );
|
|
83
|
+
|
|
84
|
+
} );
|
|
85
|
+
|
|
86
|
+
return origin;
|
|
87
|
+
|
|
88
|
+
} );
|
|
89
|
+
|
|
90
|
+
/** World-space primary ray direction for pixel uv, from {@link cameraRayOrigin}. */
|
|
24
91
|
export const cameraRayDirection = Fn( ( [
|
|
25
92
|
uv01, cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
26
93
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon
|
|
@@ -28,7 +95,7 @@ export const cameraRayDirection = Fn( ( [
|
|
|
28
95
|
|
|
29
96
|
const direction = vec3( 0.0 ).toVar();
|
|
30
97
|
|
|
31
|
-
If( cameraProjection.equal(
|
|
98
|
+
If( cameraProjection.equal( PANORAMA ), () => {
|
|
32
99
|
|
|
33
100
|
const lon = mix( panoLonRange.x, panoLonRange.y, uv01.x ).toVar();
|
|
34
101
|
const lat = mix( panoLatRange.y, panoLatRange.x, uv01.y ).toVar();
|
|
@@ -68,6 +135,10 @@ export const cameraRayDirection = Fn( ( [
|
|
|
68
135
|
.sub( back.mul( cos( lon ).mul( cosLat ) ) )
|
|
69
136
|
) );
|
|
70
137
|
|
|
138
|
+
} ).ElseIf( isOrthographic( cameraProjection ), () => {
|
|
139
|
+
|
|
140
|
+
direction.assign( normalize( vec3( cameraWorldMatrix[ 2 ] ) ).negate() );
|
|
141
|
+
|
|
71
142
|
} ).Else( () => {
|
|
72
143
|
|
|
73
144
|
const ndcPos = vec3( uv01.x.mul( 2.0 ).sub( 1.0 ), float( 1.0 ).sub( uv01.y.mul( 2.0 ) ), 1.0 );
|
|
@@ -89,10 +160,10 @@ export const generateRayFromCamera = Fn( ( [
|
|
|
89
160
|
uv01, rngState,
|
|
90
161
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
91
162
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
92
|
-
enableDOF, focalLength, aperture, focusDistance,
|
|
163
|
+
enableDOF, focalLength, aperture, focusDistance, unitsPerMetre, apertureScale, anamorphicRatio, dofMode, dofBlur
|
|
93
164
|
] ) => {
|
|
94
165
|
|
|
95
|
-
const rayOriginWorld =
|
|
166
|
+
const rayOriginWorld = cameraRayOrigin( uv01, cameraWorldMatrix, cameraProjectionMatrixInverse, cameraProjection ).toVar();
|
|
96
167
|
// .toVar() so the two reads below don't inline the whole projection graph twice.
|
|
97
168
|
const rayDirectionWorld = cameraRayDirection(
|
|
98
169
|
uv01, cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
@@ -102,10 +173,20 @@ export const generateRayFromCamera = Fn( ( [
|
|
|
102
173
|
const resultOrigin = rayOriginWorld.toVar();
|
|
103
174
|
const resultDirection = rayDirectionWorld.toVar();
|
|
104
175
|
|
|
105
|
-
|
|
176
|
+
const lookMode = dofMode.equal( int( 1 ) );
|
|
177
|
+
const lensOpen = lookMode.and( dofBlur.greaterThan( 0.0 ) ).or( lookMode.not().and( focalLength.greaterThan( 0.0 ) ).and( aperture.lessThan( 64.0 ) ) );
|
|
106
178
|
|
|
107
|
-
|
|
108
|
-
|
|
179
|
+
If( enableDOF.and( lensOpen ).and( focusDistance.greaterThan( 0.001 ) ), () => {
|
|
180
|
+
|
|
181
|
+
// Orthographic 1: the blur then does not change with where the camera stands.
|
|
182
|
+
const halfViewHeight = select( cameraProjection.equal( PANORAMA ), panoLatRange.y.sub( panoLatRange.x ).mul( 0.5 ),
|
|
183
|
+
select( isOrthographic( cameraProjection ), float( 1.0 ), cameraProjectionMatrixInverse[ 1 ].y ) );
|
|
184
|
+
const apertureRadius = select( lookMode,
|
|
185
|
+
// A far background blurs by dofBlur of the image height, whatever the scene's scale.
|
|
186
|
+
dofBlur.mul( focusDistance ).mul( halfViewHeight ),
|
|
187
|
+
// f/N is the aperture's diameter, not its radius.
|
|
188
|
+
focalLength.div( aperture.mul( 2.0 ) ).mul( 0.001 ).mul( unitsPerMetre ).mul( apertureScale )
|
|
189
|
+
);
|
|
109
190
|
|
|
110
191
|
const randomPoint = RandomPointInCircle( rngState );
|
|
111
192
|
// Anamorphic squeeze — stretch horizontally for oval bokeh
|
|
@@ -113,8 +194,9 @@ export const generateRayFromCamera = Fn( ( [
|
|
|
113
194
|
const lensY = randomPoint.y;
|
|
114
195
|
|
|
115
196
|
const lensOffset = vec3( 0.0 ).toVar();
|
|
197
|
+
const focusAlongRay = focusDistance.toVar();
|
|
116
198
|
|
|
117
|
-
If( cameraProjection.equal(
|
|
199
|
+
If( cameraProjection.equal( PANORAMA ), () => {
|
|
118
200
|
|
|
119
201
|
// Every pixel points a different way, so the lens plane is built around the ray. The
|
|
120
202
|
// camera's right/up would skew bokeh into a slit away from the image centre.
|
|
@@ -126,10 +208,13 @@ export const generateRayFromCamera = Fn( ( [
|
|
|
126
208
|
const camUp = normalize( vec3( cameraWorldMatrix[ 1 ] ) );
|
|
127
209
|
lensOffset.assign( camRight.mul( lensX ).add( camUp.mul( lensY ) ) );
|
|
128
210
|
|
|
211
|
+
// A flat focal plane: focusDistance is depth along the view axis, not distance along the ray.
|
|
212
|
+
focusAlongRay.assign( focusDistance.div( dot( rayDirectionWorld, normalize( vec3( cameraWorldMatrix[ 2 ] ) ) ).negate() ) );
|
|
213
|
+
|
|
129
214
|
} );
|
|
130
215
|
|
|
131
216
|
resultOrigin.assign( rayOriginWorld.add( lensOffset.mul( apertureRadius ) ) );
|
|
132
|
-
resultDirection.assign( normalize( rayOriginWorld.add( rayDirectionWorld.mul(
|
|
217
|
+
resultDirection.assign( normalize( rayOriginWorld.add( rayDirectionWorld.mul( focusAlongRay ) ).sub( resultOrigin ) ) );
|
|
133
218
|
|
|
134
219
|
} );
|
|
135
220
|
|
package/src/TSL/DebugKernel.js
CHANGED
|
@@ -27,7 +27,7 @@ export function buildDebugKernel( params ) {
|
|
|
27
27
|
resolution, renderWidth, renderHeight,
|
|
28
28
|
cameraWorldMatrix, cameraProjectionMatrixInverse, cameraProjectionMatrix, cameraViewMatrix,
|
|
29
29
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
30
|
-
enableDOF, focalLength, aperture, focusDistance,
|
|
30
|
+
enableDOF, focalLength, aperture, focusDistance, unitsPerMetre, apertureScale, anamorphicRatio, dofMode, dofBlur,
|
|
31
31
|
bvhBuffer, triangleBuffer, materialBuffer,
|
|
32
32
|
envTexture, environmentMatrix, environmentIntensity, enableEnvironmentLight,
|
|
33
33
|
visMode, debugVisScale,
|
|
@@ -50,7 +50,7 @@ export function buildDebugKernel( params ) {
|
|
|
50
50
|
pixelCoord.div( resolution ), seed,
|
|
51
51
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
52
52
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
53
|
-
enableDOF, focalLength, aperture, focusDistance,
|
|
53
|
+
enableDOF, focalLength, aperture, focusDistance, unitsPerMetre, apertureScale, anamorphicRatio, dofMode, dofBlur,
|
|
54
54
|
) );
|
|
55
55
|
|
|
56
56
|
const color = vec4( 1.0, 0.0, 1.0, 1.0 ).toVar();
|
|
@@ -40,7 +40,7 @@ export function buildGenerateKernel( params ) {
|
|
|
40
40
|
resolution, frame,
|
|
41
41
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
42
42
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
43
|
-
enableDOF, focalLength, aperture, focusDistance,
|
|
43
|
+
enableDOF, focalLength, aperture, focusDistance, unitsPerMetre, apertureScale, anamorphicRatio, dofMode, dofBlur,
|
|
44
44
|
renderWidth,
|
|
45
45
|
chunkRowBase, chunkRows, // row band offset (global first row) + row count for this chunk
|
|
46
46
|
transmissiveBounces, // per-ray refraction budget (megakernel parity: PathTracerCore.js:606)
|
|
@@ -78,7 +78,7 @@ export function buildGenerateKernel( params ) {
|
|
|
78
78
|
jitteredUV, seed,
|
|
79
79
|
cameraWorldMatrix, cameraProjectionMatrixInverse,
|
|
80
80
|
cameraProjection, panoLonRange, panoLatRange, panoLevelHorizon,
|
|
81
|
-
enableDOF, focalLength, aperture, focusDistance,
|
|
81
|
+
enableDOF, focalLength, aperture, focusDistance, unitsPerMetre, apertureScale, anamorphicRatio, dofMode, dofBlur,
|
|
82
82
|
) );
|
|
83
83
|
|
|
84
84
|
writeRayOriginMeta( rayBufferRW, rayID, ray.origin, int( 0 ), int( 0 ) );
|
package/src/index.js
CHANGED
|
@@ -96,6 +96,10 @@ export { TransformManager } from './managers/TransformManager.js';
|
|
|
96
96
|
// Video rendering
|
|
97
97
|
export { VideoRenderManager } from './managers/VideoRenderManager.js';
|
|
98
98
|
|
|
99
|
+
// Authored animation: keyframed tracks on one timeline (engine.timeline)
|
|
100
|
+
export { TimelineManager } from './managers/timeline/TimelineManager.js';
|
|
101
|
+
export { CameraTrack } from './managers/timeline/CameraTrack.js';
|
|
102
|
+
|
|
99
103
|
// Interaction
|
|
100
104
|
export { InteractionManager } from './managers/InteractionManager.js';
|
|
101
105
|
|