reze-engine 0.61.6 → 0.62.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/dist/_dbg-loader.mjs +1100 -0
- package/dist/engine.d.ts +24 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +105 -9
- package/dist/graph/presets/cloth_rough.d.ts.map +1 -1
- package/dist/graph/presets/cloth_rough.js +5 -3
- package/dist/graph/schema.d.ts +1 -1
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/graph/schema.js +3 -1
- package/dist/physics-debug.d.ts +30 -0
- package/dist/physics-debug.d.ts.map +1 -0
- package/dist/physics-debug.js +526 -0
- package/dist/shaders/directives.d.ts +10 -0
- package/dist/shaders/directives.d.ts.map +1 -1
- package/dist/shaders/directives.js +11 -0
- package/dist/shaders/lights.d.ts.map +1 -1
- package/dist/shaders/lights.js +2 -1
- package/dist/shaders/materials/body.d.ts +2 -0
- package/dist/shaders/materials/body.d.ts.map +1 -0
- package/dist/shaders/materials/body.js +95 -0
- package/dist/shaders/materials/cloth_rough.d.ts +2 -0
- package/dist/shaders/materials/cloth_rough.d.ts.map +1 -0
- package/dist/shaders/materials/cloth_rough.js +69 -0
- package/dist/shaders/materials/cloth_smooth.d.ts +2 -0
- package/dist/shaders/materials/cloth_smooth.d.ts.map +1 -0
- package/dist/shaders/materials/cloth_smooth.js +61 -0
- package/dist/shaders/materials/default.d.ts +2 -0
- package/dist/shaders/materials/default.d.ts.map +1 -0
- package/dist/shaders/materials/default.js +43 -0
- package/dist/shaders/materials/eye.d.ts +2 -0
- package/dist/shaders/materials/eye.d.ts.map +1 -0
- package/dist/shaders/materials/eye.js +60 -0
- package/dist/shaders/materials/face.d.ts +2 -0
- package/dist/shaders/materials/face.d.ts.map +1 -0
- package/dist/shaders/materials/face.js +95 -0
- package/dist/shaders/materials/hair.d.ts +2 -0
- package/dist/shaders/materials/hair.d.ts.map +1 -0
- package/dist/shaders/materials/hair.js +90 -0
- package/dist/shaders/materials/metal.d.ts +2 -0
- package/dist/shaders/materials/metal.d.ts.map +1 -0
- package/dist/shaders/materials/metal.js +77 -0
- package/dist/shaders/materials/mmd_classic.d.ts +2 -0
- package/dist/shaders/materials/mmd_classic.d.ts.map +1 -0
- package/dist/shaders/materials/mmd_classic.js +66 -0
- package/dist/shaders/materials/stockings.d.ts +2 -0
- package/dist/shaders/materials/stockings.d.ts.map +1 -0
- package/dist/shaders/materials/stockings.js +122 -0
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +2 -0
- package/dist/shaders/passes/grid.d.ts.map +1 -1
- package/dist/shaders/passes/grid.js +2 -0
- package/dist/shaders/passes/particles.d.ts +7 -0
- package/dist/shaders/passes/particles.d.ts.map +1 -1
- package/dist/shaders/passes/particles.js +10 -0
- package/dist/shaders/passes/physics-debug.d.ts +2 -0
- package/dist/shaders/passes/physics-debug.d.ts.map +1 -0
- package/dist/shaders/passes/physics-debug.js +69 -0
- package/dist/shaders/passes/scene-contract.d.ts.map +1 -1
- package/dist/shaders/passes/scene-contract.js +6 -2
- package/dist/shaders/passes/trails.d.ts.map +1 -1
- package/dist/shaders/passes/trails.js +2 -1
- package/dist/shaders/texture-api.d.ts +9 -0
- package/dist/shaders/texture-api.d.ts.map +1 -0
- package/dist/shaders/texture-api.js +54 -0
- package/package.json +1 -1
- package/src/engine.ts +119 -5
- package/src/graph/presets/cloth_rough.ts +5 -3
- package/src/graph/schema.ts +3 -1
- package/src/shaders/directives.ts +21 -0
- package/src/shaders/lights.ts +2 -1
- package/src/shaders/passes/composite.ts +2 -0
- package/src/shaders/passes/grid.ts +2 -0
- package/src/shaders/passes/particles.ts +13 -0
- package/src/shaders/passes/scene-contract.ts +6 -2
- package/src/shaders/passes/trails.ts +2 -1
- package/src/shaders/texture-api.ts +56 -0
- package/dist/graph/presets/pool_floor.d.ts +0 -3
- package/dist/graph/presets/pool_floor.d.ts.map +0 -1
- package/dist/graph/presets/pool_floor.js +0 -42
- package/dist/graph/presets/water.d.ts +0 -3
- package/dist/graph/presets/water.d.ts.map +0 -1
- package/dist/graph/presets/water.js +0 -31
- package/dist/physics/autofit.d.ts +0 -147
- package/dist/physics/autofit.d.ts.map +0 -1
- package/dist/physics/autofit.js +0 -501
- package/dist/shaders/passes/field-blit.d.ts +0 -26
- package/dist/shaders/passes/field-blit.d.ts.map +0 -1
- package/dist/shaders/passes/field-blit.js +0 -65
- package/dist/shaders/passes/ghosts.d.ts +0 -22
- package/dist/shaders/passes/ghosts.d.ts.map +0 -1
- package/dist/shaders/passes/ghosts.js +0 -75
- package/dist/shaders/passes/ground-noise.d.ts +0 -7
- package/dist/shaders/passes/ground-noise.d.ts.map +0 -1
- package/dist/shaders/passes/ground-noise.js +0 -88
- package/dist/shaders/passes/sim.d.ts +0 -34
- package/dist/shaders/passes/sim.d.ts.map +0 -1
- package/dist/shaders/passes/sim.js +0 -169
- package/dist/shaders/score-api.d.ts +0 -10
- package/dist/shaders/score-api.d.ts.map +0 -1
- package/dist/shaders/score-api.js +0 -114
- package/dist/shaders/shadow-api.d.ts +0 -29
- package/dist/shaders/shadow-api.d.ts.map +0 -1
- package/dist/shaders/shadow-api.js +0 -112
|
@@ -12,6 +12,7 @@ import { sceneIdFieldWgsl, sceneIdPadWgsl } from "./scene-contract"
|
|
|
12
12
|
import { idApi } from "../id-api"
|
|
13
13
|
import { sceneLightApi } from "../scene-light-api"
|
|
14
14
|
import { pointsApi } from "../points-api"
|
|
15
|
+
import { textureApi } from "../texture-api"
|
|
15
16
|
// GPU particles for user effects: a compute step and an instanced quad draw.
|
|
16
17
|
//
|
|
17
18
|
// Its own shader MODULE rather than more source spliced into composite.ts, for
|
|
@@ -115,6 +116,9 @@ type ParticleSource = {
|
|
|
115
116
|
* bending where a foot pressed is the whole case: the bend has to persist and
|
|
116
117
|
* recover, which is memory, and memory is what the grid is for. */
|
|
117
118
|
gridSize: number
|
|
119
|
+
/** `#textures N`: pictures the shading samples (rzTexture), bound only when
|
|
120
|
+
* N > 0 — see texture-api.ts. Omitted = 0. */
|
|
121
|
+
textures?: number
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
/** Where the shading stage's five scene-light bindings start — see scene-light-api.ts. */
|
|
@@ -126,6 +130,10 @@ export const PARTICLE_POINTS_BINDING = 15
|
|
|
126
130
|
* (6, count, 0, 0), so the draw reads at byte 16. */
|
|
127
131
|
export const PARTICLE_INDIRECT_BINDING = 16
|
|
128
132
|
export const PARTICLE_INDIRECT_BYTES = 32
|
|
133
|
+
/** `#textures`: the pictures at 17..20 and their one sampler at 21, render
|
|
134
|
+
* stage only — see texture-api.ts. */
|
|
135
|
+
export const PARTICLE_TEXTURE_BINDING = 17
|
|
136
|
+
export const PARTICLE_TEXTURE_SAMPLER_BINDING = 21
|
|
129
137
|
export const PARTICLE_INDIRECT_DRAW_OFFSET = 16
|
|
130
138
|
|
|
131
139
|
/** Bytes per particle. Explicitly padded — see the struct below. */
|
|
@@ -234,6 +242,9 @@ ${src.paramsDecl}
|
|
|
234
242
|
idApi(false, 0, 0) + castDistanceStub() + sceneLightApi(false, 0, 0) +
|
|
235
243
|
// The named points, for real: particleInit is where a flame is put on a wick.
|
|
236
244
|
pointsApi(true, 0, PARTICLE_POINTS_BINDING) +
|
|
245
|
+
// Stubs: textureSample is fragment-only, and a spawn rule has no use for a
|
|
246
|
+
// picture. The names resolve so the file compiles here.
|
|
247
|
+
textureApi(0) +
|
|
237
248
|
(src.live
|
|
238
249
|
? `@group(0) @binding(${PARTICLE_INDIRECT_BINDING}) var<storage, read_write> _rzIndirect: array<u32, 8>;\n`
|
|
239
250
|
: "") +
|
|
@@ -333,6 +344,8 @@ ${src.paramsDecl}
|
|
|
333
344
|
// run by the time this draws, inside the scene pass. See scene-light-api.ts.
|
|
334
345
|
sceneLightApi(true, 0, PARTICLE_LIGHT_BINDING) +
|
|
335
346
|
pointsApi(true, 0, PARTICLE_POINTS_BINDING) +
|
|
347
|
+
// The host's pictures, for real — see texture-api.ts.
|
|
348
|
+
textureApi(src.textures ?? 0, 0, PARTICLE_TEXTURE_BINDING, PARTICLE_TEXTURE_SAMPLER_BINDING) +
|
|
336
349
|
"\n// ── user effect ──\n" +
|
|
337
350
|
src.wgsl +
|
|
338
351
|
/* wgsl */ `
|
|
@@ -138,7 +138,7 @@ const ADD_BOTH: GPUBlendState = {
|
|
|
138
138
|
* OVER for something that arrives ALREADY premultiplied: take the source whole
|
|
139
139
|
* and let it displace the destination by its own coverage.
|
|
140
140
|
*
|
|
141
|
-
* The ground
|
|
141
|
+
* The ground, the mirror and particles need it. The other classes write a
|
|
142
142
|
* straight colour and an alpha, and the src-alpha factor premultiplies it once
|
|
143
143
|
* on the way in. The ground cannot: its coverage is the SUM of a lit surface
|
|
144
144
|
* and a colourless shadow-catcher layer, so it has to weight its own colour by
|
|
@@ -194,7 +194,11 @@ const BLENDS: Record<Exclude<SceneRenderClass, "depth-prepass">, [GPUBlendState,
|
|
|
194
194
|
// everything else, and coverage is what the blend applies.
|
|
195
195
|
ground: [PREMULTIPLIED_OVER, ALPHA_OVER],
|
|
196
196
|
outline: [ALPHA_OVER, ALPHA_OVER],
|
|
197
|
-
|
|
197
|
+
// PREMULTIPLIED colour: the particle fragment weights its colour by its own
|
|
198
|
+
// alpha before it writes (passes/particles.ts), so the src-alpha blend would
|
|
199
|
+
// weight it a second time — a splash at alpha 0.1 arrived at a hundredth of
|
|
200
|
+
// its colour instead of a tenth. The aux mask is written straight, as ever.
|
|
201
|
+
particle: [PREMULTIPLIED_OVER, ALPHA_OVER],
|
|
198
202
|
"particle-additive": [ADD_KEEP_ALPHA, ADD_BOTH],
|
|
199
203
|
trail: [ADD_PREMULTIPLIED, ALPHA_OVER],
|
|
200
204
|
}
|
|
@@ -12,6 +12,7 @@ import { sceneIdFieldWgsl, sceneIdPadWgsl } from "./scene-contract"
|
|
|
12
12
|
import { idApi } from "../id-api"
|
|
13
13
|
import { sceneLightApi } from "../scene-light-api"
|
|
14
14
|
import { pointsApi } from "../points-api"
|
|
15
|
+
import { textureApi } from "../texture-api"
|
|
15
16
|
// Ribbons along a bone's recorded path, drawn as geometry.
|
|
16
17
|
//
|
|
17
18
|
// This is the effect the whole geometry path was built for. As a fullscreen
|
|
@@ -303,7 +304,7 @@ fn rzTurnRadius(a: vec3f, b: vec3f, c: vec3f) -> f32 {
|
|
|
303
304
|
gridReadApi(0, 8, 9, src.gridSize) +
|
|
304
305
|
// Stubbed: this module cannot read an attachment the scene pass writes — see
|
|
305
306
|
// id-api.ts. The author's whole file compiles here, so the names must exist.
|
|
306
|
-
idApi(false, 0, 0) + castDistanceStub() + sceneLightApi(false, 0, 0) + pointsApi(false) +
|
|
307
|
+
idApi(false, 0, 0) + castDistanceStub() + sceneLightApi(false, 0, 0) + pointsApi(false) + textureApi(0) +
|
|
307
308
|
"\n// ── user effect ──\n" +
|
|
308
309
|
src.wgsl +
|
|
309
310
|
/* wgsl */ `
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Pictures an effect is handed by its host — `#textures N`.
|
|
2
|
+
//
|
|
3
|
+
// #textures 2
|
|
4
|
+
//
|
|
5
|
+
// gives the PARTICLE SHADING rzTexture(i, uv) and rzTextureLod(i, uv, lod) over
|
|
6
|
+
// N images the host passes with the install (setEffects' `textures`, slot i =
|
|
7
|
+
// picture i). uv (0,0) is the image's top-left row, the style graph's
|
|
8
|
+
// tex_image convention, and it repeats. A slot the host left empty reads white.
|
|
9
|
+
//
|
|
10
|
+
// WHY: a game's splash is a picture on a card, and an effect that may only draw
|
|
11
|
+
// procedurally can only ever guess at it — shape, coverage, veins, each a guess
|
|
12
|
+
// to be corrected. A converted stage carries the game's own textures, and this
|
|
13
|
+
// is how its particles draw them.
|
|
14
|
+
//
|
|
15
|
+
// Fragment-only, because textureSample is: the compute stage and every other
|
|
16
|
+
// module the author's file is spliced into get STUBS returning zero, so one
|
|
17
|
+
// effect file compiles in every mount it has.
|
|
18
|
+
|
|
19
|
+
/** How many pictures one effect can read. */
|
|
20
|
+
export const MAX_EFFECT_TEXTURES = 4
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* rzTexture / rzTextureLod. `count` is the effect's `#textures` (0 = stubs);
|
|
24
|
+
* the textures take bindings first..first+count-1 in `group` and the one
|
|
25
|
+
* sampler `sampler`.
|
|
26
|
+
*/
|
|
27
|
+
export function textureApi(count: number, group = 0, first = 0, sampler = 0): string {
|
|
28
|
+
if (count <= 0) {
|
|
29
|
+
return /* wgsl */ `
|
|
30
|
+
fn rzTexture(i: u32, uv: vec2f) -> vec4f { return vec4f(0.0); }
|
|
31
|
+
fn rzTextureLod(i: u32, uv: vec2f, lod: f32) -> vec4f { return vec4f(0.0); }
|
|
32
|
+
`
|
|
33
|
+
}
|
|
34
|
+
const n = Math.min(count, MAX_EFFECT_TEXTURES)
|
|
35
|
+
let decl = `@group(${group}) @binding(${sampler}) var _rzTexSampler: sampler;\n`
|
|
36
|
+
for (let k = 0; k < n; k++) decl += `@group(${group}) @binding(${first + k}) var _rzTex${k}: texture_2d<f32>;\n`
|
|
37
|
+
// Every slot is sampled unconditionally and the one asked for is selected:
|
|
38
|
+
// textureSample must be reached in uniform control flow, and a switch on a
|
|
39
|
+
// per-fragment index is not.
|
|
40
|
+
const pick = (call: (k: number) => string) => {
|
|
41
|
+
let body = " var c = vec4f(0.0);\n"
|
|
42
|
+
for (let k = 0; k < n; k++) body += ` let s${k} = ${call(k)};\n if (i == ${k}u) { c = s${k}; }\n`
|
|
43
|
+
return body + " return c;\n"
|
|
44
|
+
}
|
|
45
|
+
return (
|
|
46
|
+
decl +
|
|
47
|
+
/* wgsl */ `
|
|
48
|
+
/** Picture i of the effect's #textures, at uv ((0,0) top-left, repeating). */
|
|
49
|
+
fn rzTexture(i: u32, uv: vec2f) -> vec4f {
|
|
50
|
+
${pick((k) => `textureSample(_rzTex${k}, _rzTexSampler, uv)`)}}
|
|
51
|
+
/** The same at an explicit mip level — usable where derivatives are not. */
|
|
52
|
+
fn rzTextureLod(i: u32, uv: vec2f, lod: f32) -> vec4f {
|
|
53
|
+
${pick((k) => `textureSampleLevel(_rzTex${k}, _rzTexSampler, uv, lod)`)}}
|
|
54
|
+
`
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pool_floor.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/pool_floor.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,eAAO,MAAM,gBAAgB,EAAE,WA6B9B,CAAA"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// Pool floor — the tiled bottom seen through water, with caustics on it.
|
|
2
|
-
//
|
|
3
|
-
// The other half of a pool, and the half that does most of the work. A water
|
|
4
|
-
// surface can be tuned for a long time without the shot reading as a pool;
|
|
5
|
-
// putting the focused-light web on the FLOOR is what settles it, because that
|
|
6
|
-
// is the cue a photograph actually carries. It is a floor material, so it is
|
|
7
|
-
// applied to the tile under the water rather than to the water itself.
|
|
8
|
-
//
|
|
9
|
-
// Caustics land between the albedo and the shading deliberately: they are
|
|
10
|
-
// light, so they should still be dimmed by the floor's own shadow rather than
|
|
11
|
-
// glowing through it. That is the difference between water-focused sun and a
|
|
12
|
-
// decal.
|
|
13
|
-
export const POOL_FLOOR_GRAPH = {
|
|
14
|
-
version: 1,
|
|
15
|
-
name: "Pool floor",
|
|
16
|
-
tags: ["stage", "water", "pool"],
|
|
17
|
-
nodes: [
|
|
18
|
-
{ id: "tex", type: "texture" },
|
|
19
|
-
{ id: "mat", type: "material_diffuse" },
|
|
20
|
-
{ id: "base", type: "mix/multiply", inputs: { fac: 1.0 } },
|
|
21
|
-
{ id: "caust", type: "caustics" },
|
|
22
|
-
{
|
|
23
|
-
id: "principled",
|
|
24
|
-
type: "principled",
|
|
25
|
-
inputs: { metallic: 0.0, specular_ior_level: 0.4, roughness: 0.45, spec_clamp: 10.0, sheen_weight: 0.0, sheen_tint: 0.0 },
|
|
26
|
-
},
|
|
27
|
-
],
|
|
28
|
-
links: [
|
|
29
|
-
{ from: { node: "tex", socket: "color" }, to: { node: "base", socket: "a" } },
|
|
30
|
-
{ from: { node: "mat", socket: "color" }, to: { node: "base", socket: "b" } },
|
|
31
|
-
{ from: { node: "base", socket: "color" }, to: { node: "caust", socket: "color" } },
|
|
32
|
-
{ from: { node: "caust", socket: "color" }, to: { node: "principled", socket: "base_color" } },
|
|
33
|
-
],
|
|
34
|
-
output: { node: "principled", socket: "color" },
|
|
35
|
-
params: [
|
|
36
|
-
{ id: "tint", label: "Light tint", target: { node: "caust", socket: "tint" }, kind: "color", default: [1.0, 1.0, 1.0] },
|
|
37
|
-
{ id: "scale", label: "Caustic scale", target: { node: "caust", socket: "scale" }, kind: "float", min: 0.01, max: 1, default: 0.12 },
|
|
38
|
-
{ id: "speed", label: "Caustic speed", target: { node: "caust", socket: "speed" }, kind: "float", min: 0, max: 1, default: 0.15 },
|
|
39
|
-
{ id: "strength", label: "Caustic strength", target: { node: "caust", socket: "strength" }, kind: "float", min: 0, max: 3, default: 0.6 },
|
|
40
|
-
{ id: "fade", label: "Depth fade", target: { node: "caust", socket: "fade" }, kind: "float", min: 1, max: 200, default: 30 },
|
|
41
|
-
],
|
|
42
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"water.d.ts","sourceRoot":"","sources":["../../../src/graph/presets/water.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,eAAO,MAAM,WAAW,EAAE,WAgBzB,CAAA"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Water — a planar reflection, rippled, seen through Fresnel.
|
|
2
|
-
//
|
|
3
|
-
// Put a stage's water materials in a style group carrying this graph and the
|
|
4
|
-
// pool starts reflecting. The reflection itself is the engine's mirror pass,
|
|
5
|
-
// which this is the only graph to read; everything else here is the shaping
|
|
6
|
-
// that keeps it from reading as a mirror laid flat in the floor.
|
|
7
|
-
//
|
|
8
|
-
// The exposed params are the ones worth a slider while judging a shot. Scale
|
|
9
|
-
// and speed are the ripple; a real pool's surface is slow and broad, so both
|
|
10
|
-
// defaults sit low. Tint is the water's own colour — a game rip carries that
|
|
11
|
-
// in its material, and the converter hands it straight over.
|
|
12
|
-
//
|
|
13
|
-
// How see-through the water is belongs to the MATERIAL's alpha, not to this
|
|
14
|
-
// graph, which is where every other group's coverage comes from too.
|
|
15
|
-
export const WATER_GRAPH = {
|
|
16
|
-
version: 1,
|
|
17
|
-
name: "Water",
|
|
18
|
-
tags: ["water", "stage"],
|
|
19
|
-
nodes: [{ id: "water", type: "water" }],
|
|
20
|
-
links: [],
|
|
21
|
-
output: { node: "water", socket: "color" },
|
|
22
|
-
params: [
|
|
23
|
-
{ id: "tint", label: "Tint", target: { node: "water", socket: "tint" }, kind: "color", default: [0.04, 0.62, 0.66] },
|
|
24
|
-
{ id: "scale", label: "Ripple scale", target: { node: "water", socket: "scale" }, kind: "float", min: 0.01, max: 1, default: 0.18 },
|
|
25
|
-
{ id: "speed", label: "Ripple speed", target: { node: "water", socket: "speed" }, kind: "float", min: 0, max: 1, default: 0.12 },
|
|
26
|
-
{ id: "strength", label: "Ripple depth", target: { node: "water", socket: "strength" }, kind: "float", min: 0, max: 2, default: 0.7 },
|
|
27
|
-
{ id: "blur", label: "Reflection blur", target: { node: "water", socket: "blur" }, kind: "float", min: 0, max: 1, default: 0.25 },
|
|
28
|
-
{ id: "mirroring", label: "Mirroring", target: { node: "water", socket: "mirroring" }, kind: "float", min: 0, max: 1, default: 0.20 },
|
|
29
|
-
{ id: "sparkle", label: "Sparkle", target: { node: "water", socket: "sparkle" }, kind: "float", min: 0, max: 4, default: 1.0 },
|
|
30
|
-
],
|
|
31
|
-
};
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { type Rigidbody } from "./types";
|
|
2
|
-
import type { Skinning } from "../model";
|
|
3
|
-
/**
|
|
4
|
-
* Supplementary colliders fitted to the mesh a PMX rigid body fails to cover.
|
|
5
|
-
*
|
|
6
|
-
* PMX body proxies are bodies of revolution — 下半身 is a capsule lying
|
|
7
|
-
* transversely across the hips, so its cross-section is a circle. A pelvis seen
|
|
8
|
-
* from the side is not a circle, and across every rig measured the butt sits
|
|
9
|
-
* 0.18–0.71 units OUTSIDE that capsule while the front is flush or inside. That
|
|
10
|
-
* gap is where a skirt goes through a character: the cloth is resting correctly
|
|
11
|
-
* on the collider it was given, and the collider stops half a unit short of the
|
|
12
|
-
* skin.
|
|
13
|
-
*
|
|
14
|
-
* A rest offset cannot close it (see RigidBodyStore.restOffset) — it is one
|
|
15
|
-
* scalar on a radially symmetric shape, and the error is asymmetric. Measured
|
|
16
|
-
* on 托特's run cycle, the offset that clears the butt is 0.5, which is simply
|
|
17
|
-
* the size of the missing geometry, and at that value the skirt stands off the
|
|
18
|
-
* front and hips by the same 0.5.
|
|
19
|
-
*
|
|
20
|
-
* So fit the missing piece instead: take each bone-following body's own skinned
|
|
21
|
-
* vertices, find the ones that escape its shape in a concentrated lobe, and fit
|
|
22
|
-
* a capsule to that lobe. That is the fix riggers apply by hand, derived from
|
|
23
|
-
* the mesh rather than guessed.
|
|
24
|
-
*
|
|
25
|
-
* Measured on 托特's run cycle, counting butt vertices swallowed by a cloth
|
|
26
|
-
* body: 32.4 per frame with nothing, 30.9 with a 0.02 rest offset, 12.4 with
|
|
27
|
-
* this pass, 10.4 with both.
|
|
28
|
-
*/
|
|
29
|
-
export interface AutoFitOptions {
|
|
30
|
-
/** A vertex counts as protruding past this much (model units). Below it the
|
|
31
|
-
* mesh is within authoring tolerance of the proxy and needs no help. */
|
|
32
|
-
minProtrusion?: number;
|
|
33
|
-
/**
|
|
34
|
-
* Ignore vertices further out than this multiple of the source shape's
|
|
35
|
-
* RADIUS (its smallest characteristic dimension).
|
|
36
|
-
*
|
|
37
|
-
* A coarse first cut at keeping hair and loose clothing out — anything
|
|
38
|
-
* standing further off the proxy than the proxy is wide is not skin. The
|
|
39
|
-
* discriminator that actually does the work is minConcentration.
|
|
40
|
-
*/
|
|
41
|
-
maxProtrusionRatio?: number;
|
|
42
|
-
/** Fewer protruding vertices than this and it is a spike, not a region. */
|
|
43
|
-
minVertices?: number;
|
|
44
|
-
/**
|
|
45
|
-
* Per-axis quantile the fitted lobe's extent is clipped to, each end. A
|
|
46
|
-
* handful of stray vertices (a weight-painting slip, a seam) would otherwise
|
|
47
|
-
* stretch the capsule far past the surface everyone can see.
|
|
48
|
-
*/
|
|
49
|
-
quantile?: number;
|
|
50
|
-
/** Skip the fit unless the capsule actually reaches this far past what is
|
|
51
|
-
* already covered — otherwise it adds solver rows for nothing. */
|
|
52
|
-
minGain?: number;
|
|
53
|
-
/** How tightly the kept lobe's outward directions must agree, 0–1. A loose
|
|
54
|
-
* sanity check; the real discriminator is minConcentration. */
|
|
55
|
-
minDirectionality?: number;
|
|
56
|
-
/** Vertices outside the dominant lobe, by this cosine, are not part of the
|
|
57
|
-
* feature being fitted. */
|
|
58
|
-
lobeCos?: number;
|
|
59
|
-
/**
|
|
60
|
-
* How much deeper the fitted lobe must be than protrusion typically is on
|
|
61
|
-
* this body, averaged over the vertices that protrude at all.
|
|
62
|
-
*
|
|
63
|
-
* This is the guard that separates "the proxy is missing a lobe" from "the
|
|
64
|
-
* proxy is not a proxy for this mesh at all". A pelvis escapes its capsule by
|
|
65
|
-
* 0.53 at the back and 0.14 at the front, so the back lobe stands well clear
|
|
66
|
-
* of the average. Hair escapes the skull by a similar depth in every
|
|
67
|
-
* direction, so its deepest lobe is no deeper than typical and the ratio sits
|
|
68
|
-
* near 1. See the note at the meanProtrusion computation for what this
|
|
69
|
-
* deliberately refuses to fit.
|
|
70
|
-
*
|
|
71
|
-
* Without it the pass fits the hairstyle — measured on 托特, 頭 reports
|
|
72
|
-
* 3653 of 4669 vertices outside its capsule, and the fitted shape was a crate
|
|
73
|
-
* around the whole head. No threshold on depth or vertex count tells those
|
|
74
|
-
* two cases apart; concentration does.
|
|
75
|
-
*/
|
|
76
|
-
minConcentration?: number;
|
|
77
|
-
/**
|
|
78
|
-
* How many capsules may be fitted to one body, each against what the previous
|
|
79
|
-
* ones already cover.
|
|
80
|
-
*
|
|
81
|
-
* One capsule inscribed in a lobe does not fill it — on 托特's butt a single
|
|
82
|
-
* fit removed 58% of the clipping and left the rest at the edges the capsule
|
|
83
|
-
* could not reach. Each further pass re-measures protrusion against the
|
|
84
|
-
* original shape UNION everything fitted so far, so it lands on whatever is
|
|
85
|
-
* still exposed instead of re-fitting the same bulge.
|
|
86
|
-
*/
|
|
87
|
-
maxShapesPerBody?: number;
|
|
88
|
-
/**
|
|
89
|
-
* Quantile of the lobe's perpendicular spread used as the capsule radius.
|
|
90
|
-
*
|
|
91
|
-
* The clip-versus-float dial, and the one to reach for if a result looks
|
|
92
|
-
* wrong. Lower hugs the body: less standoff in idle, more clipping left. 1.0
|
|
93
|
-
* encloses the lobe entirely, which is what produced a visibly hovering
|
|
94
|
-
* skirt on 托特.
|
|
95
|
-
*/
|
|
96
|
-
radiusQuantile?: number;
|
|
97
|
-
/**
|
|
98
|
-
* Fit only the deepest part of each lobe: points at least this fraction of
|
|
99
|
-
* the lobe's own maximum protrusion.
|
|
100
|
-
*
|
|
101
|
-
* A lobe tapers to nothing at its edges, and a capsule sized to span the
|
|
102
|
-
* whole thing has to be fat enough to reach the edges too. Fitting the deep
|
|
103
|
-
* core keeps each capsule small and lets a later pass handle the shallows
|
|
104
|
-
* with its own, which is both tighter and closer to what the surface is
|
|
105
|
-
* actually doing.
|
|
106
|
-
*/
|
|
107
|
-
lobeDepthFraction?: number;
|
|
108
|
-
}
|
|
109
|
-
/** What the pass decided for one source body — surfaced so a rig can be
|
|
110
|
-
* inspected rather than silently rebuilt underneath its author. */
|
|
111
|
-
export interface AutoFitResult {
|
|
112
|
-
/** Index of the body in the input array that this supplements. */
|
|
113
|
-
sourceIndex: number;
|
|
114
|
-
sourceName: string;
|
|
115
|
-
/** Vertices dominated by that body's bone, and how many were outside it. */
|
|
116
|
-
vertexCount: number;
|
|
117
|
-
protrudingCount: number;
|
|
118
|
-
/** Furthest any kept vertex sat outside the source shape. */
|
|
119
|
-
maxProtrusion: number;
|
|
120
|
-
/** How far the fitted capsule reaches past what was already covered. */
|
|
121
|
-
gain: number;
|
|
122
|
-
/** Length of the kept lobe's mean outward direction, 0–1. */
|
|
123
|
-
directionality: number;
|
|
124
|
-
/** Lobe depth over the body's average protrusion. See minConcentration. */
|
|
125
|
-
concentration: number;
|
|
126
|
-
/**
|
|
127
|
-
* Furthest the capsule's newly exposed surface sits from the skin it was
|
|
128
|
-
* fitted to — the amount cloth resting on it will stand off the body at the
|
|
129
|
-
* worst point, and the number to watch if a result looks puffy. Only the part
|
|
130
|
-
* reaching outside the source shape is measured; the rest is buried.
|
|
131
|
-
*/
|
|
132
|
-
overshoot: number;
|
|
133
|
-
body: Rigidbody;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Fit supplementary colliders for every bone-following body whose own mesh
|
|
137
|
-
* escapes it.
|
|
138
|
-
*
|
|
139
|
-
* `vertices` is the model's interleaved vertex buffer (stride 8, position
|
|
140
|
-
* first) and `skinning` its joints/weights — both in PMX bind pose, the same
|
|
141
|
-
* space as `shapePosition` / `shapeRotation`, so nothing has to be skinned.
|
|
142
|
-
*
|
|
143
|
-
* Returns one entry per body it chose to supplement; the caller appends
|
|
144
|
-
* `.body` to the rigid body list before constructing RezePhysics.
|
|
145
|
-
*/
|
|
146
|
-
export declare function fitSupplementaryColliders(rigidbodies: Rigidbody[], vertices: Float32Array, skinning: Skinning, options?: AutoFitOptions): AutoFitResult[];
|
|
147
|
-
//# sourceMappingURL=autofit.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"autofit.d.ts","sourceRoot":"","sources":["../../src/physics/autofit.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AACvE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,cAAc;IAC7B;6EACyE;IACzE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;uEACmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;oEACgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;gCAC4B;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;;;;;;;;;;OAgBG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AA2BD;oEACoE;AACpE,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAA;IACnB,eAAe,EAAE,MAAM,CAAA;IACvB,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAA;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAA;IACtB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,SAAS,CAAA;CAChB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,SAAS,EAAE,EACxB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,cAAmB,GAC3B,aAAa,EAAE,CA4CjB"}
|