rayzee 8.5.0 → 8.6.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 +60 -4
- package/dist/{DLSSNeural-BNSJ8V3z.js → DLSSNeural-BhBCBgKf.js} +5 -5
- package/dist/{DLSSSuperRes-BoEW89Cl.js → DLSSSuperRes-BCA7F_k5.js} +5 -5
- package/dist/ToneMapGPU-BzcLheoR.js +533 -0
- package/dist/rayzee.es.js +27198 -9047
- package/dist/rayzee.umd.js +255 -187
- package/package.json +1 -1
- package/src/AssetConfig.js +15 -2
- package/src/Color/BakedViews.js +134 -0
- package/src/Color/BuiltinViews.js +261 -0
- package/src/Color/ColorManagement.js +1130 -0
- package/src/Color/ColorSpaces.js +432 -0
- package/src/Color/Displays.js +19 -0
- package/src/Color/InputColorSpaces.js +243 -0
- package/src/Color/LutBake.js +371 -0
- package/src/Color/OcioRuntime.js +338 -0
- package/src/Color/OcioViews.js +419 -0
- package/src/Color/ViewTransforms.js +323 -0
- package/src/Color/WorkingMatrix.js +86 -0
- package/src/EngineDefaults.js +55 -3
- package/src/EngineIssues.js +3 -0
- package/src/Passes/AIUpscaler.js +16 -7
- package/src/PathTracerApp.js +227 -7
- package/src/Processor/AssetLoader.js +1 -2
- package/src/Processor/EmissiveTriangleBuilder.js +34 -2
- package/src/Processor/GeometryExtractor.js +151 -138
- package/src/Processor/LightSerializer.js +8 -3
- package/src/Processor/MaterialPacking.js +168 -0
- package/src/Processor/PackedRayBuffer.js +6 -2
- package/src/Processor/ProceduralSky.js +4 -0
- package/src/Processor/SceneProcessor.js +25 -1
- package/src/Processor/SimpleSky.js +8 -0
- package/src/Processor/TextureCreator.js +137 -91
- package/src/Processor/TextureReadback.js +92 -0
- package/src/Processor/ToneMapCPU.js +80 -165
- package/src/Processor/ToneMapGPU.js +122 -151
- package/src/RenderSettings.js +1 -0
- package/src/Stages/Compositor.js +11 -2
- package/src/Stages/PathTracer.js +2 -0
- package/src/Stages/PathTracerStage.js +1 -1
- package/src/TSL/Common.js +15 -0
- package/src/TSL/Debugger.js +2 -3
- package/src/TSL/EmissiveSampling.js +6 -8
- package/src/TSL/ExtendKernel.js +9 -0
- package/src/TSL/Fresnel.js +23 -1
- package/src/TSL/HitFacet.js +102 -0
- package/src/TSL/LightsDirect.js +12 -33
- package/src/TSL/LightsSampling.js +15 -7
- package/src/TSL/MaterialEvaluation.js +26 -19
- package/src/TSL/MaterialProperties.js +74 -37
- package/src/TSL/MaterialTransmission.js +2 -3
- package/src/TSL/ShadeKernel.js +34 -21
- package/src/TSL/ShadowTerminator.js +125 -0
- package/src/TSL/Struct.js +9 -0
- package/src/TSL/Subsurface.js +2 -3
- package/src/index.js +29 -1
- package/src/managers/EnvironmentManager.js +20 -0
- package/src/managers/MaterialDataManager.js +118 -208
- package/src/managers/UniformManager.js +1 -0
- package/dist/ToneMapGPU-DzqSyzTx.js +0 -341
package/src/TSL/ShadeKernel.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
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,
|
|
11
11
|
instanceIndex,
|
|
12
12
|
sampler,
|
|
13
13
|
atomicAdd, atomicLoad, atomicStore, uintBitsToFloat,
|
|
@@ -15,20 +15,21 @@ import {
|
|
|
15
15
|
} from 'three/tsl';
|
|
16
16
|
|
|
17
17
|
import { sampleEnvironment, sampleEquirectProbability, sampleEquirect, groundProjectedEnvDir } from './Environment.js';
|
|
18
|
-
import { getMaterial, powerHeuristic, balanceHeuristic, classifyMaterial, REC709_LUMINANCE_COEFFICIENTS, PI_INV, EPSILON, diffuseGroundMaterial } from './Common.js';
|
|
18
|
+
import { getMaterial, powerHeuristic, balanceHeuristic, classifyMaterial, REC709_LUMINANCE_COEFFICIENTS, PI_INV, EPSILON, diffuseGroundMaterial, offsetRayOrigin, SHADOW_END } from './Common.js';
|
|
19
19
|
import { cosineWeightedSample } from './MaterialSampling.js';
|
|
20
20
|
import { sampleAllMaterialTextures, processAnisotropyMap, applyExtensionMaps, getTransformedUV, triangleUVTangent } from './TextureSampling.js';
|
|
21
21
|
import { evaluateMaterialResponse } from './MaterialEvaluation.js';
|
|
22
22
|
import { calculateDirectLightingUnified, calculateMaterialPDF } from './LightsSampling.js';
|
|
23
|
-
import { traceShadowRay
|
|
23
|
+
import { traceShadowRay } from './LightsDirect.js';
|
|
24
|
+
import { shadowTerminatorOrigin } from './ShadowTerminator.js';
|
|
25
|
+
import { unpackHitFacet } from './HitFacet.js';
|
|
24
26
|
import { traverseBVHShadow } from './BVHTraversal.js';
|
|
25
27
|
import { handleMaterialTransparency, MaterialInteractionResult } from './MaterialTransmission.js';
|
|
26
28
|
import { sampleChromaticCollision, sampleHenyeyGreenstein, subsurfaceCoefficients, CollisionSample, MediumCoeffs } from './Subsurface.js';
|
|
27
29
|
import { calculateIndirectLighting } from './LightsIndirect.js';
|
|
28
30
|
import { IndirectLightingResult, sampleCone } from './LightsCore.js';
|
|
29
31
|
import { regularizePathContribution, generateSampledDirection, computeNDCDepth, handleRussianRoulette } from './PathTracerCore.js';
|
|
30
|
-
import {
|
|
31
|
-
import { dielectricF0 } from './Fresnel.js';
|
|
32
|
+
import { evaluateSpecularDFG, baseFresnelParams } from './MaterialProperties.js';
|
|
32
33
|
import { NRD_HIT_DIST_A, NRD_HIT_DIST_B } from '../EngineDefaults.js';
|
|
33
34
|
import { sampleClearcoat, ClearcoatResult } from './Clearcoat.js';
|
|
34
35
|
import { refineDisplacedIntersection, DisplacementResult } from './Displacement.js';
|
|
@@ -46,6 +47,7 @@ import {
|
|
|
46
47
|
MaterialCache,
|
|
47
48
|
DirectLightingDual,
|
|
48
49
|
DFGResult,
|
|
50
|
+
BaseFresnel,
|
|
49
51
|
} from './Struct.js';
|
|
50
52
|
import { getRandomSample, getRandomSample1D, getRandomSample2D, SAMPLER_DIMS_PER_BOUNCE, SAMPLER_DIM_AUX_BASE } from './Random.js';
|
|
51
53
|
import { RAY_FLAG, COUNTER } from '../Processor/QueueManager.js';
|
|
@@ -56,7 +58,7 @@ import {
|
|
|
56
58
|
readTransparentCount,
|
|
57
59
|
readMisRayT,
|
|
58
60
|
readHitDistance, readHitBarycentrics, readHitNormal,
|
|
59
|
-
readHitMaterialIndex, readHitTriangleIndex, readHitInstanceLeaf,
|
|
61
|
+
readHitMaterialIndex, readHitTriangleIndex, readHitInstanceLeaf, readHitFacet,
|
|
60
62
|
writeRayOriginMeta, writeRayDirFlags, writeRayThroughputPdf, writeRayRadiance,
|
|
61
63
|
writeGBuffer, writeGBufferHitDist, readGBuffer, gbDecodeNormalDepth,
|
|
62
64
|
readRayRadiance,
|
|
@@ -96,6 +98,7 @@ export function buildShadeKernel( params ) {
|
|
|
96
98
|
globalIlluminationIntensity,
|
|
97
99
|
cameraProjectionMatrix, cameraViewMatrix,
|
|
98
100
|
fireflyThreshold, frame, resolution,
|
|
101
|
+
shadowTerminatorOffset, // Cycles' Shadow Terminator → Geometry Offset; 0 disables
|
|
99
102
|
// Accumulation index, NOT the free-running seed counter `frame` rides. The firefly clamp
|
|
100
103
|
// relaxes as sqrt(frame+1) so its bias decays as a render converges; keying that off the
|
|
101
104
|
// seed axis let it grow for the whole session and disabled suppression outright.
|
|
@@ -283,6 +286,7 @@ export function buildShadeKernel( params ) {
|
|
|
283
286
|
envTotalSum, envCompensationDelta, envResolution,
|
|
284
287
|
enableEnvironmentLight,
|
|
285
288
|
tslBool( true ), // wantUnoccluded
|
|
289
|
+
vec3( 0.0 ), planeN, float( 0.0 ),
|
|
286
290
|
) ).toVar();
|
|
287
291
|
|
|
288
292
|
const lumShad = max( dot( dual.shadowed, REC709_LUMINANCE_COEFFICIENTS ), float( 0.0 ) );
|
|
@@ -930,10 +934,9 @@ export function buildShadeKernel( params ) {
|
|
|
930
934
|
|
|
931
935
|
throughput.mulAssign( interaction.throughput );
|
|
932
936
|
|
|
933
|
-
//
|
|
934
|
-
const
|
|
935
|
-
const
|
|
936
|
-
const newOrigin = hitPoint.add( offsetDir.mul( 0.001 ) );
|
|
937
|
+
// Off the side of the facet the new ray leaves on: reflection stays, transmission and alpha skip cross.
|
|
938
|
+
const Ng = unpackHitFacet( readHitFacet( hitBufferRO, rayID ) ).faceN;
|
|
939
|
+
const newOrigin = offsetRayOrigin( hitPoint, select( dot( Ng, interaction.direction ).lessThan( 0.0 ), Ng.negate(), Ng ) );
|
|
937
940
|
|
|
938
941
|
// SSS = free bounce (depth unchanged); transmission advances camera-bounce depth.
|
|
939
942
|
// Transmissive / alpha-skip / SSS-boundary are all FREE bounces — they do NOT advance camera depth (megakernel parity, gap #4). cameraDepth advances only on opaque scatter (below).
|
|
@@ -1062,6 +1065,14 @@ export function buildShadeKernel( params ) {
|
|
|
1062
1065
|
// face-forwarded geometric normal: horizon guard for NEE and the bounce continuation
|
|
1063
1066
|
const Ngeo = normalize( hitNormal );
|
|
1064
1067
|
const NgeoFF = select( dot( Ngeo, V ).lessThan( 0.0 ), Ngeo.negate(), Ngeo ).toVar();
|
|
1068
|
+
// The facet on the viewer's side: every ray spawned from here is offset off it (HitFacet.js).
|
|
1069
|
+
const facet = unpackHitFacet( readHitFacet( hitBufferRO, rayID ) );
|
|
1070
|
+
const facetN = facet.faceN.toVar();
|
|
1071
|
+
const terminatorLift = Ngeo.mul( facet.liftScale );
|
|
1072
|
+
const lightShadowOrigin = L => shadowTerminatorOrigin( {
|
|
1073
|
+
hitPoint, offsetNormal: facetN, lift: terminatorLift, faceN: facetN, smoothN: NgeoFF, L,
|
|
1074
|
+
cutoff: shadowTerminatorOffset,
|
|
1075
|
+
} );
|
|
1065
1076
|
|
|
1066
1077
|
// Two-sided shading: opaque path only (transmissive/SSS already continued). Decide the flip on the
|
|
1067
1078
|
// GEOMETRIC normal — an inward-normal / double-sided mesh (GLB/PBRT) faces away as a whole — so a
|
|
@@ -1094,11 +1105,11 @@ export function buildShadeKernel( params ) {
|
|
|
1094
1105
|
// smooth mirror / metal: DEFER — tint by the specular directional albedo (metal colour),
|
|
1095
1106
|
// matching the opaque throughput (≈ F at the near-delta mirror lobe). Achromatic energy excluded.
|
|
1096
1107
|
const NoV = max( dot( N, V ), float( 1e-3 ) );
|
|
1097
|
-
const
|
|
1098
|
-
|
|
1099
|
-
vec3( 0.0 ),
|
|
1100
|
-
|
|
1101
|
-
|
|
1108
|
+
const bf = BaseFresnel.wrap( baseFresnelParams( material, albedo ) );
|
|
1109
|
+
featCarry.mulAssign( DFGResult.wrap( evaluateSpecularDFG(
|
|
1110
|
+
bf.f0, bf.f90, bf.eta, bf.F0m, material.metalness, vec3( 0.0 ), float( 0.0 ), bf.F0,
|
|
1111
|
+
NoV, max( rawRough, float( 0.02 ) ),
|
|
1112
|
+
) ).E_total );
|
|
1102
1113
|
|
|
1103
1114
|
} );
|
|
1104
1115
|
|
|
@@ -1176,6 +1187,7 @@ export function buildShadeKernel( params ) {
|
|
|
1176
1187
|
envTotalSum, envCompensationDelta, envResolution,
|
|
1177
1188
|
enableEnvironmentLight,
|
|
1178
1189
|
tslBool( false ), // wantUnoccluded: false on real surfaces — dead-codes the unoccluded sum
|
|
1190
|
+
terminatorLift, facetN, shadowTerminatorOffset,
|
|
1179
1191
|
) ).shadowed.toVar();
|
|
1180
1192
|
|
|
1181
1193
|
const giScale = select( bounceIndex.greaterThan( 0 ), globalIlluminationIntensity, float( 1.0 ) );
|
|
@@ -1230,11 +1242,12 @@ export function buildShadeKernel( params ) {
|
|
|
1230
1242
|
|
|
1231
1243
|
If( NoL.greaterThan( 0.0 ).and( dot( emissiveSample.direction, NgeoFF ).greaterThan( 0.0 ) ), () => {
|
|
1232
1244
|
|
|
1233
|
-
|
|
1234
|
-
const rayOrigin =
|
|
1235
|
-
const
|
|
1245
|
+
// Aimed at the sampled point and stopped a relative hair short, as for area lights.
|
|
1246
|
+
const rayOrigin = lightShadowOrigin( emissiveSample.direction ).toVar();
|
|
1247
|
+
const toSample = emissiveSample.position.sub( rayOrigin ).toVar();
|
|
1248
|
+
const shadowDist = length( toSample ).toVar();
|
|
1236
1249
|
const visibility = traceShadowRayWrapped(
|
|
1237
|
-
rayOrigin,
|
|
1250
|
+
rayOrigin, toSample.div( shadowDist ), shadowDist.mul( SHADOW_END ),
|
|
1238
1251
|
);
|
|
1239
1252
|
|
|
1240
1253
|
If( visibility.greaterThan( 0.0 ), () => {
|
|
@@ -1278,7 +1291,7 @@ export function buildShadeKernel( params ) {
|
|
|
1278
1291
|
lightBuffer, emissiveVec4Offset, emissiveTriangleCount, emissiveTotalPower,
|
|
1279
1292
|
triangleBuffer, bvhBuffer,
|
|
1280
1293
|
traceShadowRayWrapped,
|
|
1281
|
-
|
|
1294
|
+
Fn( ( [ p, , L ] ) => lightShadowOrigin( L ).sub( p ) ),
|
|
1282
1295
|
);
|
|
1283
1296
|
|
|
1284
1297
|
currentRadiance.assign( vec4(
|
|
@@ -1352,7 +1365,7 @@ export function buildShadeKernel( params ) {
|
|
|
1352
1365
|
|
|
1353
1366
|
} );
|
|
1354
1367
|
|
|
1355
|
-
const newOrigin = hitPoint
|
|
1368
|
+
const newOrigin = offsetRayOrigin( hitPoint, select( dot( facetN, bounceDir ).lessThan( 0.0 ), facetN.negate(), facetN ) );
|
|
1356
1369
|
|
|
1357
1370
|
// Opaque scatter: the only bounce that advances camera depth.
|
|
1358
1371
|
writeRayOriginMeta( rayBufferRW, rayID, newOrigin, cameraDepth.add( 1 ), sssSteps, transparentCount );
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cycles' shadow terminator geometry offset (kernel/light/sample.h, Blender 5.1).
|
|
3
|
+
*
|
|
4
|
+
* Near the terminator of a smooth-shaded low-poly surface, a light's shadow ray leaving the flat
|
|
5
|
+
* facet is blocked by that facet or its neighbours although the smooth normal says the point is lit,
|
|
6
|
+
* which draws the mesh's outline into the shading. Starting the ray on the smooth surface the vertex
|
|
7
|
+
* normals describe — lifted along the normal by a parabolic estimate, bounded by each vertex's
|
|
8
|
+
* tangent plane — removes it. Only light and environment shadow rays use it, as in Cycles.
|
|
9
|
+
*
|
|
10
|
+
* Extend computes the lift with the facet normal (HitFacet.js), where the triangle's corners were just
|
|
11
|
+
* read, and packs both into the hit record's spare lane.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { vec3, float, max, min, dot, length, clamp, select, If } from 'three/tsl';
|
|
15
|
+
import { instanceRows, instanceDirToWorld, offsetRayOrigin } from './Common.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The lift at full strength, as a signed length along the hit's smooth normal, from the triangle's
|
|
19
|
+
* corners (see HitFacet.js). Cycles lifts along the object-to-world image of that normal; the two
|
|
20
|
+
* agree unless the placement scales non-uniformly. Zero on a flat-shaded triangle.
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} p - corners and vertex normals as stored (object space when `instanced`), and
|
|
23
|
+
* `faceN`, the world facet normal on the viewer's side
|
|
24
|
+
*/
|
|
25
|
+
export function shadowTerminatorLift( { V0, V1, V2, N0, N1, N2, hitPoint, instanced, bvhBuffer, instanceLeaf, faceN } ) {
|
|
26
|
+
|
|
27
|
+
const scale = float( 0.0 ).toVar();
|
|
28
|
+
|
|
29
|
+
const P = hitPoint.toVar();
|
|
30
|
+
If( instanced, () => {
|
|
31
|
+
|
|
32
|
+
const rows = instanceRows( bvhBuffer, instanceLeaf );
|
|
33
|
+
P.assign( vec3(
|
|
34
|
+
rows[ 0 ].xyz.dot( hitPoint ).add( rows[ 0 ].w ),
|
|
35
|
+
rows[ 1 ].xyz.dot( hitPoint ).add( rows[ 1 ].w ),
|
|
36
|
+
rows[ 2 ].xyz.dot( hitPoint ).add( rows[ 2 ].w ),
|
|
37
|
+
) );
|
|
38
|
+
|
|
39
|
+
} );
|
|
40
|
+
|
|
41
|
+
// The hit record keeps texture UVs, not barycentrics.
|
|
42
|
+
const e1 = V1.sub( V0 ).toVar();
|
|
43
|
+
const e2 = V2.sub( V0 ).toVar();
|
|
44
|
+
const ep = P.sub( V0 ).toVar();
|
|
45
|
+
const d11 = dot( e1, e1 );
|
|
46
|
+
const d12 = dot( e1, e2 );
|
|
47
|
+
const d22 = dot( e2, e2 );
|
|
48
|
+
const den = d11.mul( d22 ).sub( d12.mul( d12 ) ).toVar();
|
|
49
|
+
|
|
50
|
+
If( den.greaterThan( d11.mul( d22 ).mul( 1e-12 ) ), () => {
|
|
51
|
+
|
|
52
|
+
const dp1 = dot( ep, e1 );
|
|
53
|
+
const dp2 = dot( ep, e2 );
|
|
54
|
+
const v = clamp( d22.mul( dp1 ).sub( d12.mul( dp2 ) ).div( den ), 0.0, 1.0 ).toVar();
|
|
55
|
+
const w = clamp( d11.mul( dp2 ).sub( d12.mul( dp1 ) ).div( den ), 0.0, float( 1.0 ).sub( v ) ).toVar();
|
|
56
|
+
const u = float( 1.0 ).sub( v ).sub( w ).toVar();
|
|
57
|
+
|
|
58
|
+
const Pl = V0.mul( u ).add( V1.mul( v ) ).add( V2.mul( w ) ).toVar();
|
|
59
|
+
const nLocal = N0.mul( u ).add( N1.mul( v ) ).add( N2.mul( w ) ).toVar();
|
|
60
|
+
const n = nLocal.toVar();
|
|
61
|
+
If( instanced, () => {
|
|
62
|
+
|
|
63
|
+
const rows = instanceRows( bvhBuffer, instanceLeaf );
|
|
64
|
+
n.assign( instanceDirToWorld( { r0: rows[ 0 ].xyz, r1: rows[ 1 ].xyz, r2: rows[ 2 ].xyz, v: nLocal } ) );
|
|
65
|
+
|
|
66
|
+
} );
|
|
67
|
+
|
|
68
|
+
// Parabolic approximation.
|
|
69
|
+
const a = dot( N2.sub( N0 ), V0.sub( V2 ) );
|
|
70
|
+
const b = dot( N2.sub( N1 ), V1.sub( V2 ) );
|
|
71
|
+
const c = dot( N1.sub( N0 ), V1.sub( V0 ) );
|
|
72
|
+
const h = a.mul( u ).mul( u.sub( 1.0 ) ).add( a.add( b ).add( c ).mul( u ).mul( v ) ).add( b.mul( v ).mul( v.sub( 1.0 ) ) ).toVar();
|
|
73
|
+
|
|
74
|
+
// Bounded by the local linear envelope of the vertices' tangent planes.
|
|
75
|
+
If( dot( n, faceN ).greaterThan( 0.0 ), () => {
|
|
76
|
+
|
|
77
|
+
const h0 = max( dot( V0.sub( Pl ), N0 ).add( max( max( dot( V1.sub( V0 ), N0 ), dot( V2.sub( V0 ), N0 ) ), 0.0 ) ), 0.0 );
|
|
78
|
+
const h1 = max( dot( V1.sub( Pl ), N1 ).add( max( max( dot( V0.sub( V1 ), N1 ), dot( V2.sub( V1 ), N1 ) ), 0.0 ) ), 0.0 );
|
|
79
|
+
const h2 = max( dot( V2.sub( Pl ), N2 ).add( max( max( dot( V0.sub( V2 ), N2 ), dot( V1.sub( V2 ), N2 ) ), 0.0 ) ), 0.0 );
|
|
80
|
+
h.assign( max( min( min( h0, h1 ), h2 ), h.mul( 0.5 ) ) );
|
|
81
|
+
|
|
82
|
+
} ).Else( () => {
|
|
83
|
+
|
|
84
|
+
const h0 = max( dot( Pl.sub( V0 ), N0 ).add( max( max( dot( V0.sub( V1 ), N0 ), dot( V0.sub( V2 ), N0 ) ), 0.0 ) ), 0.0 );
|
|
85
|
+
const h1 = max( dot( Pl.sub( V1 ), N1 ).add( max( max( dot( V1.sub( V0 ), N1 ), dot( V1.sub( V2 ), N1 ) ), 0.0 ) ), 0.0 );
|
|
86
|
+
const h2 = max( dot( Pl.sub( V2 ), N2 ).add( max( max( dot( V2.sub( V0 ), N2 ), dot( V2.sub( V1 ), N2 ) ), 0.0 ) ), 0.0 );
|
|
87
|
+
h.assign( min( min( min( h0, h1 ), h2 ).negate(), h.mul( 0.5 ) ) );
|
|
88
|
+
|
|
89
|
+
} );
|
|
90
|
+
|
|
91
|
+
scale.assign( length( n ).mul( h ) );
|
|
92
|
+
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
return scale;
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A shadow ray's origin towards direction `L`: lifted by the share of the lift Cycles gives a
|
|
101
|
+
* direction this close to the terminator, then offset as every spawned ray is.
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} p
|
|
104
|
+
* @param {Node} p.lift - the hit's unit smooth normal times the lift's scale
|
|
105
|
+
* @param {Node} p.smoothN - the interpolated normal on the viewer's side (Cycles' sd->N)
|
|
106
|
+
* @param {Node} p.cutoff - the geometry offset setting; 0 disables
|
|
107
|
+
*/
|
|
108
|
+
export function shadowTerminatorOrigin( { hitPoint, offsetNormal, lift, faceN, smoothN, L, cutoff } ) {
|
|
109
|
+
|
|
110
|
+
// Cycles lifts towards the back for a transmitted direction; NEE here only lights the front.
|
|
111
|
+
const NL = dot( smoothN, L );
|
|
112
|
+
const NgL = dot( faceN, L );
|
|
113
|
+
const c = max( cutoff, 1e-6 );
|
|
114
|
+
const amount = select(
|
|
115
|
+
cutoff.greaterThan( 0.0 ).and( NL.greaterThan( 0.0 ) ),
|
|
116
|
+
select(
|
|
117
|
+
NL.lessThan( cutoff ),
|
|
118
|
+
clamp( float( 2.0 ).sub( NgL.add( NL ).div( c ) ), 0.0, 1.0 ),
|
|
119
|
+
clamp( float( 1.0 ).sub( NgL.div( c ) ), 0.0, 1.0 ),
|
|
120
|
+
),
|
|
121
|
+
float( 0.0 ),
|
|
122
|
+
);
|
|
123
|
+
return offsetRayOrigin( hitPoint.add( lift.mul( amount ) ), offsetNormal );
|
|
124
|
+
|
|
125
|
+
}
|
package/src/TSL/Struct.js
CHANGED
|
@@ -198,6 +198,15 @@ export const DFGResult = struct( {
|
|
|
198
198
|
E_total: 'vec3', // clamp(E_ss * compensation, 0, 1)
|
|
199
199
|
} );
|
|
200
200
|
|
|
201
|
+
// Base-layer Fresnel inputs (see baseFresnelParams).
|
|
202
|
+
export const BaseFresnel = struct( {
|
|
203
|
+
f0: 'vec3', // dielectric reflectance head-on: min(F0(ior) * specularColor, 1) * specularIntensity
|
|
204
|
+
f90: 'float', // dielectric reflectance at grazing: specularIntensity
|
|
205
|
+
eta: 'float', // max(ior, 1)
|
|
206
|
+
F0m: 'vec3', // metal F0: color * specularIntensity
|
|
207
|
+
F0: 'vec3', // the two blended by metalness — the multiscatter tint and the iridescence substrate
|
|
208
|
+
} );
|
|
209
|
+
|
|
201
210
|
export const MaterialSamples = struct( {
|
|
202
211
|
albedo: 'vec4',
|
|
203
212
|
emissive: 'vec3',
|
package/src/TSL/Subsurface.js
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import { struct } from './patches.js';
|
|
31
31
|
import { TWO_PI, EPSILON, constructTBN } from './Common.js';
|
|
32
32
|
import { getRandomSample1D, getRandomSample2D } from './Random.js';
|
|
33
|
-
import {
|
|
33
|
+
import { fresnelDielectric } from './Fresnel.js';
|
|
34
34
|
import { ImportanceSampleGGX } from './MaterialSampling.js';
|
|
35
35
|
|
|
36
36
|
// ================================================================================
|
|
@@ -189,8 +189,7 @@ export const handleSubsurfaceEntry = Fn( ( [
|
|
|
189
189
|
const sinThetaT2 = n1.mul( n1 ).div( max( n2.mul( n2 ), EPSILON ) ).mul( float( 1.0 ).sub( cosThetaI.mul( cosThetaI ) ) );
|
|
190
190
|
const tir = sinThetaT2.greaterThan( 1.0 ).toVar();
|
|
191
191
|
|
|
192
|
-
const
|
|
193
|
-
const Fr = select( tir, float( 1.0 ), fresnelSchlickFloat( cosThetaI, F0 ) ).toVar();
|
|
192
|
+
const Fr = fresnelDielectric( cosThetaI, n2.div( max( n1, EPSILON ) ) ).toVar();
|
|
194
193
|
const reflectProb = clamp( Fr, 0.02, 0.98 ).toVar();
|
|
195
194
|
|
|
196
195
|
const doReflect = tir.or( getRandomSample1D( pixelCoord, int( 0 ), dimBase.add( int( 11 ) ), rngState, resolution, frame ).lessThan( reflectProb ) ).toVar();
|
package/src/index.js
CHANGED
|
@@ -27,7 +27,7 @@ export { SETTING_SOURCE } from './RenderSettings.js';
|
|
|
27
27
|
export { configureAssets, getAssetConfig } from './AssetConfig.js';
|
|
28
28
|
|
|
29
29
|
// glTF alphaMode derivation — the one definition, shared with hosts that edit materials
|
|
30
|
-
export { deriveAlphaMode } from './Processor/GeometryExtractor.js';
|
|
30
|
+
export { deriveAlphaMode, MATERIAL_VALUE_SOURCE } from './Processor/GeometryExtractor.js';
|
|
31
31
|
|
|
32
32
|
// Scene-level authoring metadata embedded in model files (glTF `extras`)
|
|
33
33
|
export { extractSceneMetadata, parseSceneMetadata } from './Processor/SceneMetadata.js';
|
|
@@ -53,6 +53,7 @@ export {
|
|
|
53
53
|
BVH_LEAF_MARKERS,
|
|
54
54
|
TEXTURE_CONSTANTS,
|
|
55
55
|
DEFAULT_TEXTURE_MATRIX,
|
|
56
|
+
MATERIAL_DEFAULTS,
|
|
56
57
|
MEMORY_CONSTANTS,
|
|
57
58
|
PRODUCTION_RENDER_CONFIG,
|
|
58
59
|
INTERACTIVE_RENDER_CONFIG,
|
|
@@ -103,3 +104,30 @@ export { InteractionManager } from './managers/InteractionManager.js';
|
|
|
103
104
|
// host needs to build UI against.
|
|
104
105
|
export { renderUpscaled, SR_SCALE, SR_MAX_INPUT } from './dlss/DLSSSuperRes.js';
|
|
105
106
|
export { DLSS_NR_DEFAULTS, DLSS_NR_RANGES, DLSS_NR_MAX_PIXELS } from './dlss/DLSSNeural.js';
|
|
107
|
+
|
|
108
|
+
// ── Colour management ───────────────────────────────────────────────────────────────────────────
|
|
109
|
+
// `app.color` is the instance a host normally uses; these are for building UI against it, and for
|
|
110
|
+
// code that needs the view-transform registry without an app.
|
|
111
|
+
export {
|
|
112
|
+
ColorManagement, getActiveColorManagement, setActiveColorManagement,
|
|
113
|
+
isColorManaged, DEFAULT_WORKING_SPACE, findNativeLinearSpace, canvasColorSpaceFor,
|
|
114
|
+
} from './Color/ColorManagement.js';
|
|
115
|
+
export { displayCanvasFit } from './Color/Displays.js';
|
|
116
|
+
export {
|
|
117
|
+
VIEW_TRANSFORMS, listViewTransforms, getViewTransform, addViewTransform, removeViewTransform,
|
|
118
|
+
onRegistryChange, getRegistryVersion, buildToneMapWGSL,
|
|
119
|
+
OCIO_VIEW_BASE, MAX_TABLE_TRANSFORMS,
|
|
120
|
+
} from './Color/ViewTransforms.js';
|
|
121
|
+
export {
|
|
122
|
+
buildOcioView, addOcioView, addAllOcioViews,
|
|
123
|
+
DEFAULT_LUT_SIZE, DEFAULT_MIN_EV, DEFAULT_MAX_EV,
|
|
124
|
+
} from './Color/OcioViews.js';
|
|
125
|
+
export {
|
|
126
|
+
resolveInputSpace, textureInputSpace, setInputOverride, clearInputOverrides,
|
|
127
|
+
listInputOverrides, listFileRules, isDataTexture,
|
|
128
|
+
} from './Color/InputColorSpaces.js';
|
|
129
|
+
export {
|
|
130
|
+
convertColor, convertPixelsF32, convertEncodedRGBA8, applyMatrixRGBA8, extractMatrix,
|
|
131
|
+
hasColorSpace, isDataSpace, srgbToLinear, linearToSrgb,
|
|
132
|
+
} from './Color/ColorSpaces.js';
|
|
133
|
+
export { measureBakeError, bakeLut, makeCpuSampler } from './Color/LutBake.js';
|
|
@@ -17,6 +17,7 @@ import { createLogger, fmt } from '../utils/Logger.js';
|
|
|
17
17
|
|
|
18
18
|
const log = createLogger( 'env' );
|
|
19
19
|
import { ENGINE_DEFAULTS as DEFAULT_STATE } from '../EngineDefaults.js';
|
|
20
|
+
import { getActiveColorManagement } from '../Color/ColorManagement.js';
|
|
20
21
|
|
|
21
22
|
export class EnvironmentManager {
|
|
22
23
|
|
|
@@ -234,6 +235,25 @@ export class EnvironmentManager {
|
|
|
234
235
|
|
|
235
236
|
if ( ! envTex ) return;
|
|
236
237
|
|
|
238
|
+
// Before the CDF is built, so importance sampling sees the same pixels the shader will.
|
|
239
|
+
// Inert unless a working space has been adopted; the texture's own space is honoured when
|
|
240
|
+
// the host tagged it, otherwise it is taken as linear Rec.709, which is what every HDRI
|
|
241
|
+
// loader produces.
|
|
242
|
+
const cm = getActiveColorManagement();
|
|
243
|
+
if ( cm?.hasConfig ) {
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
|
|
247
|
+
cm.convertTexturePixels( envTex, { space: envTex.userData?.ocioColorSpace ?? null } );
|
|
248
|
+
|
|
249
|
+
} catch ( error ) {
|
|
250
|
+
|
|
251
|
+
log.warn( `environment colour conversion failed, left in its original space: ${error.message}` );
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
}
|
|
256
|
+
|
|
237
257
|
this.environmentTexture = envTex;
|
|
238
258
|
this.envTexSize.set( envTex.image.width, envTex.image.height );
|
|
239
259
|
|