rayzee 8.4.1 → 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 +61 -9
- 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 +27278 -9133
- 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 +84 -4
- package/src/EngineIssues.js +3 -1
- package/src/Passes/AIUpscaler.js +16 -7
- package/src/PathTracerApp.js +318 -35
- package/src/Processor/AssetLoader.js +47 -55
- package/src/Processor/CameraOptimizer.js +22 -6
- package/src/Processor/EmissiveTriangleBuilder.js +34 -2
- package/src/Processor/GeometryExtractor.js +151 -138
- package/src/Processor/LightSerializer.js +17 -20
- 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 +10 -1
- package/src/Stages/Compositor.js +11 -2
- package/src/Stages/PathTracer.js +21 -4
- package/src/Stages/PathTracerStage.js +11 -18
- 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 -2
- package/src/managers/DenoisingManager.js +3 -7
- package/src/managers/EnvironmentManager.js +20 -0
- package/src/managers/LightManager.js +17 -15
- package/src/managers/MaterialDataManager.js +118 -208
- package/src/managers/UniformManager.js +1 -0
- package/src/managers/VideoRenderManager.js +9 -9
- package/dist/ToneMapGPU-DzqSyzTx.js +0 -341
- package/src/LightUnits.js +0 -122
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ A real-time WebGPU path tracing engine built on Three.js. Framework-agnostic —
|
|
|
26
26
|
- [engine.lightManager](#enginelightmanager)
|
|
27
27
|
- [engine.animationManager](#engineanimationmanager)
|
|
28
28
|
- [Materials](#materials)
|
|
29
|
+
- [Colour Management](#colour-management)
|
|
29
30
|
- [engine.environmentManager](#engineenvironmentmanager)
|
|
30
31
|
- [engine.denoisingManager](#enginedenoisingmanager)
|
|
31
32
|
- [engine.interactionManager](#engineinteractionmanager)
|
|
@@ -292,6 +293,11 @@ configureAssets({
|
|
|
292
293
|
dlssRuntimeUrl: '/dlss/dlss-runtime.js',
|
|
293
294
|
dlssAssetBaseUrl: '/dlss/',
|
|
294
295
|
|
|
296
|
+
// OpenColorIO runtime (~6 MB of WebAssembly) — the engine never names the package, so a host
|
|
297
|
+
// that loads colour configs supplies it, bundled or served. Unset, colour management stays inert.
|
|
298
|
+
ocioRuntimeFactory: () => import('@bb-studio/ocio'), // or: ocioRuntimeUrl: '/vendor/ocio/index.js'
|
|
299
|
+
ocioWasmUrl: '/vendor/ocio/ocio-wasm.wasm', // optional override for the .wasm
|
|
300
|
+
|
|
295
301
|
// Prefix for engine-managed IndexedDB stores. Set to a unique value if multiple
|
|
296
302
|
// apps embed the engine on the same origin to avoid cache collisions.
|
|
297
303
|
cacheNamespace: 'my-app',
|
|
@@ -414,13 +420,14 @@ Key settings:
|
|
|
414
420
|
| `maxBounces` | `number` | 3 | Max ray bounce depth |
|
|
415
421
|
| `maxSamples` | `number` | 60 | Max accumulated samples before stopping |
|
|
416
422
|
| `exposure` | `number` | 1.0 | Exposure value |
|
|
417
|
-
| `saturation` | `number` | 1.
|
|
423
|
+
| `saturation` | `number` | 1.0 | Color saturation (1 = no grade) |
|
|
418
424
|
| `enableEnvironment` | `boolean` | true | Use environment lighting |
|
|
419
425
|
| `environmentIntensity` | `number` | 1.0 | Environment light strength |
|
|
420
|
-
| `environmentRotation` | `number` |
|
|
426
|
+
| `environmentRotation` | `number` | 0 | Environment Y-rotation (degrees); 0 shows the HDRI as authored, as Blender's unmapped world does |
|
|
421
427
|
| `showBackground` | `boolean` | true | Show the environment as a visible backdrop for camera-miss rays (vs. a solid/transparent background) |
|
|
422
428
|
| `samplingTechnique` | `number` | 2 | Sampler: `0` PCG, `1` scrambled Halton, `2` Owen-scrambled Sobol |
|
|
423
429
|
| `fireflyThreshold` | `number` | 3.0 | Firefly clamping threshold |
|
|
430
|
+
| `shadowTerminatorOffset` | `number` | 0.1 | Cycles' Shadow Terminator → Geometry Offset: near the light's terminator on a smooth-shaded low-poly mesh, light and environment shadow rays start on the smooth surface the vertex normals describe, not the flat facet. Blender's default; `0` disables |
|
|
424
431
|
| `transmissiveBounces` | `number` | 5 | Max bounces for transmissive materials |
|
|
425
432
|
| `maxSubsurfaceSteps` | `number` | 8 | Max random-walk steps for subsurface scattering (raised to 64 by `configureForMode('production')`) |
|
|
426
433
|
| `enableAlphaShadows` | `boolean` | false | Alpha-tested shadow rays (enabled by `configureForMode('production')`) |
|
|
@@ -429,7 +436,8 @@ Key settings:
|
|
|
429
436
|
| `aperture` | `number` | 5.6 | DOF aperture (f-stop) |
|
|
430
437
|
| `focalLength` | `number` | 50 | DOF focal length (mm) |
|
|
431
438
|
| `transparentBackground` | `boolean` | false | Transparent canvas background |
|
|
432
|
-
| `interactionModeEnabled` | `boolean` | true |
|
|
439
|
+
| `interactionModeEnabled` | `boolean` | true | Render at lower resolution while the camera moves, keeping the full bounce budget ("Fast Navigation" in the app) |
|
|
440
|
+
| `interactionRenderScale` | `number` | 0.5 | Per-axis render scale while the camera moves (0.5 = a quarter of the pixels); `1` turns the drop off. Ignored while OIDN is the live denoiser |
|
|
433
441
|
| `renderMode` | `number` | 0 | Internal preview(0)/production(1) flag driving accumulation & ASVGF behavior — normally set via `configureForMode()`, not written directly |
|
|
434
442
|
| `visMode` | `number` | 0 | Debug visualization mode (0 = off) |
|
|
435
443
|
| `environmentMode` | `string` | 'hdri' | Sky mode: `'hdri'` \| `'procedural'` \| `'gradient'` \| `'color'` — not routed through `engine.settings`; use `engine.environmentManager.setMode()` instead |
|
|
@@ -445,7 +453,7 @@ Key settings:
|
|
|
445
453
|
| `pixelFreezeThreshold` | `number` | 0.02 | Relative-error threshold for a pixel to become a freeze candidate |
|
|
446
454
|
| `pixelFreezeStability` | `number` | 8 | Consecutive candidate frames required before a pixel freezes |
|
|
447
455
|
|
|
448
|
-
See `ENGINE_DEFAULTS` for the full list with default values.
|
|
456
|
+
See `ENGINE_DEFAULTS` for the full list with default values. The default look is AgX (`toneMapping: 6`) at neutral saturation; tone mapping is chosen through [Colour Management](#colour-management) (`engine.color.setActiveView( id )`), not `settings`.
|
|
449
457
|
|
|
450
458
|
#### Rendering Modes
|
|
451
459
|
|
|
@@ -509,11 +517,7 @@ engine.lightManager.sync() // Re-upload light data to GPU
|
|
|
509
517
|
engine.lightManager.showHelpers(true) // Toggle visual helpers
|
|
510
518
|
```
|
|
511
519
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
The **Lights panel edits Blender-style Power** — watts for point, spot and area, W/m² for the Sun — which is a view of that, converted by `lightPower()`/`setLightPower()` and nowhere else; `LightSerializer` converts the other way when it fills the GPU buffer. Dividing power by area only means something in metres, so the engine assumes **one world unit is one metre**; scenes authored in cm or mm must carry that scale in their node transforms, as glTF exporters do.
|
|
515
|
-
|
|
516
|
-
glTF punctual lights are photometric (candela, lux) and are divided by 683 lm/W on import, exactly as Blender's own glTF importer does. glTF `RectAreaLightPlaceholder` nodes author `intensity` as three.js radiance, which is already the stored quantity, so it is used verbatim. The record's own `power` field is ignored: it is written from the light's unscaled dimensions and disagrees with the world area whenever an ancestor scale is non-uniform.
|
|
520
|
+
Light `intensity` follows Blender: radiant power in watts for point, spot and area lights, irradiance in W/m² for directional. Dividing power by area only means something in metres, so the engine assumes **one world unit is one metre**; scenes authored in cm or mm must carry that scale in their node transforms, as glTF exporters do. glTF `RectAreaLightPlaceholder` nodes author `intensity` as three.js radiance (their `power` field is `intensity · width · height · π`); the importer converts it to power through the light's world area so the authored radiance is reproduced exactly, then applies the profile's `areaLightIntensityScale`.
|
|
517
521
|
|
|
518
522
|
### engine.animationManager
|
|
519
523
|
|
|
@@ -556,8 +560,43 @@ engine.updateAllMeshVisibility() // re-sync after manual object
|
|
|
556
560
|
|
|
557
561
|
// Read access to the active scene (returns the mesh-bearing scene)
|
|
558
562
|
engine.getScene()
|
|
563
|
+
|
|
564
|
+
// Where a packed value came from: 'material' | 'mapped' | 'default' | 'host'
|
|
565
|
+
engine.getMaterialPropertySource(index, 'ior')
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
A property a three.js material lacks falls back to `MATERIAL_DEFAULTS` (exported) — MeshPhysicalMaterial's own values, so a glTF metallic material gets IOR 1.5, not a guess derived from its metalness. Weights and roughnesses (metalness, roughness, transmission, opacity, clearcoat, sheen, iridescence, …) are clamped to [0, 1] on upload and on `setMaterialProperty`.
|
|
569
|
+
|
|
570
|
+
### Colour Management
|
|
571
|
+
|
|
572
|
+
`engine.color` is an OpenColorIO pipeline: what textures and lights mean, what the render happens in, and what it is shown and saved as. **It is inert until a config is loaded** — the render stays linear Rec.709 and the view transforms are three.js's own seven, so a host that never loads one sees no change. The host supplies the runtime (`ocioRuntimeFactory` or `ocioRuntimeUrl` in [`configureAssets`](#configuring-assets-cdn-urls--cache-namespace)).
|
|
573
|
+
|
|
574
|
+
```js
|
|
575
|
+
configureAssets({ ocioRuntimeFactory: () => import('@bb-studio/ocio') });
|
|
576
|
+
|
|
577
|
+
await engine.loadColorConfig({ builtin: 'ocio://cg-config-v4.0.0_aces-v2.0_ocio-v2.5' }); // a runtime built-in
|
|
578
|
+
await engine.loadColorConfig({ files, configPath: 'config.ocio', id: 'studio' }); // or a folder: [{ relativePath, data }]
|
|
579
|
+
|
|
580
|
+
engine.color.setView({ display: 'sRGB - Display', view: 'ACES 2.0 - SDR 100 nits (Rec.709)', look: null });
|
|
581
|
+
engine.color.setLook(look); // a look from status().config.looks, on the active view
|
|
582
|
+
engine.color.setActiveView(id); // any registered view, OCIO or built-in (three.js constant)
|
|
583
|
+
engine.color.setContext({ SHOT: '010' }); // $SHOT in the config resolves to this
|
|
584
|
+
engine.color.status(); // config, working space, active view, registered views
|
|
585
|
+
|
|
586
|
+
engine.color.setWorkingSpace('ACEScg'); // render in the config's space…
|
|
587
|
+
await engine.applyColorWorkingSpace(); // …which rebuilds textures, materials and the environment
|
|
588
|
+
|
|
589
|
+
await engine.setTextureColorSpace(texture, 'srgb'); // null (auto), 'srgb', 'linear' or a config space
|
|
590
|
+
const { data } = await engine.renderToBuffer({ colorSpace: 'ACES2065-1', source: 'display' }); // float delivery buffer
|
|
591
|
+
await engine.unloadColorConfig();
|
|
559
592
|
```
|
|
560
593
|
|
|
594
|
+
- **Load and unload through `engine.loadColorConfig()` / `unloadColorConfig()`** once a scene exists: they undo an adopted working space while the config that converted the environment is still loaded.
|
|
595
|
+
- A view is baked to a log2 shaper and a 65³ table, interpolated tetrahedrally; the same table drives the canvas, the GPU and CPU readbacks and the menu (`listViewTransforms()`, `onRegistryChange()`). An OCIO view returns display-encoded colour, so the engine switches the output pass to linear while one is active.
|
|
596
|
+
- **Baked views.** `await engine.color.saveBakedView(id)` writes a view's table to a file (157 KB gzip for 65³), and `await engine.color.loadBakedView(bytes, { expect })` registers it with no runtime and no config — show the look on the first frame, load the config later. When that config loads, a baked view whose files match the fingerprint it was baked from is kept as is: no rebake, no new id, no restart.
|
|
597
|
+
- `renderToBuffer({ colorSpace })` takes `'srgb'` (display bytes through the active view), `'linear'` (the working-space accumulation) or a config colour space; `source: 'display'` reads what the viewport shows, denoised, instead of the raw accumulation.
|
|
598
|
+
- Degradations (a view that cannot bake, a display the canvas cannot show) are recorded as warnings in the [degradation contract](#degradation-contract).
|
|
599
|
+
|
|
561
600
|
### engine.environmentManager
|
|
562
601
|
|
|
563
602
|
Environment maps, sky modes, and procedural generation.
|
|
@@ -958,6 +997,18 @@ import {
|
|
|
958
997
|
PRODUCTION_RENDER_CONFIG,
|
|
959
998
|
INTERACTIVE_RENDER_CONFIG,
|
|
960
999
|
MAX_RESERVABLE_RENDER_SIZE,
|
|
1000
|
+
RENDER_PROFILES,
|
|
1001
|
+
MATERIAL_DEFAULTS,
|
|
1002
|
+
} from 'rayzee';
|
|
1003
|
+
|
|
1004
|
+
// Colour management — engine.color is the instance a host normally uses; these build UI against
|
|
1005
|
+
// it, or reach the view-transform registry without an app
|
|
1006
|
+
import {
|
|
1007
|
+
ColorManagement, getActiveColorManagement, isColorManaged, DEFAULT_WORKING_SPACE,
|
|
1008
|
+
listViewTransforms, getViewTransform, addViewTransform, removeViewTransform, onRegistryChange,
|
|
1009
|
+
buildOcioView, addOcioView, addAllOcioViews,
|
|
1010
|
+
convertColor, convertPixelsF32, extractMatrix, hasColorSpace,
|
|
1011
|
+
displayCanvasFit,
|
|
961
1012
|
} from 'rayzee';
|
|
962
1013
|
|
|
963
1014
|
// Leveled/namespaced logging, shared with the workers
|
|
@@ -1021,6 +1072,7 @@ import { setBindingAudit, getBindingAuditFindings, clearBindingAuditFindings } f
|
|
|
1021
1072
|
|---|---|---|
|
|
1022
1073
|
| `oidn-web` | Intel Open Image Denoise for high-quality final renders | Yes — `npm install oidn-web` (**>=0.4.0**) |
|
|
1023
1074
|
| `onnxruntime-web` | AI-powered upscaling | No — loaded from CDN at runtime |
|
|
1075
|
+
| `@bb-studio/ocio` | OpenColorIO runtime for [Colour Management](#colour-management) (~6 MB WebAssembly) | Only to load colour configs — `npm install @bb-studio/ocio`, then pass it as `ocioRuntimeFactory` |
|
|
1024
1076
|
|
|
1025
1077
|
> **Note:** `onnxruntime-web` is also listed in `package.json` under `optionalDependencies` for bundler compatibility, but the engine's own runtime path always fetches it from a CDN (see `ortRuntimeUrl` / `ortWasmPaths` in [Configuring Assets](#configuring-assets-cdn-urls--cache-namespace)) rather than importing the installed package — installing it locally has no effect unless you also override those URLs to point at your own copy.
|
|
1026
1078
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
|
|
2
|
-
import {
|
|
2
|
+
import { S as t, t as n, y as r } from "./ToneMapGPU-BzcLheoR.js";
|
|
3
3
|
//#region src/dlss/DLSSNeural.js
|
|
4
4
|
var i = /* @__PURE__ */ e({
|
|
5
5
|
DLSSNeural: () => m,
|
|
@@ -39,7 +39,7 @@ var s = t("dlss"), c = 2048 * 2048, l = Object.freeze({
|
|
|
39
39
|
}), u = null;
|
|
40
40
|
function d() {
|
|
41
41
|
if (u) return u;
|
|
42
|
-
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } =
|
|
42
|
+
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } = r();
|
|
43
43
|
return globalThis.__DLSS5_ASSET_BASE__ = t, u = new Promise((t, n) => {
|
|
44
44
|
if (globalThis.DLSSRuntime?.getSrNrChain) return t(globalThis.DLSSRuntime.getSrNrChain());
|
|
45
45
|
let r = document.createElement("script");
|
|
@@ -139,15 +139,15 @@ var f = "\n@group(0) @binding(0) var src: texture_2d<f32>;\n@group(0) @binding(1
|
|
|
139
139
|
};
|
|
140
140
|
}
|
|
141
141
|
async readOutputToned(e) {
|
|
142
|
-
let { validWidth: t, validHeight:
|
|
143
|
-
return await this._packHDR(t,
|
|
142
|
+
let { validWidth: t, validHeight: r } = this.chain.pipeline.geometry;
|
|
143
|
+
return await this._packHDR(t, r), this._toneMapper ??= new n(this.device, "rayzee:dlss-nr-tonemap"), this._toneMapper.ensureSize(t, r), {
|
|
144
144
|
rgba8: await this._toneMapper.toRGBA8(this._hdrStorage, {
|
|
145
145
|
exposure: e.exposure ?? 1,
|
|
146
146
|
toneMapping: e.toneMapping ?? 0,
|
|
147
147
|
saturation: e.saturation ?? 1
|
|
148
148
|
}),
|
|
149
149
|
width: t,
|
|
150
|
-
height:
|
|
150
|
+
height: r
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
async readOutput() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
|
|
2
|
-
import {
|
|
2
|
+
import { S as t, t as n, y as r } from "./ToneMapGPU-BzcLheoR.js";
|
|
3
3
|
//#region src/EngineEvents.js
|
|
4
4
|
var i = {
|
|
5
5
|
RENDER_COMPLETE: "engine:renderComplete",
|
|
@@ -45,7 +45,7 @@ var i = {
|
|
|
45
45
|
}), o = 2, s = t("dlss"), c = 2048, l = null;
|
|
46
46
|
function u() {
|
|
47
47
|
if (l) return l;
|
|
48
|
-
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } =
|
|
48
|
+
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } = r();
|
|
49
49
|
return globalThis.__DLSS5_ASSET_BASE__ = t, l = new Promise((t, n) => {
|
|
50
50
|
if (globalThis.DLSSRuntime?.getNativeSR) return t(globalThis.DLSSRuntime.getNativeSR());
|
|
51
51
|
let r = document.createElement("script");
|
|
@@ -174,11 +174,11 @@ var g = class e {
|
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
176
|
async upscaleToRGBA8(e, t = {}) {
|
|
177
|
-
let { result:
|
|
178
|
-
this._toneMapper ??= new
|
|
177
|
+
let { result: r, ms: i } = await this._run(e), { outputWidth: a, outputHeight: o } = this.geometry;
|
|
178
|
+
this._toneMapper ??= new n(this.sr.device, "rayzee:dlss-sr-tonemap"), this._toneMapper.ensureSize(a, o);
|
|
179
179
|
let s = performance.now();
|
|
180
180
|
return {
|
|
181
|
-
rgba8: await this._toneMapper.toRGBA8(
|
|
181
|
+
rgba8: await this._toneMapper.toRGBA8(r.hdr.buffer ?? r.hdr, {
|
|
182
182
|
exposure: t.exposure ?? 1,
|
|
183
183
|
toneMapping: t.toneMapping ?? 0,
|
|
184
184
|
saturation: t.saturation ?? 1,
|