reze-engine 0.10.1 → 0.11.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 +113 -20
- package/dist/asset-reader.d.ts +16 -0
- package/dist/asset-reader.d.ts.map +1 -0
- package/dist/asset-reader.js +74 -0
- package/dist/engine.d.ts +179 -36
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1133 -321
- package/dist/folder-upload.d.ts +24 -0
- package/dist/folder-upload.d.ts.map +1 -0
- package/dist/folder-upload.js +50 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/model.d.ts +6 -1
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +34 -2
- package/dist/pmx-loader.d.ts +3 -0
- package/dist/pmx-loader.d.ts.map +1 -1
- package/dist/pmx-loader.js +9 -2
- package/dist/shaders/body.d.ts +2 -0
- package/dist/shaders/body.d.ts.map +1 -0
- package/dist/shaders/body.js +209 -0
- package/dist/shaders/classify.d.ts +4 -0
- package/dist/shaders/classify.d.ts.map +1 -0
- package/dist/shaders/classify.js +12 -0
- package/dist/shaders/cloth_rough.d.ts +2 -0
- package/dist/shaders/cloth_rough.d.ts.map +1 -0
- package/dist/shaders/cloth_rough.js +172 -0
- package/dist/shaders/cloth_smooth.d.ts +2 -0
- package/dist/shaders/cloth_smooth.d.ts.map +1 -0
- package/dist/shaders/cloth_smooth.js +171 -0
- package/dist/shaders/default.d.ts +2 -0
- package/dist/shaders/default.d.ts.map +1 -0
- package/dist/shaders/default.js +168 -0
- package/dist/shaders/dfg_lut.d.ts +4 -0
- package/dist/shaders/dfg_lut.d.ts.map +1 -0
- package/dist/shaders/dfg_lut.js +125 -0
- package/dist/shaders/eye.d.ts +2 -0
- package/dist/shaders/eye.d.ts.map +1 -0
- package/dist/shaders/eye.js +142 -0
- package/dist/shaders/face.d.ts +2 -0
- package/dist/shaders/face.d.ts.map +1 -0
- package/dist/shaders/face.js +211 -0
- package/dist/shaders/hair.d.ts +2 -0
- package/dist/shaders/hair.d.ts.map +1 -0
- package/dist/shaders/hair.js +186 -0
- package/dist/shaders/ltc_mag_lut.d.ts +3 -0
- package/dist/shaders/ltc_mag_lut.d.ts.map +1 -0
- package/dist/shaders/ltc_mag_lut.js +1033 -0
- package/dist/shaders/metal.d.ts +2 -0
- package/dist/shaders/metal.d.ts.map +1 -0
- package/dist/shaders/metal.js +171 -0
- package/dist/shaders/nodes.d.ts +2 -0
- package/dist/shaders/nodes.d.ts.map +1 -0
- package/dist/shaders/nodes.js +423 -0
- package/dist/shaders/stockings.d.ts +2 -0
- package/dist/shaders/stockings.d.ts.map +1 -0
- package/dist/shaders/stockings.js +229 -0
- package/package.json +1 -1
- package/src/asset-reader.ts +79 -0
- package/src/engine.ts +1352 -383
- package/src/folder-upload.ts +59 -0
- package/src/index.ts +12 -2
- package/src/model.ts +34 -2
- package/src/pmx-loader.ts +11 -2
- package/src/shaders/body.ts +211 -0
- package/src/shaders/classify.ts +25 -0
- package/src/shaders/cloth_rough.ts +174 -0
- package/src/shaders/cloth_smooth.ts +173 -0
- package/src/shaders/default.ts +169 -0
- package/src/shaders/dfg_lut.ts +127 -0
- package/src/shaders/eye.ts +143 -0
- package/src/shaders/face.ts +213 -0
- package/src/shaders/hair.ts +188 -0
- package/src/shaders/ltc_mag_lut.ts +1035 -0
- package/src/shaders/metal.ts +173 -0
- package/src/shaders/nodes.ts +424 -0
- package/src/shaders/stockings.ts +231 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install reze-engine
|
|
|
12
12
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
|
-
-
|
|
15
|
+
- Blender 3.6 EEVEE rendering port — Principled BSDF with multi-scatter + LTC energy compensation, NPR material presets (face / hair / body / eye / stockings / metal / cloth / default), Filmic tone mapping, alpha-hashed transparency, outlines, MSAA 4x
|
|
16
16
|
- VMD animation with IK solver and Bullet physics
|
|
17
17
|
- Orbit camera with bone-follow mode
|
|
18
18
|
- GPU picking (double-click/tap)
|
|
@@ -25,9 +25,9 @@ npm install reze-engine
|
|
|
25
25
|
import { Engine, Vec3 } from "reze-engine";
|
|
26
26
|
|
|
27
27
|
const engine = new Engine(canvas, {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
world: { color: new Vec3(0.4, 0.49, 0.65), strength: 1.0 },
|
|
29
|
+
sun: { color: new Vec3(1, 1, 1), strength: 2.0, direction: new Vec3(0, -0.5, 1) },
|
|
30
|
+
camera: { distance: 31.5, target: new Vec3(0, 11.5, 0) }, // MMD units (1 unit = 8 cm)
|
|
31
31
|
});
|
|
32
32
|
await engine.init();
|
|
33
33
|
|
|
@@ -43,17 +43,19 @@ engine.runRenderLoop();
|
|
|
43
43
|
|
|
44
44
|
## API
|
|
45
45
|
|
|
46
|
-
One WebGPU **Engine** per page (singleton after `init()`). Load models via
|
|
46
|
+
One WebGPU **Engine** per page (singleton after `init()`). Load models via URL **or** from a user-selected folder (see [Local folder uploads](#local-folder-uploads-browser)).
|
|
47
47
|
|
|
48
48
|
### Engine
|
|
49
49
|
|
|
50
50
|
```javascript
|
|
51
51
|
engine.init()
|
|
52
52
|
engine.loadModel(name, path)
|
|
53
|
+
engine.loadModel(name, { files, pmxFile? }) // folder upload — see below
|
|
53
54
|
engine.getModel(name)
|
|
54
55
|
engine.getModelNames()
|
|
55
56
|
engine.removeModel(name)
|
|
56
57
|
|
|
58
|
+
engine.setMaterialPresets(name, presetMap) // assign NPR presets by material name
|
|
57
59
|
engine.setMaterialVisible(name, material, visible)
|
|
58
60
|
engine.toggleMaterialVisible(name, material)
|
|
59
61
|
engine.isMaterialVisible(name, material)
|
|
@@ -75,6 +77,38 @@ engine.getStats()
|
|
|
75
77
|
engine.dispose()
|
|
76
78
|
```
|
|
77
79
|
|
|
80
|
+
### Local folder uploads (browser)
|
|
81
|
+
|
|
82
|
+
Use a hidden `<input type="file" webkitdirectory multiple>` (or drag/drop) and pass the resulting `FileList` or `File[]` into the engine. Textures resolve relative to the chosen PMX file inside that tree.
|
|
83
|
+
|
|
84
|
+
**Important:** read `input.files` into a normal array **before** setting `input.value = ""`. The browser’s `FileList` is *live* — clearing the input empties it.
|
|
85
|
+
|
|
86
|
+
1. **`parsePmxFolderInput(fileList)`** — returns a tagged result (`empty` | `not_directory` | `no_pmx` | `single` | `multiple`). For `single`, you already have `files` and `pmxFile`. For `multiple`, show a picker (dropdown) of `pmxRelativePaths`, then resolve with **`pmxFileAtRelativePath(files, path)`**.
|
|
87
|
+
2. **`engine.loadModel(name, { files, pmxFile })`** — `pmxFile` selects which `.pmx` when the folder contains several.
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
import { Engine, parsePmxFolderInput, pmxFileAtRelativePath } from "reze-engine";
|
|
91
|
+
|
|
92
|
+
// In <input onChange>:
|
|
93
|
+
const picked = parsePmxFolderInput(e.target.files);
|
|
94
|
+
e.target.value = "";
|
|
95
|
+
|
|
96
|
+
if (picked.status === "single") {
|
|
97
|
+
const model = await engine.loadModel("myModel", {
|
|
98
|
+
files: picked.files,
|
|
99
|
+
pmxFile: picked.pmxFile,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (picked.status === "multiple") {
|
|
104
|
+
// Let the user choose `chosenPath` from picked.pmxRelativePaths, then:
|
|
105
|
+
const pmxFile = pmxFileAtRelativePath(picked.files, chosenPath);
|
|
106
|
+
const model = await engine.loadModel("myModel", { files: picked.files, pmxFile });
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
VMD and other assets still load by URL when the path starts with `/` or `http(s):`; relative paths are resolved against the PMX directory inside the upload.
|
|
111
|
+
|
|
78
112
|
### Model
|
|
79
113
|
|
|
80
114
|
```javascript
|
|
@@ -108,12 +142,12 @@ model.getBoneWorldPosition(name)
|
|
|
108
142
|
`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.
|
|
109
143
|
|
|
110
144
|
```javascript
|
|
111
|
-
const buffer = model.exportVmd("idle")
|
|
112
|
-
const blob = new Blob([buffer], { type: "application/octet-stream" })
|
|
113
|
-
const link = document.createElement("a")
|
|
114
|
-
link.href = URL.createObjectURL(blob)
|
|
115
|
-
link.download = "idle.vmd"
|
|
116
|
-
link.click()
|
|
145
|
+
const buffer = model.exportVmd("idle");
|
|
146
|
+
const blob = new Blob([buffer], { type: "application/octet-stream" });
|
|
147
|
+
const link = document.createElement("a");
|
|
148
|
+
link.href = URL.createObjectURL(blob);
|
|
149
|
+
link.download = "idle.vmd";
|
|
150
|
+
link.click();
|
|
117
151
|
```
|
|
118
152
|
|
|
119
153
|
#### Playback
|
|
@@ -126,29 +160,88 @@ Call `model.play(name, options?)` to start or switch motion. `loop: true` makes
|
|
|
126
160
|
|
|
127
161
|
### Engine Options
|
|
128
162
|
|
|
163
|
+
Blender-style scene config — `world` = environment lighting, `sun` = the directional lamp, `camera` = view framing.
|
|
164
|
+
|
|
129
165
|
```javascript
|
|
130
166
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
167
|
+
world: {
|
|
168
|
+
color: Vec3, // World > Surface > Color (linear scene-referred)
|
|
169
|
+
strength: number, // World > Surface > Strength
|
|
170
|
+
},
|
|
171
|
+
sun: {
|
|
172
|
+
color: Vec3, // Light > Color
|
|
173
|
+
strength: number, // Light > Strength (Blender units)
|
|
174
|
+
direction: Vec3, // direction light travels (points from sun into the scene)
|
|
175
|
+
},
|
|
176
|
+
camera: {
|
|
177
|
+
distance: number,
|
|
178
|
+
target: Vec3,
|
|
179
|
+
fov: number, // radians
|
|
180
|
+
},
|
|
138
181
|
onRaycast: (modelName, material, screenX, screenY) => void,
|
|
139
|
-
shadowLightDirection: Vec3,
|
|
140
182
|
physicsOptions: {
|
|
141
183
|
constraintSolverKeywords: string[],
|
|
142
184
|
},
|
|
143
185
|
}
|
|
144
186
|
```
|
|
145
187
|
|
|
146
|
-
|
|
188
|
+
The shadow map is cast from `sun.direction` — same vector the shader lights with — so the visible shading and cast shadows stay coupled.
|
|
189
|
+
|
|
190
|
+
`engine.setWorld({ color?, strength? })` and `engine.setSun({ color?, strength?, direction? })` update lighting at runtime; changing `sun.direction` refreshes the shadow VP on the next frame.
|
|
147
191
|
|
|
148
192
|
`constraintSolverKeywords` — joints whose name contains any keyword use the Bullet 2.75 constraint solver; all others keep the stable Ammo 2.82+ default. See [babylon-mmd: Fix Constraint Behavior](https://noname0310.github.io/babylon-mmd/docs/reference/runtime/apply-physics-to-mmd-models/#fix-constraint-behavior) for details.
|
|
149
193
|
|
|
194
|
+
## Rendering
|
|
195
|
+
|
|
196
|
+
The renderer follows Blender 3.6 EEVEE — shading, tone mapping, and transparency decisions match the reference CPU/GPU paths so authors tuning a model in Blender see the same result on the web.
|
|
197
|
+
|
|
198
|
+
### Principled BSDF port
|
|
199
|
+
|
|
200
|
+
- GGX specular with Schlick Fresnel and Smith G1
|
|
201
|
+
- **Multi-scatter compensation** via Fdez-Agüera 2019 (`F_brdf_multi_scatter`) — the closed-form version used in EEVEE's `bsdf_common_lib.glsl`
|
|
202
|
+
- **DFG split-sum LUT** baked at `engine.init()` — port of Blender's `bsdf_lut_frag.glsl`. Used for indirect specular and as the denominator of the direct-spec energy compensation
|
|
203
|
+
- **LTC direct-specular energy compensation** (`ltc_brdf_scale = (ltc.x + ltc.y) / (dfg.x + dfg.y)`, per `closure_eval_glossy_lib.glsl:79-81`) — keeps direct and indirect spec in the same energy budget. The LTC magnitude LUT is uploaded from `eevee_lut.c` constants
|
|
204
|
+
- Sheen coarse approximation (`f³·0.077 + f·0.01 + 0.00026`) on cloth/stockings
|
|
205
|
+
|
|
206
|
+
### NPR material presets
|
|
207
|
+
|
|
208
|
+
Each PMX material is dispatched to one of the preset shaders, all ported from "仿深空之眼渲染预设v1.0" Blender node graphs:
|
|
209
|
+
|
|
210
|
+
| Preset | Based on Blender material |
|
|
211
|
+
| -------------- | ------------------------- |
|
|
212
|
+
| `face` | `M_Face` — toon ramp + rim + warm bleed + Principled mix |
|
|
213
|
+
| `hair` | `M_Hair` — anisotropic spec highlight + rim |
|
|
214
|
+
| `body` | `M_Body` — toon ramp + AO + rim + Principled mix |
|
|
215
|
+
| `eye` | `M_Eye` — iris mapping + highlight |
|
|
216
|
+
| `stockings` | `M_Stockings` — NPR mask × Principled with sheen, alpha-hashed |
|
|
217
|
+
| `metal` | `M_Metal` — anisotropic + environment rim |
|
|
218
|
+
| `cloth_smooth` | `M_Cloth_Smooth` — Principled cloth with sheen |
|
|
219
|
+
| `cloth_rough` | `M_Cloth_Rough` — rougher variant |
|
|
220
|
+
| `default` | Principled BSDF (unmapped fallback) |
|
|
221
|
+
|
|
222
|
+
Assign presets per-model:
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
engine.setMaterialPresets("hero", {
|
|
226
|
+
face: ["顔", "白目", "口の中"],
|
|
227
|
+
hair: ["髪", "前髪"],
|
|
228
|
+
body: ["肌"],
|
|
229
|
+
eye: ["瞳"],
|
|
230
|
+
stockings: ["袜子"],
|
|
231
|
+
cloth_smooth: ["制服", "スカート"],
|
|
232
|
+
metal: ["ボタン"],
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Material names not listed fall through to the `default` Principled BSDF.
|
|
237
|
+
|
|
238
|
+
### Alpha-hashed transparency
|
|
239
|
+
|
|
240
|
+
`stockings` uses the Wyman & McGuire 2017 derivative-aware stochastic discard (port of EEVEE's `prepass_frag.glsl::hashed_alpha_threshold`) instead of alpha blend. Self-overlapping transparent meshes (stockings wrap the leg — front and back surfaces share screen pixels) can't be sorted per-fragment in one draw call, so blend produces "cracks". Hashed alpha keeps opaque-style depth writes, resolves under MSAA/TAA, and matches the fix the preset author documented.
|
|
241
|
+
|
|
150
242
|
## Projects Using This Engine
|
|
151
243
|
|
|
244
|
+
- **[Reze Studio](https://reze.studio)** - Web-native MMD animation editor
|
|
152
245
|
- **[MiKaPo](https://mikapo.vercel.app)** — Real-time motion capture for MMD
|
|
153
246
|
- **[Popo](https://popo.love)** — LLM-generated MMD poses
|
|
154
247
|
- **[MPL](https://mmd-mpl.vercel.app)** — Motion programming language for MMD
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Unified binary I/O for PMX/VMD/textures: HTTP(s) or user folder (File map). */
|
|
2
|
+
export type AssetReader = {
|
|
3
|
+
readBinary(logicalPath: string): Promise<ArrayBuffer>;
|
|
4
|
+
};
|
|
5
|
+
/** Normalize PMX-style paths: backslashes, trim, strip leading ./ */
|
|
6
|
+
export declare function normalizeAssetPath(p: string): string;
|
|
7
|
+
/** Join PMX directory prefix and texture-relative path (both may be ""). */
|
|
8
|
+
export declare function joinAssetPath(baseDir: string, relative: string): string;
|
|
9
|
+
/** Same rules as the original engine string split: supports absolute site paths like `/models/a/b.pmx`. */
|
|
10
|
+
export declare function deriveBasePathFromPmxPath(pmxPath: string): string;
|
|
11
|
+
export declare function createFetchAssetReader(): AssetReader;
|
|
12
|
+
/** Keys must be normalized paths relative to the selected folder root (see fileListToMap). */
|
|
13
|
+
export declare function createFileMapAssetReader(files: Map<string, File>): AssetReader;
|
|
14
|
+
export declare function fileListToMap(files: FileList | File[]): Map<string, File>;
|
|
15
|
+
export declare function findFirstPmxFileInList(files: FileList | File[]): File | null;
|
|
16
|
+
//# sourceMappingURL=asset-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-reader.d.ts","sourceRoot":"","sources":["../src/asset-reader.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;CACtD,CAAA;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED,2GAA2G;AAC3G,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,sBAAsB,IAAI,WAAW,CAQpD;AAED,8FAA8F;AAC9F,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,WAAW,CAkB9E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAOzE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAS5E"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Unified binary I/O for PMX/VMD/textures: HTTP(s) or user folder (File map). */
|
|
2
|
+
/** Normalize PMX-style paths: backslashes, trim, strip leading ./ */
|
|
3
|
+
export function normalizeAssetPath(p) {
|
|
4
|
+
let s = p.replace(/\\/g, "/").trim();
|
|
5
|
+
if (s.startsWith("./"))
|
|
6
|
+
s = s.slice(2);
|
|
7
|
+
return s;
|
|
8
|
+
}
|
|
9
|
+
/** Join PMX directory prefix and texture-relative path (both may be ""). */
|
|
10
|
+
export function joinAssetPath(baseDir, relative) {
|
|
11
|
+
const rel = normalizeAssetPath(relative);
|
|
12
|
+
if (!rel)
|
|
13
|
+
return normalizeAssetPath(baseDir);
|
|
14
|
+
const base = baseDir.endsWith("/") ? baseDir.slice(0, -1) : baseDir;
|
|
15
|
+
if (!base)
|
|
16
|
+
return rel;
|
|
17
|
+
return `${base}/${rel}`;
|
|
18
|
+
}
|
|
19
|
+
/** Same rules as the original engine string split: supports absolute site paths like `/models/a/b.pmx`. */
|
|
20
|
+
export function deriveBasePathFromPmxPath(pmxPath) {
|
|
21
|
+
const pathParts = pmxPath.replace(/\\/g, "/").split("/");
|
|
22
|
+
pathParts.pop();
|
|
23
|
+
return pathParts.join("/") + (pathParts.length > 0 ? "/" : "");
|
|
24
|
+
}
|
|
25
|
+
export function createFetchAssetReader() {
|
|
26
|
+
return {
|
|
27
|
+
async readBinary(logicalPath) {
|
|
28
|
+
const r = await fetch(logicalPath);
|
|
29
|
+
if (!r.ok)
|
|
30
|
+
throw new Error(`Failed to fetch ${logicalPath}: ${r.status} ${r.statusText}`);
|
|
31
|
+
return r.arrayBuffer();
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Keys must be normalized paths relative to the selected folder root (see fileListToMap). */
|
|
36
|
+
export function createFileMapAssetReader(files) {
|
|
37
|
+
return {
|
|
38
|
+
async readBinary(logicalPath) {
|
|
39
|
+
const key = normalizeAssetPath(logicalPath);
|
|
40
|
+
let file = files.get(key);
|
|
41
|
+
if (!file) {
|
|
42
|
+
const lower = key.toLowerCase();
|
|
43
|
+
for (const [k, f] of files) {
|
|
44
|
+
if (k.toLowerCase() === lower) {
|
|
45
|
+
file = f;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!file)
|
|
51
|
+
throw new Error(`Missing file in folder: ${key}`);
|
|
52
|
+
return file.arrayBuffer();
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function fileListToMap(files) {
|
|
57
|
+
const m = new Map();
|
|
58
|
+
for (const f of Array.from(files)) {
|
|
59
|
+
const rel = f.webkitRelativePath ?? f.name;
|
|
60
|
+
m.set(normalizeAssetPath(rel), f);
|
|
61
|
+
}
|
|
62
|
+
return m;
|
|
63
|
+
}
|
|
64
|
+
export function findFirstPmxFileInList(files) {
|
|
65
|
+
const list = Array.from(files).filter((f) => f.name.toLowerCase().endsWith(".pmx"));
|
|
66
|
+
if (list.length === 0)
|
|
67
|
+
return null;
|
|
68
|
+
list.sort((a, b) => {
|
|
69
|
+
const pa = a.webkitRelativePath ?? a.name;
|
|
70
|
+
const pb = b.webkitRelativePath ?? b.name;
|
|
71
|
+
return pa.localeCompare(pb);
|
|
72
|
+
});
|
|
73
|
+
return list[0] ?? null;
|
|
74
|
+
}
|
package/dist/engine.d.ts
CHANGED
|
@@ -1,32 +1,86 @@
|
|
|
1
1
|
import { Vec3 } from "./math";
|
|
2
2
|
import { Model } from "./model";
|
|
3
3
|
import { type PhysicsOptions } from "./physics";
|
|
4
|
+
import { type AssetReader } from "./asset-reader";
|
|
5
|
+
import { type MaterialPresetMap } from "./shaders/classify";
|
|
4
6
|
export type RaycastCallback = (modelName: string, material: string | null, screenX: number, screenY: number) => void;
|
|
7
|
+
/** Select a folder (webkitdirectory) and pass FileList or File[]; pmxFile picks which .pmx when several exist. */
|
|
8
|
+
export type LoadModelFromFilesOptions = {
|
|
9
|
+
files: FileList | File[];
|
|
10
|
+
pmxFile?: File;
|
|
11
|
+
};
|
|
12
|
+
export type WorldOptions = {
|
|
13
|
+
/** Linear scene-referred color of the World Background (Blender: World > Surface > Color). */
|
|
14
|
+
color?: Vec3;
|
|
15
|
+
/** Multiplier on world color (Blender: World > Surface > Strength). */
|
|
16
|
+
strength?: number;
|
|
17
|
+
};
|
|
18
|
+
export type SunOptions = {
|
|
19
|
+
/** Linear color of the sun lamp (Blender: Light > Color). */
|
|
20
|
+
color?: Vec3;
|
|
21
|
+
/** Lamp power in Blender units (Blender: Light > Strength). */
|
|
22
|
+
strength?: number;
|
|
23
|
+
/** Direction sunlight travels (points FROM sun TO scene, Blender: -light.rotation.Z). */
|
|
24
|
+
direction?: Vec3;
|
|
25
|
+
};
|
|
26
|
+
export type CameraOptions = {
|
|
27
|
+
/** Orbit distance from target. */
|
|
28
|
+
distance?: number;
|
|
29
|
+
/** World-space orbit center. */
|
|
30
|
+
target?: Vec3;
|
|
31
|
+
/** Vertical field of view in radians. */
|
|
32
|
+
fov?: number;
|
|
33
|
+
};
|
|
34
|
+
/** EEVEE Bloom panel (3D Viewport > Render > Bloom). Fields map 1:1 to Blender's UI. */
|
|
35
|
+
export type BloomOptions = {
|
|
36
|
+
enabled: boolean;
|
|
37
|
+
threshold: number;
|
|
38
|
+
knee: number;
|
|
39
|
+
radius: number;
|
|
40
|
+
color: Vec3;
|
|
41
|
+
intensity: number;
|
|
42
|
+
clamp: number;
|
|
43
|
+
};
|
|
44
|
+
export declare const DEFAULT_BLOOM_OPTIONS: BloomOptions;
|
|
45
|
+
/** Blender Color Management / View (rendering.txt: Filmic, exposure, gamma). `look` is reserved for future curve tweaks. */
|
|
46
|
+
export type ViewTransformOptions = {
|
|
47
|
+
/** Stops applied before Filmic: `linear *= 2^exposure` (Blender default often ~−0.3). */
|
|
48
|
+
exposure: number;
|
|
49
|
+
/** After Filmic, display gamma (`pow(rgb, 1/gamma)`). */
|
|
50
|
+
gamma: number;
|
|
51
|
+
look: "default" | "medium_high_contrast";
|
|
52
|
+
};
|
|
53
|
+
export declare const DEFAULT_VIEW_TRANSFORM: ViewTransformOptions;
|
|
5
54
|
export type EngineOptions = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
55
|
+
world?: WorldOptions;
|
|
56
|
+
sun?: SunOptions;
|
|
57
|
+
camera?: CameraOptions;
|
|
58
|
+
/** Initial EEVEE-style bloom; tune at runtime with `setBloomOptions`. */
|
|
59
|
+
bloom?: Partial<BloomOptions>;
|
|
60
|
+
/** View transform (exposure/gamma) applied in composite before/after Filmic. */
|
|
61
|
+
view?: Partial<ViewTransformOptions>;
|
|
13
62
|
onRaycast?: RaycastCallback;
|
|
14
63
|
physicsOptions?: PhysicsOptions;
|
|
15
|
-
shadowLightDirection?: Vec3;
|
|
16
64
|
};
|
|
17
65
|
export declare const DEFAULT_ENGINE_OPTIONS: {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
66
|
+
world: {
|
|
67
|
+
color: Vec3;
|
|
68
|
+
strength: number;
|
|
69
|
+
};
|
|
70
|
+
sun: {
|
|
71
|
+
color: Vec3;
|
|
72
|
+
strength: number;
|
|
73
|
+
direction: Vec3;
|
|
74
|
+
};
|
|
75
|
+
camera: {
|
|
76
|
+
distance: number;
|
|
77
|
+
target: Vec3;
|
|
78
|
+
fov: number;
|
|
79
|
+
};
|
|
25
80
|
onRaycast: undefined;
|
|
26
81
|
physicsOptions: {
|
|
27
82
|
constraintSolverKeywords: string[];
|
|
28
83
|
};
|
|
29
|
-
shadowLightDirection: Vec3;
|
|
30
84
|
};
|
|
31
85
|
export interface EngineStats {
|
|
32
86
|
fps: number;
|
|
@@ -42,15 +96,23 @@ export declare class Engine {
|
|
|
42
96
|
private camera;
|
|
43
97
|
private cameraUniformBuffer;
|
|
44
98
|
private cameraMatrixData;
|
|
45
|
-
private
|
|
46
|
-
private
|
|
47
|
-
private
|
|
99
|
+
private world;
|
|
100
|
+
private sun;
|
|
101
|
+
private cameraConfig;
|
|
48
102
|
private lightUniformBuffer;
|
|
49
103
|
private lightData;
|
|
50
104
|
private lightCount;
|
|
51
105
|
private resizeObserver;
|
|
52
106
|
private depthTexture;
|
|
53
107
|
private modelPipeline;
|
|
108
|
+
private facePipeline;
|
|
109
|
+
private hairPipeline;
|
|
110
|
+
private clothSmoothPipeline;
|
|
111
|
+
private clothRoughPipeline;
|
|
112
|
+
private metalPipeline;
|
|
113
|
+
private bodyPipeline;
|
|
114
|
+
private eyePipeline;
|
|
115
|
+
private stockingsPipeline;
|
|
54
116
|
private groundShadowPipeline;
|
|
55
117
|
private groundShadowBindGroupLayout;
|
|
56
118
|
private outlinePipeline;
|
|
@@ -62,17 +124,48 @@ export declare class Engine {
|
|
|
62
124
|
private perFrameBindGroup;
|
|
63
125
|
private outlinePerFrameBindGroup;
|
|
64
126
|
private multisampleTexture;
|
|
127
|
+
private hdrResolveTexture;
|
|
65
128
|
private static readonly MULTISAMPLE_COUNT;
|
|
129
|
+
private static readonly HDR_FORMAT;
|
|
66
130
|
private renderPassDescriptor;
|
|
67
|
-
private
|
|
68
|
-
private
|
|
69
|
-
private
|
|
70
|
-
private
|
|
131
|
+
private compositePassDescriptor;
|
|
132
|
+
private compositePipeline;
|
|
133
|
+
private compositeBindGroupLayout;
|
|
134
|
+
private compositeBindGroup;
|
|
135
|
+
private compositeUniformBuffer;
|
|
136
|
+
private readonly compositeUniformData;
|
|
137
|
+
private bloomSampler;
|
|
138
|
+
private bloomBlitUniformBuffer;
|
|
139
|
+
private bloomUpsampleUniformBuffer;
|
|
140
|
+
private readonly bloomBlitUniformData;
|
|
141
|
+
private readonly bloomUpsampleUniformData;
|
|
142
|
+
private bloomBlitPipeline;
|
|
143
|
+
private bloomDownsamplePipeline;
|
|
144
|
+
private bloomUpsamplePipeline;
|
|
145
|
+
private bloomBlitBindGroupLayout;
|
|
146
|
+
private bloomDownsampleBindGroupLayout;
|
|
147
|
+
private bloomUpsampleBindGroupLayout;
|
|
148
|
+
private bloomDownTexture;
|
|
149
|
+
private bloomUpTexture;
|
|
150
|
+
private bloomMipCount;
|
|
151
|
+
private bloomDownMipViews;
|
|
152
|
+
private bloomUpMipViews;
|
|
153
|
+
private bloomBlitBindGroup;
|
|
154
|
+
private bloomDownsampleBindGroups;
|
|
155
|
+
private bloomUpsampleBindGroups;
|
|
156
|
+
/** Single-attachment pass; colorAttachments[0].view set per bloom step. */
|
|
157
|
+
private bloomPassDescriptor;
|
|
158
|
+
private static readonly BLOOM_MAX_LEVELS;
|
|
71
159
|
private groundVertexBuffer?;
|
|
72
160
|
private groundIndexBuffer?;
|
|
73
161
|
private hasGround;
|
|
74
|
-
private shadowMapTexture
|
|
75
|
-
private shadowMapDepthView
|
|
162
|
+
private shadowMapTexture;
|
|
163
|
+
private shadowMapDepthView;
|
|
164
|
+
private dfgLutTexture;
|
|
165
|
+
private dfgLutView;
|
|
166
|
+
private ltcMagLutTexture;
|
|
167
|
+
private ltcMagLutView;
|
|
168
|
+
private static readonly SHADOW_MAP_SIZE;
|
|
76
169
|
private shadowDepthPipeline;
|
|
77
170
|
private shadowLightVPBuffer;
|
|
78
171
|
private shadowLightVPMatrix;
|
|
@@ -82,7 +175,6 @@ export declare class Engine {
|
|
|
82
175
|
private groundDrawCall;
|
|
83
176
|
private onRaycast?;
|
|
84
177
|
private physicsOptions;
|
|
85
|
-
private shadowLightDirection;
|
|
86
178
|
private lastTouchTime;
|
|
87
179
|
private readonly DOUBLE_TAP_DELAY;
|
|
88
180
|
private pickPipeline;
|
|
@@ -111,8 +203,23 @@ export declare class Engine {
|
|
|
111
203
|
private stats;
|
|
112
204
|
private animationFrameId;
|
|
113
205
|
private renderLoopCallback;
|
|
206
|
+
private bloomSettings;
|
|
207
|
+
private viewTransform;
|
|
114
208
|
constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
|
|
209
|
+
/** Merge partial bloom with EEVEE defaults (same as constructor). */
|
|
210
|
+
static mergeBloomDefaults(partial?: Partial<BloomOptions>): BloomOptions;
|
|
211
|
+
static mergeViewTransformDefaults(partial?: Partial<ViewTransformOptions>): ViewTransformOptions;
|
|
212
|
+
/** Current bloom settings (Blender names; tint is a copied `Vec3`). */
|
|
213
|
+
getBloomOptions(): BloomOptions;
|
|
214
|
+
getViewTransformOptions(): ViewTransformOptions;
|
|
215
|
+
setViewTransformOptions(patch: Partial<ViewTransformOptions>): void;
|
|
216
|
+
private writeCompositeViewUniforms;
|
|
217
|
+
/** Patch bloom; GPU uniforms update immediately if `init()` has run. */
|
|
218
|
+
setBloomOptions(patch: Partial<BloomOptions>): void;
|
|
219
|
+
private writeBloomUniforms;
|
|
115
220
|
init(): Promise<void>;
|
|
221
|
+
private bakeDfgLut;
|
|
222
|
+
private uploadLtcMagLut;
|
|
116
223
|
private createRenderPipeline;
|
|
117
224
|
private createPipelines;
|
|
118
225
|
private setupResize;
|
|
@@ -131,15 +238,33 @@ export declare class Engine {
|
|
|
131
238
|
getCameraBeta(): number;
|
|
132
239
|
setCameraBeta(b: number): void;
|
|
133
240
|
private setupLighting;
|
|
134
|
-
|
|
135
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Write world ambient. For a uniform-radiance world, hemispherical irradiance
|
|
243
|
+
* is E = π·L and a Lambertian BRDF reflects (albedo/π)·E = albedo·L, so the
|
|
244
|
+
* shader's ambient uniform is just `world.color × world.strength` — no /π.
|
|
245
|
+
*/
|
|
246
|
+
private writeWorld;
|
|
247
|
+
/** Write sun lamp into light slot `index` (0..3). Layout mirrors the WGSL struct. */
|
|
248
|
+
private writeSun;
|
|
249
|
+
/** Update the world environment (Blender: World Background). Ambient recomputes immediately. */
|
|
250
|
+
setWorld(options: WorldOptions): void;
|
|
251
|
+
/** Update the sun lamp (Blender: Light > Sun). Direction change marks shadow VP dirty. */
|
|
252
|
+
setSun(options: SunOptions): void;
|
|
253
|
+
getWorld(): Readonly<{
|
|
254
|
+
color: Vec3;
|
|
255
|
+
strength: number;
|
|
256
|
+
}>;
|
|
257
|
+
getSun(): Readonly<{
|
|
258
|
+
color: Vec3;
|
|
259
|
+
strength: number;
|
|
260
|
+
direction: Vec3;
|
|
261
|
+
}>;
|
|
136
262
|
addGround(options?: {
|
|
137
263
|
width?: number;
|
|
138
264
|
height?: number;
|
|
139
265
|
diffuseColor?: Vec3;
|
|
140
266
|
fadeStart?: number;
|
|
141
267
|
fadeEnd?: number;
|
|
142
|
-
shadowMapSize?: number;
|
|
143
268
|
shadowStrength?: number;
|
|
144
269
|
gridSpacing?: number;
|
|
145
270
|
gridLineWidth?: number;
|
|
@@ -154,11 +279,13 @@ export declare class Engine {
|
|
|
154
279
|
dispose(): void;
|
|
155
280
|
loadModel(path: string): Promise<Model>;
|
|
156
281
|
loadModel(name: string, path: string): Promise<Model>;
|
|
157
|
-
|
|
282
|
+
loadModel(name: string, options: LoadModelFromFilesOptions): Promise<Model>;
|
|
283
|
+
addModel(model: Model, pmxPath: string, name?: string, assetReader?: AssetReader): Promise<string>;
|
|
158
284
|
removeModel(name: string): void;
|
|
159
285
|
getModelNames(): string[];
|
|
160
286
|
getModel(name: string): Model | null;
|
|
161
287
|
markVertexBufferDirty(modelNameOrModel?: string | Model): void;
|
|
288
|
+
setMaterialPresets(modelName: string, presets: MaterialPresetMap): void;
|
|
162
289
|
setMaterialVisible(modelName: string, materialName: string, visible: boolean): void;
|
|
163
290
|
toggleMaterialVisible(modelName: string, materialName: string): void;
|
|
164
291
|
isMaterialVisible(modelName: string, materialName: string): boolean;
|
|
@@ -178,7 +305,7 @@ export declare class Engine {
|
|
|
178
305
|
private createMaterialUniformBuffer;
|
|
179
306
|
private createUniformBuffer;
|
|
180
307
|
private shouldRenderDrawCall;
|
|
181
|
-
private
|
|
308
|
+
private createTextureFromLogicalPath;
|
|
182
309
|
private renderGround;
|
|
183
310
|
private handleCanvasDoubleClick;
|
|
184
311
|
private handleCanvasTouch;
|
|
@@ -186,15 +313,31 @@ export declare class Engine {
|
|
|
186
313
|
private renderPickPass;
|
|
187
314
|
private resolvePickResult;
|
|
188
315
|
render(): void;
|
|
189
|
-
private updateRenderTarget;
|
|
190
316
|
private drawInstanceShadow;
|
|
191
|
-
private
|
|
192
|
-
|
|
193
|
-
|
|
317
|
+
private pipelineForPreset;
|
|
318
|
+
/**
|
|
319
|
+
* Draw every material of a given type (`opaque` or `transparent`) using the main
|
|
320
|
+
* pipeline(s). Binds the per-frame and per-instance groups once at the top of the
|
|
321
|
+
* batch, then issues one draw per material. Early-outs if nothing to draw so we
|
|
322
|
+
* don't waste bindings when a model has no transparents, etc.
|
|
323
|
+
*/
|
|
324
|
+
private drawMaterials;
|
|
325
|
+
/**
|
|
326
|
+
* Draw every outline of a given type (`opaque-outline` or `transparent-outline`).
|
|
327
|
+
* Uses its own pipeline layout (group 0 = camera-only, group 2 = edge uniforms), so
|
|
328
|
+
* every batch binds its own groups from scratch — the next drawMaterials call will
|
|
329
|
+
* rebind group 0/1 correctly if needed.
|
|
330
|
+
*/
|
|
331
|
+
private drawOutlines;
|
|
332
|
+
/**
|
|
333
|
+
* Main-pass render sequence for one model instance:
|
|
334
|
+
* 1) opaque bodies → 2) opaque outlines → 3) transparents → 4) transparent outlines.
|
|
335
|
+
* Each batch binds the groups it needs, so switching between main and outline
|
|
336
|
+
* pipelines is self-contained (no cross-batch dependencies).
|
|
337
|
+
*/
|
|
194
338
|
private renderOneModel;
|
|
195
339
|
private updateCameraUniforms;
|
|
196
340
|
private updateSkinMatrices;
|
|
197
|
-
private drawOutlines;
|
|
198
341
|
private updateStats;
|
|
199
342
|
}
|
|
200
343
|
//# sourceMappingURL=engine.d.ts.map
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,IAAI,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/B,OAAO,EAAW,KAAK,cAAc,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|