reze-engine 0.60.4 → 0.61.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 +121 -5
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +284 -19
- package/dist/graph/compile.d.ts.map +1 -1
- package/dist/graph/compile.js +4 -1
- package/dist/graph/registry.d.ts.map +1 -1
- package/dist/graph/registry.js +14 -2
- package/dist/graph/slots.d.ts +1 -1
- package/dist/graph/slots.d.ts.map +1 -1
- package/dist/graph/slots.js +19 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -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/lights.d.ts.map +1 -1
- package/dist/shaders/lights.js +19 -0
- 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/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +47 -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/nodes.d.ts +1 -1
- package/dist/shaders/materials/nodes.d.ts.map +1 -1
- package/dist/shaders/materials/nodes.js +110 -23
- 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 +1 -1
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +34 -2
- 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/scene-tap.js +1 -1
- package/package.json +1 -1
- package/src/engine.ts +312 -19
- package/src/graph/compile.ts +4 -1
- package/src/graph/registry.ts +14 -2
- package/src/graph/slots.ts +20 -5
- package/src/index.ts +4 -0
- package/src/shaders/lights.ts +19 -0
- package/src/shaders/materials/common.ts +47 -0
- package/src/shaders/materials/nodes.ts +110 -23
- package/src/shaders/passes/composite.ts +34 -2
- package/src/shaders/scene-tap.ts +1 -1
- 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/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
package/src/shaders/lights.ts
CHANGED
|
@@ -362,6 +362,25 @@ fn rzLightsDiffuse(p: vec3f, n: vec3f) -> vec3f {
|
|
|
362
362
|
return _rzLightsIrradiance(p, n) * (1.0 / 3.141592653589793);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
// ONE WALK PER FRAGMENT. A principled closure walks the lamps for its specular
|
|
366
|
+
// anyway, and every lamp's reach, falloff and cone are the same numbers the
|
|
367
|
+
// diffuse layer needs — so that walk computes both, against the normal the
|
|
368
|
+
// material prelude recorded here, and leaves the diffuse for the epilogue.
|
|
369
|
+
// Walking the grid twice was ~60% of a lit stage's frame.
|
|
370
|
+
var<private> _rzLampN: vec3f;
|
|
371
|
+
var<private> _rzLampDiffuse: vec3f;
|
|
372
|
+
var<private> _rzLampDiffuseSet: bool = false;
|
|
373
|
+
// Set by a closure that shaded the lamps' diffuse itself (a Unity-mode
|
|
374
|
+
// principled, which tints it by its own base) — the epilogue then adds none.
|
|
375
|
+
var<private> _rzLampDiffuseTaken: bool = false;
|
|
376
|
+
|
|
377
|
+
/** rzLightsDiffuse(p, _rzLampN), taken from a principled walk when one ran. */
|
|
378
|
+
fn rzLightsDiffuseOnce(p: vec3f, n: vec3f) -> vec3f {
|
|
379
|
+
if (_rzLampDiffuseTaken) { return vec3f(0.0); }
|
|
380
|
+
if (_rzLampDiffuseSet) { return _rzLampDiffuse; }
|
|
381
|
+
return rzLightsDiffuse(p, n);
|
|
382
|
+
}
|
|
383
|
+
|
|
365
384
|
fn _rzLightsIrradiance(p: vec3f, n: vec3f) -> vec3f {
|
|
366
385
|
var acc = vec3f(0.0);
|
|
367
386
|
let count = rzLightCount();
|
|
@@ -54,6 +54,13 @@ struct LightUniforms {
|
|
|
54
54
|
lights: array<Light, 4>,
|
|
55
55
|
/** Irradiance SH of the HDRI world; [0].w is the on-flag. */
|
|
56
56
|
sh: array<vec4f, 9>,
|
|
57
|
+
/** The scene fog (Engine.setSceneFog): haze (colour, amount), (distance,
|
|
58
|
+
* height), then the second layer the same. Amount 0 is none. */
|
|
59
|
+
fog: array<vec4f, 4>,
|
|
60
|
+
/** The cast's shadow on a stage (Engine.setStageCastShadow): colour, amount;
|
|
61
|
+
* amount 0 is off. Then the view-projection its map was drawn with. */
|
|
62
|
+
castShadow: vec4f,
|
|
63
|
+
castVP: mat4x4f,
|
|
57
64
|
};
|
|
58
65
|
|
|
59
66
|
// Per-material uniforms. Every material binds this layout even if it ignores fields;
|
|
@@ -121,8 +128,19 @@ struct VertexOutput {
|
|
|
121
128
|
* must agree — a pass that disagrees punches holes through her.
|
|
122
129
|
*/
|
|
123
130
|
@location(4) @interpolate(flat) faceT: f32,
|
|
131
|
+
/** The scene fog's two amounts, computed PER VERTEX as the game does — see
|
|
132
|
+
* Engine.setSceneFog — and interpolated across the face. */
|
|
133
|
+
@location(5) fog: vec2f,
|
|
124
134
|
};
|
|
125
135
|
|
|
136
|
+
/** One fog layer's amount at a vertex of view depth d and world height y. */
|
|
137
|
+
fn _rzFogAmount(d: f32, y: f32, col: vec4f, p: vec4f) -> f32 {
|
|
138
|
+
if (col.w <= 0.0) { return 0.0; }
|
|
139
|
+
let f = clamp(d * p.x + p.y, 0.0, 1.0);
|
|
140
|
+
let h = clamp((p.z - y) / p.w, -1.0, 1.0);
|
|
141
|
+
return (1.0 - clamp(f - (1.0 - f) * h, 0.0, 1.0)) * col.w;
|
|
142
|
+
}
|
|
143
|
+
|
|
126
144
|
// One view-projection per shadow cascade, inner to outer — the volumes built
|
|
127
145
|
// by shadow-cascades.ts, in the same order.
|
|
128
146
|
struct LightVP { viewProj: array<mat4x4f, ${SHADOW_CASCADES.length}>, };
|
|
@@ -144,6 +162,30 @@ struct LightVP { viewProj: array<mat4x4f, ${SHADOW_CASCADES.length}>, };
|
|
|
144
162
|
// has the 1x1 fallback bound here; rzWorldSpecular checks the SH flag and
|
|
145
163
|
// answers with the flat ambient instead, so nothing samples the placeholder.
|
|
146
164
|
@group(0) @binding(8) var worldEnvTexture: texture_2d<f32>;
|
|
165
|
+
// The cast's own shadow map for a stage's floor — see _rzCastShadow.
|
|
166
|
+
@group(0) @binding(10) var castShadowMap: texture_depth_2d;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* How much of the cast stands between this point and the stage's shadow
|
|
170
|
+
* direction, 0–1 — setStageCastShadow. A 5×5 comparison filter at 1.5 texels:
|
|
171
|
+
* the game blurs its character shadow before laying it, and a single tap reads
|
|
172
|
+
* as a stencil.
|
|
173
|
+
*/
|
|
174
|
+
fn _rzCastShadow(wp: vec3f) -> f32 {
|
|
175
|
+
if (light.castShadow.w <= 0.0) { return 0.0; }
|
|
176
|
+
let c = light.castVP * vec4f(wp, 1.0);
|
|
177
|
+
let ndc = c.xyz / c.w;
|
|
178
|
+
if (abs(ndc.x) >= 1.0 || abs(ndc.y) >= 1.0 || ndc.z <= 0.0 || ndc.z >= 1.0) { return 0.0; }
|
|
179
|
+
let uv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
|
|
180
|
+
let ts = 1.5 / f32(textureDimensions(castShadowMap).x);
|
|
181
|
+
var lit = 0.0;
|
|
182
|
+
for (var y = -2; y <= 2; y++) {
|
|
183
|
+
for (var x = -2; x <= 2; x++) {
|
|
184
|
+
lit += textureSampleCompareLevel(castShadowMap, shadowSampler, uv + vec2f(f32(x), f32(y)) * ts, ndc.z - 0.001);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return 1.0 - lit / 25.0;
|
|
188
|
+
}
|
|
147
189
|
// binding(9) brdfLut is declared inside NODES_WGSL (nodes.ts).
|
|
148
190
|
@group(1) @binding(0) var<storage, read> skinMats: array<mat4x4f>;
|
|
149
191
|
// The light this model takes apart from the scene's — see Engine.setModelFill
|
|
@@ -273,6 +315,11 @@ const COMMON_VS_WGSL = /* wgsl */ `
|
|
|
273
315
|
output.worldPos = skinnedPos.xyz;
|
|
274
316
|
output.restPos = position;
|
|
275
317
|
output.faceT = rz_dissolve_threshold(position);
|
|
318
|
+
let viewZ = (camera.view * vec4f(skinnedPos.xyz, 1.0)).z;
|
|
319
|
+
output.fog = vec2f(
|
|
320
|
+
_rzFogAmount(viewZ, skinnedPos.y, light.fog[0], light.fog[1]),
|
|
321
|
+
_rzFogAmount(viewZ, skinnedPos.y, light.fog[2], light.fog[3]),
|
|
322
|
+
);
|
|
276
323
|
return output;
|
|
277
324
|
}
|
|
278
325
|
|
|
@@ -312,6 +312,21 @@ fn point_world_to_camera(p: vec3f) -> vec3f { return (camera.view * vec4f(p, 1.0
|
|
|
312
312
|
* texture sees no change at all.
|
|
313
313
|
*/
|
|
314
314
|
fn rzWorldSpecular(dir: vec3f, roughness: f32) -> vec3f {
|
|
315
|
+
return rzWorldSpecularLod(dir, roughness, 0.0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The same, with the blur curve chosen. unity = 0 is the sqrt ramp above; 1 is
|
|
320
|
+
* Unity's reflection-probe lookup, mip = p·(1.7 − 0.7p)·8 — the curve a game's
|
|
321
|
+
* glossy floor was tuned under, about a level sharper than sqrt through the
|
|
322
|
+
* glossy range (roughness 0.1–0.3) and the same by 0.5.
|
|
323
|
+
*
|
|
324
|
+
* Its levels map one to one onto this chain's: a cube of N texels a face and an
|
|
325
|
+
* equirect 4N wide resolve the same angle per texel, so a cube's last level —
|
|
326
|
+
* one texel a face — is this chain's log2(width/4), and the curve stops there
|
|
327
|
+
* rather than averaging the whole sky, as the game's does.
|
|
328
|
+
*/
|
|
329
|
+
fn rzWorldSpecularLod(dir: vec3f, roughness: f32, unity: f32) -> vec3f {
|
|
315
330
|
// A SKY TEXTURE, or the best the scene has. The flag is 2 when an HDRI is
|
|
316
331
|
// installed, 1 when the world is a gradient fitted to the same harmonics,
|
|
317
332
|
// and 0 when it is one flat colour — and in the last two cases the ambient
|
|
@@ -327,7 +342,9 @@ fn rzWorldSpecular(dir: vec3f, roughness: f32) -> vec3f {
|
|
|
327
342
|
// sqrt, not linear: mip n covers roughly twice the angle of n-1, so a linear
|
|
328
343
|
// ramp spends most of its travel in the blurry end and a mirror-to-satin
|
|
329
344
|
// sweep happens entirely in the first tenth of the dial.
|
|
330
|
-
let
|
|
345
|
+
let r = clamp(roughness, 0.0, 1.0);
|
|
346
|
+
let unityLod = min(r * (1.7 - 0.7 * r) * 8.0, max(levels - 2.0, 0.0));
|
|
347
|
+
let lod = clamp(mix(sqrt(r) * levels, unityLod, unity), 0.0, levels);
|
|
331
348
|
return textureSampleLevel(worldEnvTexture, diffuseSampler, vec2f(u, v), lod).rgb * light.ambientColor.w;
|
|
332
349
|
}
|
|
333
350
|
|
|
@@ -866,6 +883,28 @@ fn bsdf_ggx(N: vec3f, L: vec3f, V: vec3f, NL_in: f32, NV_in: f32, roughness: f32
|
|
|
866
883
|
return NL * a2 / (D_opti * G);
|
|
867
884
|
}
|
|
868
885
|
|
|
886
|
+
// URP's direct-light specular, as a game on URP (or a fork of it) shades its
|
|
887
|
+
// lamps and sun: D·V·F folded into a2 / (d²·max(0.1, LoH²)·(4a + 2)), a the
|
|
888
|
+
// SQUARED roughness. Unity folds π into its light units, and a light that came
|
|
889
|
+
// from one reaches this engine with that π restored (see the app's stage
|
|
890
|
+
// loader), so it comes back out here. Returns BRDF × NL, like bsdf_ggx.
|
|
891
|
+
fn bsdf_urp(N: vec3f, L: vec3f, V: vec3f, NL: f32, roughness: f32) -> f32 {
|
|
892
|
+
let a = max(roughness * roughness, 6.1035156e-5);
|
|
893
|
+
let a2 = a * a;
|
|
894
|
+
let H = normalize(L + V);
|
|
895
|
+
let NH = max(dot(N, H), 0.0);
|
|
896
|
+
let LH = max(dot(L, H), 0.0);
|
|
897
|
+
let d = NH * NH * (a2 - 1.0) + 1.00001;
|
|
898
|
+
return a2 / (d * d * max(0.1, LH * LH) * (a * 4.0 + 2.0)) * NL / EEVEE_PI;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/** The direct-light lobe a principled closure asked for: 0 the engine's own,
|
|
902
|
+
* 1 URP's (principled's unity_direct). */
|
|
903
|
+
fn _rzDirectLobe(N: vec3f, L: vec3f, V: vec3f, NL: f32, NV: f32, roughness: f32, unity: f32) -> f32 {
|
|
904
|
+
if (unity > 0.5) { return bsdf_urp(N, L, V, NL, roughness); }
|
|
905
|
+
return bsdf_ggx(N, L, V, NL, NV, roughness);
|
|
906
|
+
}
|
|
907
|
+
|
|
869
908
|
// Split-sum DFG LUT — Karis 2013 curve fit stand-in for the 64×64 baked LUT.
|
|
870
909
|
// Returns (lut.x, lut.y) in Blender convention: tint = f0·lut.x + f90·lut.y.
|
|
871
910
|
fn brdf_lut_approx(NV: f32, roughness: f32) -> vec2f {
|
|
@@ -997,50 +1036,74 @@ fn principled_specular(ior: f32, level: f32) -> f32 {
|
|
|
997
1036
|
// It walks the light grid a second time — the lamps THIS CELL can see, which
|
|
998
1037
|
// is what the grid is for — and with no lamps at all neither walk runs.
|
|
999
1038
|
|
|
1000
|
-
|
|
1039
|
+
// The walk also yields the DIFFUSE layer, against the prelude's normal
|
|
1040
|
+
// (_rzLampN, not the mapped N) and in the order rzLightsDiffuse sums it, so the
|
|
1041
|
+
// epilogue's rzLightsDiffuseOnce is that function's exact answer without a
|
|
1042
|
+
// second pass over the grid. See lights.ts.
|
|
1043
|
+
struct _RzLampPair { d: vec3f, s: vec3f };
|
|
1044
|
+
|
|
1045
|
+
fn _rzLampOne(i: u32, p: vec3f, n: vec3f, v: vec3f, ndv: f32, roughness: f32, unity: f32) -> _RzLampPair {
|
|
1046
|
+
var out = _RzLampPair(vec3f(0.0), vec3f(0.0));
|
|
1001
1047
|
let pr = _rzLightVec(i, 0u);
|
|
1002
1048
|
let d = pr.xyz - p;
|
|
1003
1049
|
let dist = length(d);
|
|
1004
|
-
if (dist >= pr.w) { return
|
|
1050
|
+
if (dist >= pr.w) { return out; }
|
|
1005
1051
|
let toLight = d / max(dist, 1e-4);
|
|
1052
|
+
let ndlD = max(dot(_rzLampN, toLight), 0.0);
|
|
1006
1053
|
let ndl = dot(n, toLight);
|
|
1007
|
-
if (ndl <= 0.0) { return
|
|
1054
|
+
if (ndlD <= 0.0 && ndl <= 0.0) { return out; }
|
|
1008
1055
|
let t = clamp(dist / max(pr.w, 1e-4), 0.0, 1.0);
|
|
1009
1056
|
let t2 = t * t;
|
|
1010
1057
|
let window = 1.0 - t2 * t2;
|
|
1011
1058
|
let falloff = window * window / max(dist * dist, RZ_LAMP_NEAR * RZ_LAMP_NEAR);
|
|
1012
1059
|
let cone = rzLightCone(i);
|
|
1013
1060
|
let aim = clamp((dot(-toLight, rzLightAim(i)) - cone.x) / max(cone.y - cone.x, 1e-4), 0.0, 1.0);
|
|
1014
|
-
|
|
1061
|
+
let c = rzLightColor(i);
|
|
1062
|
+
if (ndlD > 0.0) { out.d = c * (ndlD * falloff * aim * aim); }
|
|
1063
|
+
if (ndl > 0.0) { out.s = c * (_rzDirectLobe(n, toLight, v, ndl, ndv, roughness, unity) * falloff * aim * aim); }
|
|
1064
|
+
return out;
|
|
1015
1065
|
}
|
|
1016
1066
|
|
|
1017
|
-
fn
|
|
1018
|
-
var acc = vec3f(0.0);
|
|
1067
|
+
fn _rzLampWord(bits0: u32, base: u32, p: vec3f, n: vec3f, v: vec3f, ndv: f32, roughness: f32, unity: f32) -> _RzLampPair {
|
|
1068
|
+
var acc = _RzLampPair(vec3f(0.0), vec3f(0.0));
|
|
1019
1069
|
var bits = bits0;
|
|
1020
1070
|
loop {
|
|
1021
1071
|
if (bits == 0u) { break; }
|
|
1022
1072
|
let i = base + firstTrailingBit(bits);
|
|
1023
1073
|
bits = bits & (bits - 1u);
|
|
1024
|
-
|
|
1074
|
+
let one = _rzLampOne(i, p, n, v, ndv, roughness, unity);
|
|
1075
|
+
acc.d = acc.d + one.d;
|
|
1076
|
+
acc.s = acc.s + one.s;
|
|
1025
1077
|
}
|
|
1026
1078
|
return acc;
|
|
1027
1079
|
}
|
|
1028
1080
|
|
|
1029
|
-
fn rzLampsSpecular(p: vec3f, n: vec3f, v: vec3f, ndv: f32, roughness: f32) -> vec3f {
|
|
1030
|
-
var
|
|
1081
|
+
fn rzLampsSpecular(p: vec3f, n: vec3f, v: vec3f, ndv: f32, roughness: f32, unity: f32) -> vec3f {
|
|
1082
|
+
var d = vec3f(0.0);
|
|
1083
|
+
var s = vec3f(0.0);
|
|
1031
1084
|
let count = rzLightCount();
|
|
1032
1085
|
let docs = _rzLightDocCount();
|
|
1033
1086
|
if (docs > 0u) {
|
|
1034
1087
|
let m = _rzLightCellMask(p);
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1088
|
+
let wx = _rzLampWord(m.x, 0u, p, n, v, ndv, roughness, unity);
|
|
1089
|
+
let wy = _rzLampWord(m.y, 32u, p, n, v, ndv, roughness, unity);
|
|
1090
|
+
let wz = _rzLampWord(m.z, 64u, p, n, v, ndv, roughness, unity);
|
|
1091
|
+
let ww = _rzLampWord(m.w, 96u, p, n, v, ndv, roughness, unity);
|
|
1092
|
+
d = d + wx.d + wy.d + wz.d + ww.d;
|
|
1093
|
+
s = s + wx.s + wy.s + wz.s + ww.s;
|
|
1039
1094
|
}
|
|
1040
1095
|
for (var i = docs; i < count; i = i + 1u) {
|
|
1041
|
-
|
|
1096
|
+
let one = _rzLampOne(i, p, n, v, ndv, roughness, unity);
|
|
1097
|
+
d = d + one.d;
|
|
1098
|
+
s = s + one.s;
|
|
1042
1099
|
}
|
|
1043
|
-
|
|
1100
|
+
// The first closure's walk speaks for the fragment; a second principled in
|
|
1101
|
+
// the same graph shares p and the prelude normal, so its answer is the same.
|
|
1102
|
+
if (!_rzLampDiffuseSet) {
|
|
1103
|
+
_rzLampDiffuse = d * (1.0 / 3.141592653589793);
|
|
1104
|
+
_rzLampDiffuseSet = true;
|
|
1105
|
+
}
|
|
1106
|
+
return s;
|
|
1044
1107
|
}
|
|
1045
1108
|
|
|
1046
1109
|
struct PrincipledIn {
|
|
@@ -1051,6 +1114,8 @@ struct PrincipledIn {
|
|
|
1051
1114
|
spec_clamp: f32,
|
|
1052
1115
|
sheen: f32,
|
|
1053
1116
|
sheen_tint: f32,
|
|
1117
|
+
reflection_lod: f32,
|
|
1118
|
+
unity_direct: f32,
|
|
1054
1119
|
};
|
|
1055
1120
|
|
|
1056
1121
|
fn eval_principled(
|
|
@@ -1077,9 +1142,12 @@ fn eval_principled(
|
|
|
1077
1142
|
// split-sum indirect path, matching EEVEE closure_eval_glossy_lib behavior.
|
|
1078
1143
|
// The sun, and every lamp that reaches this point. One clamp over the pair:
|
|
1079
1144
|
// a candle a hand's width from a polished floor is a firefly otherwise.
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1145
|
+
// URP's lobe carries its own normalisation, so the LTC rescale that matches
|
|
1146
|
+
// EEVEE's direct light to its split-sum indirect does not apply to it.
|
|
1147
|
+
let direct_scale = select(ltc_brdf_scale_from_lut(lut), 1.0, p.unity_direct > 0.5);
|
|
1148
|
+
let spec_direct_raw = (_rzDirectLobe(N, L, V, NL, NV, p.roughness, p.unity_direct) * sun_rgb * shadow
|
|
1149
|
+
+ rzLampsSpecular(wp, N, V, NV, p.roughness, p.unity_direct))
|
|
1150
|
+
* direct_scale;
|
|
1083
1151
|
let spec_direct = min(spec_direct_raw, vec3f(p.spec_clamp));
|
|
1084
1152
|
// Indirect specular reads the world ALONG THE REFLECTION, at a roughness-
|
|
1085
1153
|
// picked level — EEVEE's probe_evaluate_world_spec, where the diffuse half
|
|
@@ -1088,8 +1156,13 @@ fn eval_principled(
|
|
|
1088
1156
|
// roughness, so a chrome rail mirrored what a matte wall did and a stage's
|
|
1089
1157
|
// metal only ever lost its diffuse. A uniform sky gives the same number
|
|
1090
1158
|
// either way, so this moves direction, not energy.
|
|
1091
|
-
let spec_indirect =
|
|
1092
|
-
|
|
1159
|
+
let spec_indirect = rzWorldSpecularLod(reflect(-V, N), p.roughness, p.reflection_lod);
|
|
1160
|
+
// URP tints a lamp's highlight by f0 alone — its D·V·F already folds the
|
|
1161
|
+
// Fresnel in — where the split-sum reflectance grows toward grazing; applied
|
|
1162
|
+
// to the direct term it made a far glossy floor several times brighter than
|
|
1163
|
+
// the game draws it. Reflections keep the split sum either way.
|
|
1164
|
+
let direct_tint = select(reflection_color, f0, p.unity_direct > 0.5);
|
|
1165
|
+
let spec_radiance = spec_direct * direct_tint + spec_indirect * reflection_color;
|
|
1093
1166
|
|
|
1094
1167
|
// Sheen add — when p.sheen=0 the whole term collapses, leaving diffuse_color=base.
|
|
1095
1168
|
let base_tint = tint_from_color(p.base);
|
|
@@ -1099,9 +1172,23 @@ fn eval_principled(
|
|
|
1099
1172
|
// diffuse_weight = (1-metallic). Indirect diffuse uses amb (L_w) with no π factor
|
|
1100
1173
|
// (probe_evaluate_world_diff returns SH-projected radiance, not cosine-convolved).
|
|
1101
1174
|
let diffuse_weight = 1.0 - p.metallic;
|
|
1102
|
-
|
|
1175
|
+
var diffuse_radiance = diffuse_color * (sun_rgb * NL * shadow / EEVEE_PI + amb_rgb) * diffuse_weight;
|
|
1176
|
+
// The lamps' diffuse, in Unity mode, as URP shades it: THIS surface's albedo
|
|
1177
|
+
// — its tint and its maps, not the raw texture the epilogue would use —
|
|
1178
|
+
// times 0.96·(1 − metal). X340's floor wears a 0.588 tint the epilogue never
|
|
1179
|
+
// saw, and every lamp on it landed 1.7× too bright.
|
|
1180
|
+
if (p.unity_direct > 0.5 && !_rzLampDiffuseTaken) {
|
|
1181
|
+
diffuse_radiance += p.base * (0.96 * (1.0 - p.metallic)) * rzLightsDiffuseOnce(wp, N);
|
|
1182
|
+
_rzLampDiffuseTaken = true;
|
|
1183
|
+
}
|
|
1103
1184
|
|
|
1104
|
-
|
|
1185
|
+
// The cast's shadow on a stage (Unity mode): the game lays its character
|
|
1186
|
+
// shadow over the whole lit surface as a multiply toward the shadow colour.
|
|
1187
|
+
var lit = diffuse_radiance + spec_radiance;
|
|
1188
|
+
if (p.unity_direct > 0.5) {
|
|
1189
|
+
lit = lit * mix(vec3f(1.0), light.castShadow.rgb, _rzCastShadow(wp) * light.castShadow.w);
|
|
1190
|
+
}
|
|
1191
|
+
return lit;
|
|
1105
1192
|
}
|
|
1106
1193
|
|
|
1107
1194
|
`;
|
|
@@ -157,7 +157,8 @@ override APPLY_GAMMA: bool = true;
|
|
|
157
157
|
// per frame while skybox/effect active.
|
|
158
158
|
// viewU[6] = (time seconds, view transform id, canvas width, canvas height).
|
|
159
159
|
// viewU[7] = (grade offset.rgb, contrast); viewU[8] = (grade power.rgb, saturation);
|
|
160
|
-
// viewU[9] = (grade slope.rgb, grade
|
|
160
|
+
// viewU[9] = (grade slope.rgb, grade flags) — bit 0 the CDL grade(), bit 1 the
|
|
161
|
+
// scene's own LUT (setStageGrade) — see _rzGradeScene() below.
|
|
161
162
|
// viewU[10] = (camera world position, _) — refreshed with the basis above.
|
|
162
163
|
// invGamma = 1/gamma precomputed on CPU — avoids a per-pixel divide.
|
|
163
164
|
@group(0) @binding(6) var bgEquirect: texture_2d<f32>;
|
|
@@ -178,6 +179,9 @@ override APPLY_GAMMA: bool = true;
|
|
|
178
179
|
// Blender's AgX, as the 57³ lookup it ships as rather than a reconstruction of
|
|
179
180
|
// it. Sampled in the log-encoded E-Gamut space the cube expects — see agxTransform.
|
|
180
181
|
@group(0) @binding(10) var agxLut: texture_3d<f32>;
|
|
182
|
+
// The scene's own colour grade, as a cube — see _rzStageGrade. sRGB-encoded
|
|
183
|
+
// storage, so what a sample returns is already linear.
|
|
184
|
+
@group(0) @binding(12) var stageGradeLut: texture_3d<f32>;
|
|
181
185
|
// The cast, as data. Read through rzSubject/rzAnchor below — the LAYOUT IS NOT
|
|
182
186
|
// STABLE and never will be, because it depends on what each effect declared.
|
|
183
187
|
// Reading it directly is the one thing that would freeze it forever.
|
|
@@ -306,6 +310,33 @@ fn viewTransform(c: vec3f) -> vec3f {
|
|
|
306
310
|
if (mode > 0.5) { return vec3f(srgb_encode(c.r), srgb_encode(c.g), srgb_encode(c.b)); }
|
|
307
311
|
return vec3f(filmic(c.r), filmic(c.g), filmic(c.b));
|
|
308
312
|
}
|
|
313
|
+
|
|
314
|
+
fn _rzSrgbDecode(x: f32) -> f32 {
|
|
315
|
+
let c = max(x, 0.0);
|
|
316
|
+
return select(pow((c + 0.055) / 1.055, 2.4), c / 12.92, c <= 0.04045);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** The grade a scene arrived with — a game's, baked to a cube by its converter
|
|
320
|
+
* (setStageGrade). Looked up the way that game's final pass looks it up: the
|
|
321
|
+
* formed colour, linear, clamped to the cube, with texel centres at the ends,
|
|
322
|
+
* and trilinear between. The lookup is the whole grade; it has no dials. */
|
|
323
|
+
fn _rzStageGrade(c: vec3f) -> vec3f {
|
|
324
|
+
let lin = clamp(vec3f(_rzSrgbDecode(c.r), _rzSrgbDecode(c.g), _rzSrgbDecode(c.b)), vec3f(0.0), vec3f(1.0));
|
|
325
|
+
let n = f32(textureDimensions(stageGradeLut).x);
|
|
326
|
+
let graded = textureSampleLevel(stageGradeLut, bloomSamp, lin * ((n - 1.0) / n) + 0.5 / n, 0.0).rgb;
|
|
327
|
+
return vec3f(srgb_encode(graded.r), srgb_encode(graded.g), srgb_encode(graded.b));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Both grades, in order: the scene's own first, as the room was graded, then
|
|
331
|
+
* the author's CDL on top of it. Each is behind its own flag bit in viewU[9].w
|
|
332
|
+
* so a scene with neither pays one uniform branch. */
|
|
333
|
+
fn _rzGradeScene(c: vec3f) -> vec3f {
|
|
334
|
+
let flags = u32(viewU[9].w);
|
|
335
|
+
var x = c;
|
|
336
|
+
if ((flags & 2u) != 0u) { x = _rzStageGrade(x); }
|
|
337
|
+
if ((flags & 1u) != 0u) { x = grade(x); }
|
|
338
|
+
return x;
|
|
339
|
+
}
|
|
309
340
|
`
|
|
310
341
|
|
|
311
342
|
/**
|
|
@@ -455,6 +486,7 @@ fn grade(c: vec3f) -> vec3f {
|
|
|
455
486
|
let luma = dot(x, vec3f(0.2126, 0.7152, 0.0722));
|
|
456
487
|
return max(mix(vec3f(luma), x, viewU[8].w), vec3f(0.0));
|
|
457
488
|
}
|
|
489
|
+
|
|
458
490
|
`
|
|
459
491
|
|
|
460
492
|
const COMPOSITE_BODY = /* wgsl */ `
|
|
@@ -537,7 +569,7 @@ const COMPOSITE_BODY = /* wgsl */ `
|
|
|
537
569
|
// load-bearing — leaves green-screen mode's key color unshifted so chroma
|
|
538
570
|
// keying still works. Skipped entirely when the grade is neutral.
|
|
539
571
|
if (viewU[9].w > 0.5) {
|
|
540
|
-
disp =
|
|
572
|
+
disp = _rzGradeScene(disp);
|
|
541
573
|
}
|
|
542
574
|
if (APPLY_GAMMA) {
|
|
543
575
|
disp = pow(disp, vec3f(viewU[0].y));
|
package/src/shaders/scene-tap.ts
CHANGED
|
@@ -202,7 +202,7 @@ fn rzSceneHit(uv: vec2f) -> bool {
|
|
|
202
202
|
*/
|
|
203
203
|
fn rzSceneDisplay(uv: vec2f) -> vec3f {
|
|
204
204
|
var c = max(viewTransform(rzScene(uv) * exp2(viewU[0].x)), vec3f(0.0));
|
|
205
|
-
if (viewU[9].w > 0.5) { c =
|
|
205
|
+
if (viewU[9].w > 0.5) { c = _rzGradeScene(c); }
|
|
206
206
|
return pow(max(c, vec3f(0.0)), vec3f(viewU[0].y));
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -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"}
|