rayzee 8.5.0 → 8.6.1
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 -56
- package/dist/{DLSSNeural-BNSJ8V3z.js → NeuralRetouch-CYOJ21Wn.js} +33 -33
- package/dist/{DLSSSuperRes-BoEW89Cl.js → NeuralSuperRes-Dc6jRYke.js} +25 -25
- package/dist/ToneMapGPU-BVE852iN.js +533 -0
- package/dist/rayzee.es.js +27235 -9074
- package/dist/rayzee.umd.js +255 -187
- package/package.json +1 -1
- package/src/AssetConfig.js +21 -7
- 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/Passes/OIDNDenoiser.js +13 -5
- 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 +32 -4
- package/src/managers/DenoisingManager.js +60 -44
- package/src/managers/EnvironmentManager.js +20 -0
- package/src/managers/MaterialDataManager.js +118 -208
- package/src/managers/UniformManager.js +1 -0
- package/src/{dlss/DLSSNeural.js → neural/NeuralRetouch.js} +42 -41
- package/src/{dlss/DLSSSuperRes.js → neural/NeuralSuperRes.js} +27 -26
- 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,
|
|
@@ -98,8 +99,35 @@ export { VideoRenderManager } from './managers/VideoRenderManager.js';
|
|
|
98
99
|
// Interaction
|
|
99
100
|
export { InteractionManager } from './managers/InteractionManager.js';
|
|
100
101
|
|
|
101
|
-
//
|
|
102
|
+
// Neural post passes. The app drives these through `denoisingManager` — what is exported here is
|
|
102
103
|
// the offline entry point (`renderUpscaled`, used by the regression bench) plus the two contracts a
|
|
103
104
|
// host needs to build UI against.
|
|
104
|
-
export { renderUpscaled, SR_SCALE, SR_MAX_INPUT } from './
|
|
105
|
-
export {
|
|
105
|
+
export { renderUpscaled, SR_SCALE, SR_MAX_INPUT } from './neural/NeuralSuperRes.js';
|
|
106
|
+
export { RETOUCH_DEFAULTS, RETOUCH_RANGES, RETOUCH_MAX_PIXELS } from './neural/NeuralRetouch.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';
|
|
@@ -4,9 +4,9 @@ import { AIUpscaler } from '../Passes/AIUpscaler.js';
|
|
|
4
4
|
import { EngineEvents } from '../EngineEvents.js';
|
|
5
5
|
import { createLogger } from '../utils/Logger.js';
|
|
6
6
|
|
|
7
|
-
// The neural passes live in `../
|
|
8
|
-
// share one namespace: `rayzee.log.only( '
|
|
9
|
-
const
|
|
7
|
+
// The neural passes live in `../neural/` but report through the manager that drives them, so they
|
|
8
|
+
// share one namespace: `rayzee.log.only( 'neural' )` shows the whole chain.
|
|
9
|
+
const neuralLog = createLogger( 'neural' );
|
|
10
10
|
import { ENGINE_DEFAULTS as DEFAULT_STATE, ASVGF_QUALITY_PRESETS, NRD_DEFAULTS, NRD_QUALITY_PRESETS, NRD_PRESET_KEYS } from '../EngineDefaults.js';
|
|
11
11
|
|
|
12
12
|
// A refresh slower than this is a slideshow, not a live view, so the cadence swaps to a cheaper
|
|
@@ -112,16 +112,16 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
112
112
|
|
|
113
113
|
this.denoiser = null;
|
|
114
114
|
this.upscaler = null;
|
|
115
|
-
// Which model the AI upscaler runs. 'esrgan' is the ONNX chain; '
|
|
115
|
+
// Which model the AI upscaler runs. 'esrgan' is the ONNX chain; 'neural' is the neural
|
|
116
116
|
// super-resolution pass, which is fixed at 2x and needs a denoised source.
|
|
117
117
|
this.upscalerBackend = 'esrgan';
|
|
118
|
-
this.
|
|
118
|
+
this._neuralUpscaler = null;
|
|
119
119
|
// The neural-rendering (detail) pass is independent of the upscaler: it changes appearance,
|
|
120
120
|
// not resolution, and runs last because its result cannot be read back.
|
|
121
121
|
this.neuralRendering = false;
|
|
122
122
|
this.neuralRenderingSettings = {};
|
|
123
|
-
this.
|
|
124
|
-
this.
|
|
123
|
+
this._retouch = null;
|
|
124
|
+
this._superResModule = null;
|
|
125
125
|
this._neuralPostBusy = false;
|
|
126
126
|
|
|
127
127
|
// The tier the finished image uses. The loaded tier is not always this one: while the
|
|
@@ -162,6 +162,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
162
162
|
// Bound event forwarding handlers (stored for removal on re-setup / dispose)
|
|
163
163
|
this._denoiserStartHandler = null;
|
|
164
164
|
this._denoiserEndHandler = null;
|
|
165
|
+
this._denoiserTileHandler = null;
|
|
165
166
|
this._upscalerResChangedHandler = null;
|
|
166
167
|
this._upscalerStartHandler = null;
|
|
167
168
|
this._upscalerProgressHandler = null;
|
|
@@ -298,8 +299,21 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
298
299
|
|
|
299
300
|
};
|
|
300
301
|
|
|
302
|
+
// The loop has stopped by the time a final denoise runs, so each tile has to redraw the
|
|
303
|
+
// canvas itself. Not through the display-refresh callback: that restarts the loop, which a
|
|
304
|
+
// video export drives by hand.
|
|
305
|
+
this._denoiserTileHandler = e => {
|
|
306
|
+
|
|
307
|
+
if ( e.continuous ) return;
|
|
308
|
+
this._publishOutput();
|
|
309
|
+
const ctx = this.pipeline?.context;
|
|
310
|
+
if ( this._stages.compositor && ctx ) this._stages.compositor.render( ctx );
|
|
311
|
+
|
|
312
|
+
};
|
|
313
|
+
|
|
301
314
|
this.denoiser.addEventListener( 'start', this._denoiserStartHandler );
|
|
302
315
|
this.denoiser.addEventListener( 'end', this._denoiserEndHandler );
|
|
316
|
+
this.denoiser.addEventListener( 'tileProgress', this._denoiserTileHandler );
|
|
303
317
|
|
|
304
318
|
}
|
|
305
319
|
|
|
@@ -804,20 +818,20 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
804
818
|
}
|
|
805
819
|
|
|
806
820
|
/**
|
|
807
|
-
* Selects the AI upscaler's model. '
|
|
821
|
+
* Selects the AI upscaler's model. 'neural' is fixed at 2x and reads the denoised picture, so it
|
|
808
822
|
* is a no-op without a denoiser — feeding it raw Monte-Carlo noise measurably loses to bilinear.
|
|
809
823
|
*
|
|
810
|
-
* @param {'esrgan'|'
|
|
824
|
+
* @param {'esrgan'|'neural'} backend
|
|
811
825
|
*/
|
|
812
826
|
setUpscalerBackend( backend ) {
|
|
813
827
|
|
|
814
|
-
const next = backend === '
|
|
828
|
+
const next = backend === 'neural' ? 'neural' : 'esrgan';
|
|
815
829
|
if ( next === this.upscalerBackend ) return;
|
|
816
830
|
|
|
817
831
|
this.upscalerBackend = next;
|
|
818
832
|
// Whatever is on screen came from the model being switched away from.
|
|
819
833
|
this._restoreRenderDisplay();
|
|
820
|
-
if ( next !== '
|
|
834
|
+
if ( next !== 'neural' ) this._releaseNeuralUpscaler();
|
|
821
835
|
|
|
822
836
|
}
|
|
823
837
|
|
|
@@ -847,15 +861,15 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
847
861
|
|
|
848
862
|
}
|
|
849
863
|
|
|
850
|
-
|
|
864
|
+
_releaseNeuralUpscaler() {
|
|
851
865
|
|
|
852
|
-
this.
|
|
853
|
-
this.
|
|
866
|
+
this._neuralUpscaler?.dispose();
|
|
867
|
+
this._neuralUpscaler = null;
|
|
854
868
|
|
|
855
869
|
// The frame packer lives on the module, not on the upscaler, and holds two buffers the size
|
|
856
870
|
// of the render. Nothing else reaches it, so this is its only release point. Guarded on the
|
|
857
871
|
// module having been loaded, so a teardown never pulls in 1 MB of runtime to call a no-op.
|
|
858
|
-
this.
|
|
872
|
+
this._superResModule?.releaseDenoisedReader();
|
|
859
873
|
|
|
860
874
|
}
|
|
861
875
|
|
|
@@ -866,17 +880,17 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
866
880
|
if ( settings ) this.neuralRenderingSettings = { ...this.neuralRenderingSettings, ...settings };
|
|
867
881
|
if ( ! this.neuralRendering ) {
|
|
868
882
|
|
|
869
|
-
this.
|
|
883
|
+
this._releaseNeuralRetouch();
|
|
870
884
|
this._restoreRenderDisplay();
|
|
871
885
|
|
|
872
886
|
}
|
|
873
887
|
|
|
874
888
|
}
|
|
875
889
|
|
|
876
|
-
|
|
890
|
+
_releaseNeuralRetouch() {
|
|
877
891
|
|
|
878
|
-
this.
|
|
879
|
-
this.
|
|
892
|
+
this._retouch?.dispose();
|
|
893
|
+
this._retouch = null;
|
|
880
894
|
|
|
881
895
|
}
|
|
882
896
|
|
|
@@ -894,7 +908,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
894
908
|
*/
|
|
895
909
|
async _runNeuralPost( isStillComplete ) {
|
|
896
910
|
|
|
897
|
-
const wantSR = this.upscaler?.enabled && this.upscalerBackend === '
|
|
911
|
+
const wantSR = this.upscaler?.enabled && this.upscalerBackend === 'neural';
|
|
898
912
|
const wantNR = this.neuralRendering;
|
|
899
913
|
if ( ! wantSR && ! wantNR ) return;
|
|
900
914
|
|
|
@@ -904,14 +918,14 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
904
918
|
|
|
905
919
|
if ( ! this.upscalerCanvas ) {
|
|
906
920
|
|
|
907
|
-
|
|
921
|
+
neuralLog.warn( 'neural pass skipped: the engine has no overlay canvas to present on' );
|
|
908
922
|
return;
|
|
909
923
|
|
|
910
924
|
}
|
|
911
925
|
|
|
912
926
|
if ( ! this.pipeline?.context?.getTexture( 'oidn:output' ) ) {
|
|
913
927
|
|
|
914
|
-
|
|
928
|
+
neuralLog.warn( 'neural pass skipped: no denoised picture — it needs OIDN' );
|
|
915
929
|
return;
|
|
916
930
|
|
|
917
931
|
}
|
|
@@ -921,26 +935,26 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
921
935
|
|
|
922
936
|
try {
|
|
923
937
|
|
|
924
|
-
const sr = await import( '../
|
|
925
|
-
this.
|
|
938
|
+
const sr = await import( '../neural/NeuralSuperRes.js' );
|
|
939
|
+
this._superResModule = sr;
|
|
926
940
|
|
|
927
941
|
// The detail pass has a size ceiling — above it a run takes minutes and then loses every GPU
|
|
928
942
|
// device in the page. Running it FIRST is what keeps it under: at render size it sees a
|
|
929
943
|
// quarter of the pixels it would after a 2x upscale, and the render reserve already caps
|
|
930
944
|
// that at 2048. The check stays as a floor under a raised reserve.
|
|
931
|
-
const nrModule = wantNR ? await import( '../
|
|
945
|
+
const nrModule = wantNR ? await import( '../neural/NeuralRetouch.js' ) : null;
|
|
932
946
|
const srcSize = this.denoiser?._outTexSize;
|
|
933
947
|
const nrPixels = ( srcSize?.width ?? 0 ) * ( srcSize?.height ?? 0 );
|
|
934
|
-
const runNR = wantNR && nrPixels <= nrModule.
|
|
948
|
+
const runNR = wantNR && nrPixels <= nrModule.RETOUCH_MAX_PIXELS;
|
|
935
949
|
|
|
936
950
|
if ( wantNR && ! runNR ) {
|
|
937
951
|
|
|
938
|
-
|
|
952
|
+
neuralLog.warn(
|
|
939
953
|
`Neural rendering skipped: the render is ${( nrPixels / 1e6 ).toFixed( 1 )} MP, above the ` +
|
|
940
|
-
`${( nrModule.
|
|
954
|
+
`${( nrModule.RETOUCH_MAX_PIXELS / 1e6 ).toFixed( 1 )} MP the pass survives.` +
|
|
941
955
|
( wantSR ? ' The upscale still ran.' : '' )
|
|
942
956
|
);
|
|
943
|
-
this.
|
|
957
|
+
this._releaseNeuralRetouch();
|
|
944
958
|
|
|
945
959
|
}
|
|
946
960
|
|
|
@@ -961,16 +975,16 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
961
975
|
|
|
962
976
|
if ( wantSR ) {
|
|
963
977
|
|
|
964
|
-
if ( this.
|
|
965
|
-
&& ( this.
|
|
978
|
+
if ( this._neuralUpscaler
|
|
979
|
+
&& ( this._neuralUpscaler.inputWidth !== source.width || this._neuralUpscaler.inputHeight !== source.height ) ) {
|
|
966
980
|
|
|
967
|
-
this.
|
|
981
|
+
this._releaseNeuralUpscaler();
|
|
968
982
|
|
|
969
983
|
}
|
|
970
984
|
|
|
971
|
-
if ( ! this.
|
|
985
|
+
if ( ! this._neuralUpscaler ) {
|
|
972
986
|
|
|
973
|
-
this.
|
|
987
|
+
this._neuralUpscaler = await sr.NeuralSuperRes.create( { width: source.width, height: source.height } );
|
|
974
988
|
|
|
975
989
|
}
|
|
976
990
|
|
|
@@ -979,23 +993,23 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
979
993
|
let image = source;
|
|
980
994
|
|
|
981
995
|
// Detail first, upscale second. The detail pass hands back scene-referred light (see
|
|
982
|
-
// `
|
|
996
|
+
// the runtime's `rayzee-patch` edits), so the upscaler still gets the linear HDR it expects —
|
|
983
997
|
// which is what makes this order possible at all.
|
|
984
998
|
if ( runNR ) {
|
|
985
999
|
|
|
986
1000
|
const result = await nrModule.enhanceFrame( {
|
|
987
1001
|
source: image,
|
|
988
1002
|
settings: this.neuralRenderingSettings,
|
|
989
|
-
instance: this.
|
|
1003
|
+
instance: this._retouch,
|
|
990
1004
|
exposure: tone.exposure,
|
|
991
1005
|
tone: wantSR ? null : tone,
|
|
992
1006
|
} );
|
|
993
|
-
this.
|
|
1007
|
+
this._retouch = result.instance;
|
|
994
1008
|
image = result;
|
|
995
1009
|
|
|
996
1010
|
}
|
|
997
1011
|
|
|
998
|
-
if ( wantSR ) image = await this.
|
|
1012
|
+
if ( wantSR ) image = await this._neuralUpscaler.upscaleToRGBA8( image, tone );
|
|
999
1013
|
|
|
1000
1014
|
if ( ! isStillComplete() ) {
|
|
1001
1015
|
|
|
@@ -1024,7 +1038,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1024
1038
|
|
|
1025
1039
|
} catch ( error ) {
|
|
1026
1040
|
|
|
1027
|
-
|
|
1041
|
+
neuralLog.warn( 'neural pass failed', error );
|
|
1028
1042
|
|
|
1029
1043
|
} finally {
|
|
1030
1044
|
|
|
@@ -1060,7 +1074,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1060
1074
|
|
|
1061
1075
|
// One owner of the overlay canvas, so the neural chain and the ONNX upscaler are
|
|
1062
1076
|
// exclusive. The neural chain also runs on its own when only its detail pass is on.
|
|
1063
|
-
if ( this.neuralRendering || ( this.upscaler?.enabled && this.upscalerBackend === '
|
|
1077
|
+
if ( this.neuralRendering || ( this.upscaler?.enabled && this.upscalerBackend === 'neural' ) ) {
|
|
1064
1078
|
|
|
1065
1079
|
this._runNeuralPost( isStillComplete );
|
|
1066
1080
|
return;
|
|
@@ -1184,8 +1198,8 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1184
1198
|
// Remove pending completion-chain listener
|
|
1185
1199
|
this._cleanupCompletionListener();
|
|
1186
1200
|
// Owns a second GPUDevice plus 3 MB of weights, so it must not outlive the manager.
|
|
1187
|
-
this.
|
|
1188
|
-
this.
|
|
1201
|
+
this._releaseNeuralUpscaler();
|
|
1202
|
+
this._releaseNeuralRetouch();
|
|
1189
1203
|
|
|
1190
1204
|
// Before the denoiser destroys the picture the Compositor would otherwise still sample.
|
|
1191
1205
|
this._unpublishOutput();
|
|
@@ -1194,6 +1208,7 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1194
1208
|
|
|
1195
1209
|
if ( this._denoiserStartHandler ) this.denoiser.removeEventListener( 'start', this._denoiserStartHandler );
|
|
1196
1210
|
if ( this._denoiserEndHandler ) this.denoiser.removeEventListener( 'end', this._denoiserEndHandler );
|
|
1211
|
+
if ( this._denoiserTileHandler ) this.denoiser.removeEventListener( 'tileProgress', this._denoiserTileHandler );
|
|
1197
1212
|
this.denoiser.dispose();
|
|
1198
1213
|
this.denoiser = null;
|
|
1199
1214
|
|
|
@@ -1207,15 +1222,16 @@ export class DenoisingManager extends EventDispatcher {
|
|
|
1207
1222
|
if ( this._upscalerEndHandler ) this.upscaler.removeEventListener( 'end', this._upscalerEndHandler );
|
|
1208
1223
|
this.upscaler.dispose();
|
|
1209
1224
|
this.upscaler = null;
|
|
1210
|
-
// Which model the AI upscaler runs. 'esrgan' is the ONNX chain; '
|
|
1225
|
+
// Which model the AI upscaler runs. 'esrgan' is the ONNX chain; 'neural' is the neural
|
|
1211
1226
|
// super-resolution pass, which is fixed at 2x and needs a denoised source.
|
|
1212
1227
|
this.upscalerBackend = 'esrgan';
|
|
1213
|
-
this.
|
|
1228
|
+
this._neuralUpscaler = null;
|
|
1214
1229
|
|
|
1215
1230
|
}
|
|
1216
1231
|
|
|
1217
1232
|
this._denoiserStartHandler = null;
|
|
1218
1233
|
this._denoiserEndHandler = null;
|
|
1234
|
+
this._denoiserTileHandler = null;
|
|
1219
1235
|
this._upscalerResChangedHandler = null;
|
|
1220
1236
|
this._upscalerStartHandler = null;
|
|
1221
1237
|
this._upscalerProgressHandler = null;
|