reze-engine 0.12.1 → 0.12.3
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 +102 -61
- package/dist/engine.d.ts +9 -4
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +62 -18
- package/dist/shaders/body.d.ts +1 -1
- package/dist/shaders/body.d.ts.map +1 -1
- package/dist/shaders/body.js +7 -28
- package/dist/shaders/cloth_rough.d.ts +1 -1
- package/dist/shaders/cloth_rough.d.ts.map +1 -1
- package/dist/shaders/cloth_rough.js +4 -16
- package/dist/shaders/cloth_smooth.d.ts +1 -1
- package/dist/shaders/cloth_smooth.d.ts.map +1 -1
- package/dist/shaders/cloth_smooth.js +5 -17
- package/dist/shaders/default.d.ts +1 -1
- package/dist/shaders/default.d.ts.map +1 -1
- package/dist/shaders/eye.d.ts +1 -1
- package/dist/shaders/eye.d.ts.map +1 -1
- package/dist/shaders/face.d.ts +1 -1
- package/dist/shaders/face.d.ts.map +1 -1
- package/dist/shaders/face.js +21 -57
- package/dist/shaders/hair.d.ts +1 -1
- package/dist/shaders/hair.d.ts.map +1 -1
- package/dist/shaders/hair.js +7 -27
- package/dist/shaders/materials/body.d.ts +1 -1
- package/dist/shaders/materials/body.d.ts.map +1 -1
- package/dist/shaders/materials/body.js +86 -197
- package/dist/shaders/materials/cloth_rough.d.ts +1 -1
- package/dist/shaders/materials/cloth_rough.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_rough.js +11 -122
- package/dist/shaders/materials/cloth_smooth.d.ts +1 -1
- package/dist/shaders/materials/cloth_smooth.d.ts.map +1 -1
- package/dist/shaders/materials/cloth_smooth.js +59 -172
- package/dist/shaders/materials/common.d.ts +6 -0
- package/dist/shaders/materials/common.d.ts.map +1 -0
- package/dist/shaders/materials/common.js +160 -0
- package/dist/shaders/materials/default.d.ts +1 -1
- package/dist/shaders/materials/default.d.ts.map +1 -1
- package/dist/shaders/materials/default.js +13 -146
- package/dist/shaders/materials/eye.d.ts +1 -1
- package/dist/shaders/materials/eye.d.ts.map +1 -1
- package/dist/shaders/materials/eye.js +13 -118
- package/dist/shaders/materials/face.d.ts +1 -1
- package/dist/shaders/materials/face.d.ts.map +1 -1
- package/dist/shaders/materials/face.js +85 -197
- package/dist/shaders/materials/hair.d.ts +1 -1
- package/dist/shaders/materials/hair.d.ts.map +1 -1
- package/dist/shaders/materials/hair.js +78 -183
- package/dist/shaders/materials/metal.d.ts +1 -1
- package/dist/shaders/materials/metal.d.ts.map +1 -1
- package/dist/shaders/materials/metal.js +16 -122
- package/dist/shaders/materials/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +77 -0
- package/dist/shaders/materials/stockings.d.ts +1 -1
- package/dist/shaders/materials/stockings.d.ts.map +1 -1
- package/dist/shaders/materials/stockings.js +26 -152
- package/dist/shaders/metal.d.ts +1 -1
- package/dist/shaders/metal.d.ts.map +1 -1
- package/dist/shaders/metal.js +4 -17
- package/dist/shaders/nodes.d.ts +1 -1
- package/dist/shaders/nodes.d.ts.map +1 -1
- package/dist/shaders/nodes.js +0 -9
- package/dist/shaders/passes/bloom.d.ts +1 -1
- package/dist/shaders/passes/bloom.d.ts.map +1 -1
- package/dist/shaders/passes/bloom.js +7 -4
- package/dist/shaders/passes/composite.d.ts +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +11 -4
- package/dist/shaders/passes/ground.d.ts +1 -1
- package/dist/shaders/passes/ground.d.ts.map +1 -1
- package/dist/shaders/passes/ground.js +6 -2
- package/dist/shaders/passes/outline.d.ts +1 -1
- package/dist/shaders/passes/outline.d.ts.map +1 -1
- package/dist/shaders/passes/outline.js +2 -2
- package/dist/shaders/stockings.d.ts +1 -1
- package/dist/shaders/stockings.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine.ts +60 -18
- package/src/shaders/materials/body.ts +90 -201
- package/src/shaders/materials/cloth_rough.ts +11 -122
- package/src/shaders/materials/cloth_smooth.ts +63 -176
- package/src/shaders/materials/common.ts +171 -0
- package/src/shaders/materials/default.ts +13 -146
- package/src/shaders/materials/eye.ts +13 -118
- package/src/shaders/materials/face.ts +89 -201
- package/src/shaders/materials/hair.ts +82 -187
- package/src/shaders/materials/metal.ts +16 -122
- package/src/shaders/materials/nodes.ts +77 -0
- package/src/shaders/materials/stockings.ts +27 -153
- package/src/shaders/passes/bloom.ts +7 -4
- package/src/shaders/passes/composite.ts +11 -4
- package/src/shaders/passes/ground.ts +6 -2
- package/src/shaders/passes/outline.ts +2 -2
- package/dist/bezier-interpolate.d.ts +0 -15
- package/dist/bezier-interpolate.d.ts.map +0 -1
- package/dist/bezier-interpolate.js +0 -40
- package/dist/engine_ts.d.ts +0 -143
- package/dist/engine_ts.d.ts.map +0 -1
- package/dist/engine_ts.js +0 -1575
- package/dist/ik.d.ts +0 -32
- package/dist/ik.d.ts.map +0 -1
- package/dist/ik.js +0 -337
- package/dist/player.d.ts +0 -64
- package/dist/player.d.ts.map +0 -1
- package/dist/player.js +0 -220
- package/dist/pool-scene.d.ts +0 -52
- package/dist/pool-scene.d.ts.map +0 -1
- package/dist/pool-scene.js +0 -1122
- package/dist/pool.d.ts +0 -38
- package/dist/pool.d.ts.map +0 -1
- package/dist/pool.js +0 -422
- package/dist/rzm-converter.d.ts +0 -12
- package/dist/rzm-converter.d.ts.map +0 -1
- package/dist/rzm-converter.js +0 -40
- package/dist/rzm-loader.d.ts +0 -24
- package/dist/rzm-loader.d.ts.map +0 -1
- package/dist/rzm-loader.js +0 -488
- package/dist/rzm-writer.d.ts +0 -27
- package/dist/rzm-writer.d.ts.map +0 -1
- package/dist/rzm-writer.js +0 -701
package/README.md
CHANGED
|
@@ -14,9 +14,10 @@ npm install reze-engine
|
|
|
14
14
|
|
|
15
15
|
- **Anime/MMD-style hybrid renderer** — toon-ramp NPR diffuse mixed with PBR GGX specular (multi-scatter + LTC energy compensation)
|
|
16
16
|
- **Per-material presets** — `face` / `hair` / `body` / `eye` / `stockings` / `metal` / `cloth_smooth` / `cloth_rough` / `default`, assigned by material name
|
|
17
|
-
- **HDR pipeline** with bloom mip pyramid, Filmic tone mapping, 4× MSAA
|
|
17
|
+
- **HDR pipeline** with bloom mip pyramid, Filmic tone mapping, 4× MSAA, tile-memory-friendly on Apple Silicon
|
|
18
18
|
- **Alpha-hashed transparency** (Wyman & McGuire 2017) for self-overlapping transparent meshes like stockings
|
|
19
19
|
- **Screen-space outlines** on opaque + transparent materials
|
|
20
|
+
- **See-through hair over eyes** — stencil-gated MMD post-alpha-eye so eyes read at 50% through hair silhouettes
|
|
20
21
|
- **VMD animation** with IK solver and Bullet physics
|
|
21
22
|
- **Orbit camera** with bone-follow mode
|
|
22
23
|
- **GPU picking** (double-click/tap)
|
|
@@ -26,7 +27,7 @@ npm install reze-engine
|
|
|
26
27
|
## Usage
|
|
27
28
|
|
|
28
29
|
```javascript
|
|
29
|
-
import { Engine, Vec3 } from "reze-engine"
|
|
30
|
+
import { Engine, Vec3 } from "reze-engine"
|
|
30
31
|
|
|
31
32
|
const engine = new Engine(canvas, {
|
|
32
33
|
world: { color: new Vec3(0.4, 0.49, 0.65), strength: 1.0 },
|
|
@@ -36,16 +37,16 @@ const engine = new Engine(canvas, {
|
|
|
36
37
|
direction: new Vec3(0, -0.5, 1),
|
|
37
38
|
},
|
|
38
39
|
camera: { distance: 31.5, target: new Vec3(0, 11.5, 0) }, // MMD units (1 unit = 8 cm)
|
|
39
|
-
})
|
|
40
|
-
await engine.init()
|
|
40
|
+
})
|
|
41
|
+
await engine.init()
|
|
41
42
|
|
|
42
43
|
engine.setBloomOptions({
|
|
43
44
|
color: new Vec3(0.9, 0.1, 0.8),
|
|
44
45
|
intensity: 0.05,
|
|
45
46
|
threshold: 0.5,
|
|
46
|
-
})
|
|
47
|
+
})
|
|
47
48
|
|
|
48
|
-
const model = await engine.loadModel("hero", "/models/hero/hero.pmx")
|
|
49
|
+
const model = await engine.loadModel("hero", "/models/hero/hero.pmx")
|
|
49
50
|
|
|
50
51
|
// Map PMX material names to NPR presets (unlisted names fall back to `default`).
|
|
51
52
|
engine.setMaterialPresets("hero", {
|
|
@@ -57,15 +58,15 @@ engine.setMaterialPresets("hero", {
|
|
|
57
58
|
cloth_rough: ["jacket", "pants"],
|
|
58
59
|
stockings: ["stockings"],
|
|
59
60
|
metal: ["metal01", "earring"],
|
|
60
|
-
})
|
|
61
|
+
})
|
|
61
62
|
|
|
62
|
-
await model.loadVmd("idle", "/animations/idle.vmd")
|
|
63
|
-
model.show("idle")
|
|
64
|
-
model.play()
|
|
63
|
+
await model.loadVmd("idle", "/animations/idle.vmd")
|
|
64
|
+
model.show("idle")
|
|
65
|
+
model.play()
|
|
65
66
|
|
|
66
|
-
engine.setCameraFollow(model, "センター", new Vec3(0, 3.5, 0))
|
|
67
|
-
engine.addGround({ width: 160, height: 160 })
|
|
68
|
-
engine.runRenderLoop()
|
|
67
|
+
engine.setCameraFollow(model, "センター", new Vec3(0, 3.5, 0))
|
|
68
|
+
engine.addGround({ width: 160, height: 160 })
|
|
69
|
+
engine.runRenderLoop()
|
|
69
70
|
```
|
|
70
71
|
|
|
71
72
|
## API
|
|
@@ -114,30 +115,26 @@ Use a hidden `<input type="file" webkitdirectory multiple>` (or drag/drop) and p
|
|
|
114
115
|
2. **`engine.loadModel(name, { files, pmxFile })`** — `pmxFile` selects which `.pmx` when the folder contains several.
|
|
115
116
|
|
|
116
117
|
```javascript
|
|
117
|
-
import {
|
|
118
|
-
Engine,
|
|
119
|
-
parsePmxFolderInput,
|
|
120
|
-
pmxFileAtRelativePath,
|
|
121
|
-
} from "reze-engine";
|
|
118
|
+
import { Engine, parsePmxFolderInput, pmxFileAtRelativePath } from "reze-engine"
|
|
122
119
|
|
|
123
120
|
// In <input onChange>:
|
|
124
|
-
const picked = parsePmxFolderInput(e.target.files)
|
|
125
|
-
e.target.value = ""
|
|
121
|
+
const picked = parsePmxFolderInput(e.target.files)
|
|
122
|
+
e.target.value = ""
|
|
126
123
|
|
|
127
124
|
if (picked.status === "single") {
|
|
128
125
|
const model = await engine.loadModel("myModel", {
|
|
129
126
|
files: picked.files,
|
|
130
127
|
pmxFile: picked.pmxFile,
|
|
131
|
-
})
|
|
128
|
+
})
|
|
132
129
|
}
|
|
133
130
|
|
|
134
131
|
if (picked.status === "multiple") {
|
|
135
132
|
// Let the user choose `chosenPath` from picked.pmxRelativePaths, then:
|
|
136
|
-
const pmxFile = pmxFileAtRelativePath(picked.files, chosenPath)
|
|
133
|
+
const pmxFile = pmxFileAtRelativePath(picked.files, chosenPath)
|
|
137
134
|
const model = await engine.loadModel("myModel", {
|
|
138
135
|
files: picked.files,
|
|
139
136
|
pmxFile,
|
|
140
|
-
})
|
|
137
|
+
})
|
|
141
138
|
}
|
|
142
139
|
```
|
|
143
140
|
|
|
@@ -176,12 +173,12 @@ model.getBoneWorldPosition(name)
|
|
|
176
173
|
`model.exportVmd(name)` serialises a loaded clip back to the VMD binary format and returns an `ArrayBuffer`. Bone and morph names are Shift-JIS encoded for compatibility with standard MMD tools.
|
|
177
174
|
|
|
178
175
|
```javascript
|
|
179
|
-
const buffer = model.exportVmd("idle")
|
|
180
|
-
const blob = new Blob([buffer], { type: "application/octet-stream" })
|
|
181
|
-
const link = document.createElement("a")
|
|
182
|
-
link.href = URL.createObjectURL(blob)
|
|
183
|
-
link.download = "idle.vmd"
|
|
184
|
-
link.click()
|
|
176
|
+
const buffer = model.exportVmd("idle")
|
|
177
|
+
const blob = new Blob([buffer], { type: "application/octet-stream" })
|
|
178
|
+
const link = document.createElement("a")
|
|
179
|
+
link.href = URL.createObjectURL(blob)
|
|
180
|
+
link.download = "idle.vmd"
|
|
181
|
+
link.click()
|
|
185
182
|
```
|
|
186
183
|
|
|
187
184
|
#### Playback
|
|
@@ -227,55 +224,99 @@ The shadow map is cast from `sun.direction` — same vector the shader lights wi
|
|
|
227
224
|
|
|
228
225
|
## Rendering
|
|
229
226
|
|
|
230
|
-
|
|
227
|
+
Each surface combines an NPR stack with a Principled-style BSDF, mixed per material — so anime characters keep their flat illustrated look while highlights and reflections stay grounded. Every per-material shader is ~40–120 lines of distinctive code standing on a small set of shared WGSL primitives (`engine/src/shaders/materials/`).
|
|
228
|
+
|
|
229
|
+
### Anatomy of a material shader
|
|
230
|
+
|
|
231
|
+
Every material's fragment shader is the same 7-stage pipeline. The order is fixed; the content is per-material:
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
(A) Fragment setup → n, v, l, sun, amb, shadow ← shared
|
|
235
|
+
(B) Texture + alpha → tex_rgb, discard ← shared shape
|
|
236
|
+
(C) NPR stack → toon + rim + warm + … ← UNIQUE per material
|
|
237
|
+
(D) Optional bump → noise → bump_lh ← 3 presets
|
|
238
|
+
(E) Principled BSDF → eval_principled(...) ← shared helper
|
|
239
|
+
(F) NPR ↔ PBR mix → mix(npr, principled, fac) ← per-material fac
|
|
240
|
+
(G) FSOut → color + bloom mask ← shared
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The simplest material (`default`) uses only A/B/E/G — no NPR stack at all:
|
|
244
|
+
|
|
245
|
+
```wgsl
|
|
246
|
+
let color = eval_principled(
|
|
247
|
+
PrincipledIn(albedo, 0.0, 0.5, 0.5, 1e30, 0.0, 0.0), // metallic, spec, rough, clamp, sheen, sheen_tint
|
|
248
|
+
n, l, v, sun, amb, shadow
|
|
249
|
+
);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
NPR presets add stage C (and sometimes D) on top, and stage F chooses how NPR-leaning the surface is.
|
|
253
|
+
|
|
254
|
+
### Shared WGSL foundations
|
|
255
|
+
|
|
256
|
+
- **`nodes.ts`** — WGSL mirrors of the Blender shader nodes the presets use: `hue_sat`, `bright_contrast`, `ramp_constant/linear/cardinal`, `mix_overlay/lighten/linear_light`, `fresnel`, `layer_weight_fresnel/facing`, `tex_noise`, `tex_voronoi`, `mapping_point`, `bump_lh`, `normal_map`. Plus a combined DFG + LTC LUT, `eval_principled(PrincipledIn, N, L, V, sun, amb, shadow)`, and `principled_sheen`.
|
|
257
|
+
- **`common.ts`** — Uniform structs, bind-group layout (same for every material pipeline), PCF shadow sampler, skinning vertex shader, shared `FSOut`.
|
|
258
|
+
- **Per-material files** — constants + NPR stack + optional bump + `eval_principled` call + final mix.
|
|
231
259
|
|
|
232
260
|
### PBR specular core
|
|
233
261
|
|
|
262
|
+
Inside `eval_principled`:
|
|
263
|
+
|
|
234
264
|
- GGX microfacet specular with Schlick Fresnel and Walter–Smith G1
|
|
235
|
-
- **Multi-scatter compensation** (Fdez-Agüera 2019
|
|
236
|
-
- **Split-sum DFG LUT** (Karis 2013)
|
|
237
|
-
- **LTC direct-spec scale** (Heitz 2016
|
|
238
|
-
- Sheen coarse
|
|
265
|
+
- **Multi-scatter compensation** (Fdez-Agüera 2019) — restores energy at high roughness so metals don't darken
|
|
266
|
+
- **Split-sum DFG LUT** (Karis 2013) — drives indirect specular
|
|
267
|
+
- **LTC direct-spec scale** (Heitz 2016) — keeps analytic-light specular in the same energy budget as image-based lighting
|
|
268
|
+
- **Sheen coarse curve** gated by the `sheen` field on `PrincipledIn`
|
|
239
269
|
|
|
240
|
-
###
|
|
270
|
+
### NPR toolbox
|
|
241
271
|
|
|
242
|
-
Every preset is built
|
|
272
|
+
Every preset's stage C is built from these primitives:
|
|
243
273
|
|
|
244
|
-
- **Toon ramps** — quantised NdotL through constant or
|
|
245
|
-
- **HSV remaps** — separate hue/sat/value tints for shadow vs lit zones,
|
|
246
|
-
- **Fresnel rim & layer-weight wrap** —
|
|
247
|
-
- **Procedural micro-detail** —
|
|
248
|
-
- **Selective emission** —
|
|
274
|
+
- **Toon ramps** — quantised NdotL through constant or `ramp_constant_edge_aa` (fwidth-based step anti-alias) for cel-shaded shadow terminators
|
|
275
|
+
- **HSV remaps** — separate hue/sat/value tints for shadow vs lit zones, layered with mix-overlay against the lit texture for warm-shadow / cool-light shifts
|
|
276
|
+
- **Fresnel rim & layer-weight wrap** — `fresnel × layer_weight_facing` (or two stacked fresnels) feeds a MixShader against an emissive backdrop for anime back-light
|
|
277
|
+
- **Procedural micro-detail** — 3-octave value noise (PCG hash, fully unrolled) drives bump-from-height for skin and fabric; 3D Voronoi in reflection-coord space drives metallic sparkle
|
|
278
|
+
- **Selective emission** — BT.601-luminance-gated boosts (eye iris, face highlights, stockings pattern) that survive into bloom
|
|
249
279
|
|
|
250
|
-
###
|
|
280
|
+
### Per-material NPR stacks
|
|
251
281
|
|
|
252
|
-
Each PMX material is
|
|
282
|
+
Each PMX material is assigned to one of these shaders. The NPR stack column is what's actually in stage C of that file; the Principled column is what gets passed to `eval_principled`.
|
|
253
283
|
|
|
254
|
-
| Preset |
|
|
255
|
-
| -------------- |
|
|
256
|
-
| `
|
|
257
|
-
| `
|
|
258
|
-
| `
|
|
259
|
-
| `
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
262
|
-
| `cloth_smooth`
|
|
263
|
-
| `
|
|
264
|
-
| `
|
|
284
|
+
| Preset | NPR stack (stage C) | Principled (stage E) |
|
|
285
|
+
| -------------- | ----------------------------------------------------------- | ------------------------------------------------------------- |
|
|
286
|
+
| `default` | — | metallic=0, spec=0.5, rough=0.5 |
|
|
287
|
+
| `eye` | — (emission = albedo × 1.5 added post-eval) | same as default |
|
|
288
|
+
| `face` | toon + warm rim + dual-fresnel rim + BT.601 bright-tex gate | spec=0.5, rough=0.3, noise bump, spec clamp=10 |
|
|
289
|
+
| `body` | toon + warm rim + fresnel rim + facing rim | spec=0.5, rough=0.3, noise bump, spec clamp=10 |
|
|
290
|
+
| `hair` | toon + fresnel rim + bevel (n.y) + bright-tex gate | spec=1.0, rough=0.3, mixed at 20% PBR |
|
|
291
|
+
| `cloth_smooth` | toon + bevel + mix-overlay emission (×18) | spec=0.8, rough=0.5 |
|
|
292
|
+
| `cloth_rough` | same NPR as `cloth_smooth` | spec=0.8, rough=0.82, live noise bump, spec clamp=10 |
|
|
293
|
+
| `metal` | toon + mix-overlay emission (×8) | metallic=1, voronoi-driven base (reflection-coord), rough=0.3 |
|
|
294
|
+
| `stockings` | gradient × facing mask + HSV-boosted emission (×5) | metallic=0.1, spec=1, rough=0.5, **sheen=0.7**, hashed alpha |
|
|
295
|
+
|
|
296
|
+
Assign presets per-model with `engine.setMaterialPresets(name, map)` (see the [Usage](#usage) example). Material names not listed fall through to `default`.
|
|
265
297
|
|
|
266
298
|
### Shadows, post, output
|
|
267
299
|
|
|
268
|
-
- Directional shadow map (2048², depth32float,
|
|
269
|
-
- HDR
|
|
270
|
-
- Bloom via threshold + downsample/upsample mip pyramid, gated by
|
|
271
|
-
- Filmic tone mapping (LUT
|
|
300
|
+
- Directional shadow map (2048², depth32float, PCF, normal + depth bias)
|
|
301
|
+
- HDR main pass with 4× MSAA. Color is `rg11b10ufloat` paired with an `rg8unorm` aux MRT carrying bloom mask (`.r`) and accumulated alpha (`.g`). The combined footprint fits Apple Silicon TBDR tile memory, so the 4× MSAA buffer resolves in-tile rather than spilling to system memory every frame. Falls back to `rgba16float` when the device does not expose `rg11b10ufloat-renderable`.
|
|
302
|
+
- Bloom via threshold + downsample/upsample mip pyramid, gated by the aux bloom-mask channel
|
|
303
|
+
- Filmic tone mapping (LUT extracted from Blender 3.6 OCIO "Filmic / Medium High Contrast")
|
|
272
304
|
- Screen-space outline pass (inverted-hull) on opaque and transparent materials
|
|
273
305
|
|
|
274
|
-
Assign presets per-model with `engine.setMaterialPresets(name, map)` (see the [Usage](#usage) example). Material names not listed fall through to the `default` Principled BSDF.
|
|
275
|
-
|
|
276
306
|
### Alpha-hashed transparency
|
|
277
307
|
|
|
278
|
-
`stockings` uses the Wyman & McGuire 2017 derivative-aware stochastic discard
|
|
308
|
+
`stockings` uses the Wyman & McGuire 2017 derivative-aware stochastic discard so self-overlapping transparent meshes (e.g. the front and back of a stocking wrapped around a leg) resolve cleanly under MSAA with opaque-style depth writes. The hash is derived from world-space position, so the dither pattern does not swim when the camera moves.
|
|
309
|
+
|
|
310
|
+
### See-through hair over eyes (MMD post-alpha-eye)
|
|
311
|
+
|
|
312
|
+
The classic MMD effect where hair strands covering the eye are rendered at 50% so the iris stays readable — implemented as a single extra pass driven by the stencil buffer, not a two-texture composite.
|
|
313
|
+
|
|
314
|
+
- **Eye pipeline** stamps `stencil = EYE_VALUE` on every fragment it writes, with `cullMode: "front"` and a small negative `depthBias` so only the back half of the eye mesh renders (the MMD trick that keeps eyes from leaking through the back of the head).
|
|
315
|
+
- **Main hair pipeline** stencil-tests `not-equal EYE_VALUE` and skips those fragments.
|
|
316
|
+
- **Hair-over-eyes pipeline** re-issues the hair draws with `IS_OVER_EYES = true`, stencil-tests `equal EYE_VALUE`, disables depth writes, and alpha blends at 50% — eye-stamped pixels end up `0.5·hair + 0.5·eye` in linear HDR before tonemap.
|
|
317
|
+
- **Outline pipeline** stencil-tests `not-equal EYE_VALUE` so edge color does not overwrite the see-through region.
|
|
318
|
+
|
|
319
|
+
Draw order within a model: non-eye/non-hair opaque → eye (stamp) → hair (skip stamp) → outlines (skip stamp) → hair-over-eyes (match stamp).
|
|
279
320
|
|
|
280
321
|
## Projects Using This Engine
|
|
281
322
|
|
package/dist/engine.d.ts
CHANGED
|
@@ -128,13 +128,18 @@ export declare class Engine {
|
|
|
128
128
|
private multisampleTexture;
|
|
129
129
|
private hdrResolveTexture;
|
|
130
130
|
private static readonly MULTISAMPLE_COUNT;
|
|
131
|
-
private
|
|
131
|
+
private hdrFormat;
|
|
132
132
|
/** Stencil value stamped by eye draws so hair can stencil-test against it and
|
|
133
133
|
* alpha-blend a second pass over eye silhouette pixels (see-through-hair effect). */
|
|
134
134
|
private static readonly STENCIL_EYE_VALUE;
|
|
135
|
-
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
135
|
+
/** Aux MRT alongside HDR color. Two channels:
|
|
136
|
+
* .r — bloom mask (1 = model geometry, 0 = ground; sampled by bloom blit to gate prefilter).
|
|
137
|
+
* .g — accumulated alpha (the channel that used to live in hdr.a before the HDR format
|
|
138
|
+
* switched to rg11b10ufloat, which has no alpha). Sampled by composite/bloom to
|
|
139
|
+
* un-premultiply color for tonemap and to produce the canvas-drawable alpha used by
|
|
140
|
+
* the premultiplied alphaMode compositor (so the page background still shows through
|
|
141
|
+
* cleared / edge-faded regions like before).
|
|
142
|
+
* rg8unorm at 4× MSAA is 8 bytes/texel — still fits Apple TBDR tile memory comfortably. */
|
|
138
143
|
private static readonly BLOOM_MASK_FORMAT;
|
|
139
144
|
private multisampleMaskTexture;
|
|
140
145
|
private maskResolveTexture;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine.js
CHANGED
|
@@ -65,6 +65,23 @@ export class Engine {
|
|
|
65
65
|
this.lightData = new Float32Array(64);
|
|
66
66
|
this.lightCount = 0;
|
|
67
67
|
this.resizeObserver = null;
|
|
68
|
+
// HDR intermediate format. rg11b10ufloat when the adapter exposes the
|
|
69
|
+
// `rg11b10ufloat-renderable` feature (Chrome + Safari on Apple Silicon both
|
|
70
|
+
// do), else fall back to rgba16float.
|
|
71
|
+
//
|
|
72
|
+
// Why it matters — Apple TBDR tile memory: rgba16float is 8 bytes/texel, so
|
|
73
|
+
// 4× MSAA is 32 bytes/texel and does not fit Apple Silicon's tile memory at
|
|
74
|
+
// useful tile sizes. The driver then stores the full MSAA buffer to system
|
|
75
|
+
// memory every frame and resolves from there — ~300 MB/frame of extra
|
|
76
|
+
// bandwidth at 1920×1200 DPR=2, which is the dominant frame-pacing hit on
|
|
77
|
+
// Safari (visibly: shrinking the window made Safari smooth; Chrome was
|
|
78
|
+
// always smooth because Dawn apparently amortizes it). rg11b10ufloat at
|
|
79
|
+
// 4 bytes/texel → 16 bytes/texel at 4× MSAA → fits tile memory like
|
|
80
|
+
// rgba8unorm does, resolves in-tile, no system-memory round-trip. No alpha
|
|
81
|
+
// channel (the HDR path never needed one — alpha blending reads src.a from
|
|
82
|
+
// the fragment shader and treats missing dst.a as 1, so the blend math is
|
|
83
|
+
// unchanged).
|
|
84
|
+
this.hdrFormat = "rgba16float";
|
|
68
85
|
// [exposure, invGamma, _, _, bloomTint.x, bloomTint.y, bloomTint.z, bloomIntensity]
|
|
69
86
|
this.compositeUniformData = new Float32Array(8);
|
|
70
87
|
this.bloomBlitUniformData = new Float32Array(4);
|
|
@@ -276,11 +293,19 @@ export class Engine {
|
|
|
276
293
|
// Step 1: Get WebGPU device and context
|
|
277
294
|
async init() {
|
|
278
295
|
const adapter = await navigator.gpu?.requestAdapter();
|
|
279
|
-
|
|
296
|
+
if (!adapter)
|
|
297
|
+
throw new Error("WebGPU is not supported in this browser.");
|
|
298
|
+
const wantFeature = "rg11b10ufloat-renderable";
|
|
299
|
+
const hasRg11b10 = adapter.features.has(wantFeature);
|
|
300
|
+
const device = await adapter.requestDevice({
|
|
301
|
+
requiredFeatures: hasRg11b10 ? [wantFeature] : [],
|
|
302
|
+
});
|
|
280
303
|
if (!device) {
|
|
281
304
|
throw new Error("WebGPU is not supported in this browser.");
|
|
282
305
|
}
|
|
283
306
|
this.device = device;
|
|
307
|
+
if (hasRg11b10)
|
|
308
|
+
this.hdrFormat = "rg11b10ufloat";
|
|
284
309
|
const context = this.canvas.getContext("webgpu");
|
|
285
310
|
if (!context) {
|
|
286
311
|
throw new Error("Failed to get WebGPU context.");
|
|
@@ -438,7 +463,7 @@ export class Engine {
|
|
|
438
463
|
// composite pass writes the swapchain. Tonemap moved to composite so bloom
|
|
439
464
|
// (added next) can run on linear HDR.
|
|
440
465
|
const standardBlend = {
|
|
441
|
-
format:
|
|
466
|
+
format: this.hdrFormat,
|
|
442
467
|
blend: {
|
|
443
468
|
color: {
|
|
444
469
|
srcFactor: "src-alpha",
|
|
@@ -452,10 +477,21 @@ export class Engine {
|
|
|
452
477
|
},
|
|
453
478
|
},
|
|
454
479
|
};
|
|
455
|
-
//
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
|
|
480
|
+
// Aux target carrying (bloom mask, alpha). Src-alpha blend so the .g channel
|
|
481
|
+
// accumulates proper alpha-over (same semantic the old rgba16f hdr.a had).
|
|
482
|
+
// Materials write vec2f(mask, 1.0); ground writes vec2f(0.0, 1.0). With src.a
|
|
483
|
+
// coming from the fragment color.a, the blend equation produces
|
|
484
|
+
// out.g = 1·src.a + dst.g·(1-src.a) → premultiplied over operator on alpha.
|
|
485
|
+
// .r gets weighted by src.a too, which is fine: opaque pixels (α=1) give full
|
|
486
|
+
// mask, partially translucent fragments dilute mask proportionally — acceptable
|
|
487
|
+
// for the bloom-gate use.
|
|
488
|
+
const maskBlend = {
|
|
489
|
+
format: Engine.BLOOM_MASK_FORMAT,
|
|
490
|
+
blend: {
|
|
491
|
+
color: { srcFactor: "src-alpha", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
492
|
+
alpha: { srcFactor: "one", dstFactor: "one-minus-src-alpha", operation: "add" },
|
|
493
|
+
},
|
|
494
|
+
};
|
|
459
495
|
const sceneTargets = [standardBlend, maskBlend];
|
|
460
496
|
const shaderModule = this.device.createShaderModule({
|
|
461
497
|
label: "default model shader",
|
|
@@ -889,21 +925,21 @@ export class Engine {
|
|
|
889
925
|
label: "bloom blit pipeline",
|
|
890
926
|
layout: bloomBlitLayout,
|
|
891
927
|
vertex: { module: bloomBlitShader, entryPoint: "vs" },
|
|
892
|
-
fragment: { module: bloomBlitShader, entryPoint: "fs", targets: [{ format:
|
|
928
|
+
fragment: { module: bloomBlitShader, entryPoint: "fs", targets: [{ format: this.hdrFormat }] },
|
|
893
929
|
primitive: { topology: "triangle-list" },
|
|
894
930
|
});
|
|
895
931
|
this.bloomDownsamplePipeline = this.device.createRenderPipeline({
|
|
896
932
|
label: "bloom downsample pipeline",
|
|
897
933
|
layout: bloomDownLayout,
|
|
898
934
|
vertex: { module: bloomDownsampleShader, entryPoint: "vs" },
|
|
899
|
-
fragment: { module: bloomDownsampleShader, entryPoint: "fs", targets: [{ format:
|
|
935
|
+
fragment: { module: bloomDownsampleShader, entryPoint: "fs", targets: [{ format: this.hdrFormat }] },
|
|
900
936
|
primitive: { topology: "triangle-list" },
|
|
901
937
|
});
|
|
902
938
|
this.bloomUpsamplePipeline = this.device.createRenderPipeline({
|
|
903
939
|
label: "bloom upsample pipeline",
|
|
904
940
|
layout: bloomUpLayout,
|
|
905
941
|
vertex: { module: bloomUpsampleShader, entryPoint: "vs" },
|
|
906
|
-
fragment: { module: bloomUpsampleShader, entryPoint: "fs", targets: [{ format:
|
|
942
|
+
fragment: { module: bloomUpsampleShader, entryPoint: "fs", targets: [{ format: this.hdrFormat }] },
|
|
907
943
|
primitive: { topology: "triangle-list" },
|
|
908
944
|
});
|
|
909
945
|
// ─── Composite: HDR + bloom → Filmic → swapchain (premultiplied) ───
|
|
@@ -921,6 +957,9 @@ export class Engine {
|
|
|
921
957
|
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
922
958
|
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
|
|
923
959
|
{ binding: 3, visibility: GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
960
|
+
// Aux mask/alpha texture — composite reads .g to reconstruct the alpha that
|
|
961
|
+
// used to live in the HDR target before the rg11b10ufloat switch.
|
|
962
|
+
{ binding: 4, visibility: GPUShaderStage.FRAGMENT, texture: {} },
|
|
924
963
|
],
|
|
925
964
|
});
|
|
926
965
|
const compositeShader = this.device.createShaderModule({
|
|
@@ -1029,13 +1068,13 @@ export class Engine {
|
|
|
1029
1068
|
label: "multisample HDR render target",
|
|
1030
1069
|
size: [width, height],
|
|
1031
1070
|
sampleCount: Engine.MULTISAMPLE_COUNT,
|
|
1032
|
-
format:
|
|
1071
|
+
format: this.hdrFormat,
|
|
1033
1072
|
usage: GPUTextureUsage.RENDER_ATTACHMENT,
|
|
1034
1073
|
});
|
|
1035
1074
|
this.hdrResolveTexture = this.device.createTexture({
|
|
1036
1075
|
label: "HDR resolve target",
|
|
1037
1076
|
size: [width, height],
|
|
1038
|
-
format:
|
|
1077
|
+
format: this.hdrFormat,
|
|
1039
1078
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
1040
1079
|
});
|
|
1041
1080
|
// Bloom-mask MRT attachments — same dims + MSAA as HDR so they share the render pass.
|
|
@@ -1064,14 +1103,14 @@ export class Engine {
|
|
|
1064
1103
|
label: "bloom down pyramid",
|
|
1065
1104
|
size: [bw, bh],
|
|
1066
1105
|
mipLevelCount: this.bloomMipCount,
|
|
1067
|
-
format:
|
|
1106
|
+
format: this.hdrFormat,
|
|
1068
1107
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
1069
1108
|
});
|
|
1070
1109
|
this.bloomUpTexture = this.device.createTexture({
|
|
1071
1110
|
label: "bloom up pyramid",
|
|
1072
1111
|
size: [bw, bh],
|
|
1073
1112
|
mipLevelCount: Math.max(1, this.bloomMipCount - 1),
|
|
1074
|
-
format:
|
|
1113
|
+
format: this.hdrFormat,
|
|
1075
1114
|
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
|
|
1076
1115
|
});
|
|
1077
1116
|
this.bloomDownMipViews = [];
|
|
@@ -1186,6 +1225,7 @@ export class Engine {
|
|
|
1186
1225
|
{ binding: 1, resource: compositeBloomView },
|
|
1187
1226
|
{ binding: 2, resource: this.bloomSampler },
|
|
1188
1227
|
{ binding: 3, resource: { buffer: this.compositeUniformBuffer } },
|
|
1228
|
+
{ binding: 4, resource: this.maskResolveView },
|
|
1189
1229
|
],
|
|
1190
1230
|
});
|
|
1191
1231
|
}
|
|
@@ -2320,13 +2360,17 @@ export class Engine {
|
|
|
2320
2360
|
}
|
|
2321
2361
|
Engine.instance = null;
|
|
2322
2362
|
Engine.MULTISAMPLE_COUNT = 4;
|
|
2323
|
-
Engine.HDR_FORMAT = "rgba16float";
|
|
2324
2363
|
/** Stencil value stamped by eye draws so hair can stencil-test against it and
|
|
2325
2364
|
* alpha-blend a second pass over eye silhouette pixels (see-through-hair effect). */
|
|
2326
2365
|
Engine.STENCIL_EYE_VALUE = 1;
|
|
2327
|
-
/**
|
|
2328
|
-
*
|
|
2329
|
-
*
|
|
2330
|
-
|
|
2366
|
+
/** Aux MRT alongside HDR color. Two channels:
|
|
2367
|
+
* .r — bloom mask (1 = model geometry, 0 = ground; sampled by bloom blit to gate prefilter).
|
|
2368
|
+
* .g — accumulated alpha (the channel that used to live in hdr.a before the HDR format
|
|
2369
|
+
* switched to rg11b10ufloat, which has no alpha). Sampled by composite/bloom to
|
|
2370
|
+
* un-premultiply color for tonemap and to produce the canvas-drawable alpha used by
|
|
2371
|
+
* the premultiplied alphaMode compositor (so the page background still shows through
|
|
2372
|
+
* cleared / edge-faded regions like before).
|
|
2373
|
+
* rg8unorm at 4× MSAA is 8 bytes/texel — still fits Apple TBDR tile memory comfortably. */
|
|
2374
|
+
Engine.BLOOM_MASK_FORMAT = "rg8unorm";
|
|
2331
2375
|
Engine.BLOOM_MAX_LEVELS = 7;
|
|
2332
2376
|
Engine.SHADOW_MAP_SIZE = 2048;
|