reze-engine 0.68.3 → 0.68.5
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 +40 -2
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +119 -8
- package/dist/graph/slots.d.ts.map +1 -1
- package/dist/graph/slots.js +12 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/jelly-eyes.d.ts +37 -0
- package/dist/jelly-eyes.d.ts.map +1 -0
- package/dist/jelly-eyes.js +381 -0
- package/dist/shaders/materials/common.d.ts.map +1 -1
- package/dist/shaders/materials/common.js +133 -2
- package/package.json +1 -1
- package/src/engine.ts +121 -8
- package/src/graph/slots.ts +13 -4
- package/src/index.ts +1 -0
- package/src/jelly-eyes.ts +434 -0
- package/src/shaders/materials/common.ts +133 -2
- 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/agx-lut.d.ts +0 -11
- package/dist/shaders/agx-lut.d.ts.map +0 -1
- package/dist/shaders/agx-lut.js +0 -29
- package/dist/shaders/dfg_lut.d.ts +0 -3
- package/dist/shaders/dfg_lut.d.ts.map +0 -1
- package/dist/shaders/dfg_lut.js +0 -129
- package/dist/shaders/ltc_mag_lut.d.ts +0 -3
- package/dist/shaders/ltc_mag_lut.d.ts.map +0 -1
- package/dist/shaders/ltc_mag_lut.js +0 -1033
- 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
package/src/engine.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
type SimClock,
|
|
44
44
|
} from "./effect-schedule"
|
|
45
45
|
import { parentKeySpan, type ModelParentKey } from "./parent-keys"
|
|
46
|
+
import { JellyEyes, clampStrength, clearJellyEyes, type JellyEyeOptions } from "./jelly-eyes"
|
|
46
47
|
import { NativeHost } from "./unity/host"
|
|
47
48
|
import { NativeLooks, type NativeLook } from "./unity/looks"
|
|
48
49
|
import { NativeStage, type NativeStageLights, type NativeStagePackage, type NativeStageReader } from "./unity/stage"
|
|
@@ -427,6 +428,11 @@ export interface MidiNote {
|
|
|
427
428
|
/** How many character positions an effect can read (viewU[11..14]). Defined
|
|
428
429
|
* beside the shader that reads them — the layout arithmetic has to agree. */
|
|
429
430
|
const MAX_EFFECT_SUBJECTS = EFFECT_SUBJECTS
|
|
431
|
+
/** The frame's half height (model units) at and past which a camera follow
|
|
432
|
+
* takes its full smoothing; closer shots follow more rigidly — see the
|
|
433
|
+
* follow in renderWithDelta(). About a full-body shot. */
|
|
434
|
+
const FOLLOW_LAG_FULL_HALF = 8
|
|
435
|
+
|
|
430
436
|
/** Where a character IS, for an effect that follows them. センター carries a
|
|
431
437
|
* motion's root movement — walking, jumping — where the model transform only
|
|
432
438
|
* carries where the model was placed; 全ての親 is the fallback for a model that
|
|
@@ -1004,6 +1010,9 @@ interface ModelInstance {
|
|
|
1004
1010
|
* Off drops every draw from the shadow list; on hands it back to the PMX
|
|
1005
1011
|
* flag on each material. */
|
|
1006
1012
|
castShadow: boolean
|
|
1013
|
+
/** Its jelly eyes' springs, or null while its eyes are still — see
|
|
1014
|
+
* setModelJellyEyes. */
|
|
1015
|
+
jellyEyes: JellyEyes | null
|
|
1007
1016
|
basePath: string
|
|
1008
1017
|
assetReader: AssetReader
|
|
1009
1018
|
gpuBuffers: GPUBuffer[]
|
|
@@ -3038,6 +3047,12 @@ export class Engine {
|
|
|
3038
3047
|
private cameraFollowSmoothing = 0
|
|
3039
3048
|
private cameraFollowSeeded = false
|
|
3040
3049
|
private readonly cameraFollowPos = new Vec3(0, 0, 0)
|
|
3050
|
+
// Turning with the bone (setCameraFollow's `turn`): the bone's facing as yaw
|
|
3051
|
+
// and elevation, eased like the position, whose change each frame is added
|
|
3052
|
+
// to the orbit — so the shot keeps its angle to her face as she turns.
|
|
3053
|
+
private cameraFollowTurn = false
|
|
3054
|
+
private cameraFollowYaw = 0
|
|
3055
|
+
private cameraFollowPitch = 0
|
|
3041
3056
|
private cameraTargetOffset: Vec3 = new Vec3(0, 0, 0)
|
|
3042
3057
|
|
|
3043
3058
|
private lastFrameTime = performance.now()
|
|
@@ -8311,8 +8326,9 @@ export class Engine {
|
|
|
8311
8326
|
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
8312
8327
|
buffer: { type: "read-only-storage" },
|
|
8313
8328
|
},
|
|
8314
|
-
// The model's own light — see setModelFill and setModelSun.
|
|
8315
|
-
|
|
8329
|
+
// The model's own light — see setModelFill and setModelSun. VERTEX
|
|
8330
|
+
// too: jelly eyes move the iris in the vertex shader (jelly[] in it).
|
|
8331
|
+
{ binding: 1, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: "uniform" } },
|
|
8316
8332
|
],
|
|
8317
8333
|
})
|
|
8318
8334
|
// group 2: per-material (textures + material uniforms) — bound per draw call.
|
|
@@ -10222,8 +10238,13 @@ export class Engine {
|
|
|
10222
10238
|
this.cameraTargetOffset.z = offset?.z ?? 0
|
|
10223
10239
|
}
|
|
10224
10240
|
|
|
10225
|
-
/**
|
|
10226
|
-
|
|
10241
|
+
/**
|
|
10242
|
+
* Souls-style follow cam: orbit center tracks a model bone each frame.
|
|
10243
|
+
* Shorthand for setCameraTarget(model, boneName, offset). With `turn`, the
|
|
10244
|
+
* orbit also turns with her face (the head bone) — the camera keeps its
|
|
10245
|
+
* angle to her face as she turns and nods, and a drag still orbits on top.
|
|
10246
|
+
*/
|
|
10247
|
+
setCameraFollow(model: Model | null, boneName?: string, offset?: Vec3, smoothing?: number, turn?: boolean): void {
|
|
10227
10248
|
// Panning sets the very thing the follow overwrites each frame, so it is
|
|
10228
10249
|
// goes to the offset for as long as the shot is riding a bone. See Camera.panSink.
|
|
10229
10250
|
this.camera.panSink = model !== null ? this.cameraTargetOffset : null
|
|
@@ -10239,6 +10260,7 @@ export class Engine {
|
|
|
10239
10260
|
// Handheld feel: seconds for the camera to close ~63% of the gap to the
|
|
10240
10261
|
// bone (exponential, frame-rate independent). 0 = rigid instant follow.
|
|
10241
10262
|
this.cameraFollowSmoothing = Math.max(0, smoothing ?? 0)
|
|
10263
|
+
this.cameraFollowTurn = turn ?? false
|
|
10242
10264
|
this.cameraFollowSeeded = false
|
|
10243
10265
|
}
|
|
10244
10266
|
|
|
@@ -10400,6 +10422,49 @@ export class Engine {
|
|
|
10400
10422
|
}
|
|
10401
10423
|
}
|
|
10402
10424
|
|
|
10425
|
+
/**
|
|
10426
|
+
* The follow's turn: her FACE's direction — the head bone (頭), whatever bone
|
|
10427
|
+
* the position rides, since an eye under eye tracking turns back toward the
|
|
10428
|
+
* camera as the face turns and so never points anywhere new. MMD rests facing
|
|
10429
|
+
* −Z, so forward is its negated third column, placed by the model's
|
|
10430
|
+
* rotation (the followed bone stands in on a rig with no 頭) — as yaw and
|
|
10431
|
+
* elevation, eased by the follow's own lag, and each frame's change added to
|
|
10432
|
+
* the orbit (alpha turns with the yaw, beta with the elevation) and to the
|
|
10433
|
+
* offset (turned about the vertical, so a framing off to her side stays at
|
|
10434
|
+
* her side). Seeds without moving the camera, on the frame the follow is
|
|
10435
|
+
* (re)bound — cameraFollowSeeded, cleared there, is set right after this.
|
|
10436
|
+
*/
|
|
10437
|
+
private turnWithFollowBone(m: Model, tau: number, deltaTime: number): void {
|
|
10438
|
+
const w = m.getBoneWorldMatrix("頭") ?? m.getBoneWorldMatrix(this.cameraTargetBoneName)
|
|
10439
|
+
if (!w) return
|
|
10440
|
+
const fwd = new Vec3(-w[8], -w[9], -w[10])
|
|
10441
|
+
Quat.rotateVecInto(m.rotation, fwd, fwd)
|
|
10442
|
+
const len = Math.hypot(fwd.x, fwd.y, fwd.z)
|
|
10443
|
+
if (len < 1e-6) return
|
|
10444
|
+
const yaw = Math.atan2(fwd.x, fwd.z)
|
|
10445
|
+
const pitch = Math.asin(Math.max(-1, Math.min(1, fwd.y / len)))
|
|
10446
|
+
if (!this.cameraFollowSeeded) {
|
|
10447
|
+
this.cameraFollowYaw = yaw
|
|
10448
|
+
this.cameraFollowPitch = pitch
|
|
10449
|
+
return
|
|
10450
|
+
}
|
|
10451
|
+
const wrap = (a: number) => a - 2 * Math.PI * Math.round(a / (2 * Math.PI))
|
|
10452
|
+
const k = tau > 0 ? 1 - Math.exp(-deltaTime / tau) : 1
|
|
10453
|
+
const dYaw = wrap(yaw - this.cameraFollowYaw) * k
|
|
10454
|
+
const dPitch = (pitch - this.cameraFollowPitch) * k
|
|
10455
|
+
this.cameraFollowYaw = wrap(this.cameraFollowYaw + dYaw)
|
|
10456
|
+
this.cameraFollowPitch += dPitch
|
|
10457
|
+
const cam = this.camera
|
|
10458
|
+
cam.alpha += dYaw
|
|
10459
|
+
cam.beta = Math.max(0.01, Math.min(Math.PI - 0.01, cam.beta - dPitch))
|
|
10460
|
+
const o = this.cameraTargetOffset
|
|
10461
|
+
const c = Math.cos(dYaw)
|
|
10462
|
+
const sn = Math.sin(dYaw)
|
|
10463
|
+
const ox = o.x
|
|
10464
|
+
o.x = ox * c + o.z * sn
|
|
10465
|
+
o.z = -ox * sn + o.z * c
|
|
10466
|
+
}
|
|
10467
|
+
|
|
10403
10468
|
/** True while the orbit target is riding a model bone (setCameraFollow). */
|
|
10404
10469
|
isCameraFollowing(): boolean {
|
|
10405
10470
|
return this.cameraTargetModel !== null
|
|
@@ -13730,6 +13795,39 @@ export class Engine {
|
|
|
13730
13795
|
return true
|
|
13731
13796
|
}
|
|
13732
13797
|
|
|
13798
|
+
/**
|
|
13799
|
+
* Jelly eyes: her irises shrink and spring back as her lids move, swell as her
|
|
13800
|
+
* head turns or moves, and wobble back, and shine like a gem — two hard
|
|
13801
|
+
* glints, light glowing through the iris, deeper colour. MMD's 果冻眼, on any
|
|
13802
|
+
* PMX and under any eye graph. Null stills them again.
|
|
13803
|
+
*
|
|
13804
|
+
* Driven by her closing morphs (まばたき, the winks) and her head bone, never
|
|
13805
|
+
* her eyes' own turn, so eye tracking following the camera leaves it still.
|
|
13806
|
+
* The springs step on the scene clock, so an export bounces exactly as the
|
|
13807
|
+
* screen did. The iris only scales in place (see jelly-eyes.ts).
|
|
13808
|
+
*/
|
|
13809
|
+
setModelJellyEyes(modelName: string, options: JellyEyeOptions | null): boolean {
|
|
13810
|
+
const inst = this.modelInstances.get(modelName)
|
|
13811
|
+
if (!inst || !this.device) return false
|
|
13812
|
+
if (!options) {
|
|
13813
|
+
inst.jellyEyes = null
|
|
13814
|
+
clearJellyEyes(inst.objectLight)
|
|
13815
|
+
this.device.queue.writeBuffer(inst.lightBuffer, 0, inst.objectLight)
|
|
13816
|
+
return true
|
|
13817
|
+
}
|
|
13818
|
+
if (inst.jellyEyes) {
|
|
13819
|
+
inst.jellyEyes.strength = clampStrength(options.strength)
|
|
13820
|
+
inst.jellyEyes.idle = options.idle ?? true
|
|
13821
|
+
}
|
|
13822
|
+
else inst.jellyEyes = new JellyEyes(inst.model, options)
|
|
13823
|
+
return true
|
|
13824
|
+
}
|
|
13825
|
+
|
|
13826
|
+
getModelJellyEyes(modelName: string): Required<JellyEyeOptions> | null {
|
|
13827
|
+
const jelly = this.modelInstances.get(modelName)?.jellyEyes
|
|
13828
|
+
return jelly ? { strength: jelly.strength, idle: jelly.idle } : null
|
|
13829
|
+
}
|
|
13830
|
+
|
|
13733
13831
|
getModelCastShadow(modelName: string): boolean {
|
|
13734
13832
|
return this.modelInstances.get(modelName)?.castShadow ?? true
|
|
13735
13833
|
}
|
|
@@ -13800,6 +13898,12 @@ export class Engine {
|
|
|
13800
13898
|
verticesChanged = inst.model.update(deltaTime, inst.isStage || inst.isPlane ? false : this.ikEnabled)
|
|
13801
13899
|
inst.skinMatricesDirty = true
|
|
13802
13900
|
}
|
|
13901
|
+
// After the pose, so the springs read this frame's blink and eye turn.
|
|
13902
|
+
if (inst.jellyEyes) {
|
|
13903
|
+
inst.jellyEyes.step(deltaTime, inst.model)
|
|
13904
|
+
inst.jellyEyes.write(inst.objectLight)
|
|
13905
|
+
this.device.queue.writeBuffer(inst.lightBuffer, 48 * 4, inst.objectLight, 48, 24)
|
|
13906
|
+
}
|
|
13803
13907
|
animMs += performance.now() - tAnim
|
|
13804
13908
|
// Material morphs ride the same weight change as vertex morphs but land in
|
|
13805
13909
|
// uniform buffers, so they consume their own flag — a model whose only
|
|
@@ -15104,9 +15208,9 @@ export class Engine {
|
|
|
15104
15208
|
|
|
15105
15209
|
// Its ObjectLight: the world's ambient, and the layers its kind draws on —
|
|
15106
15210
|
// the cast on the character layer as well as the default one. Words:
|
|
15107
|
-
// layers [0..3], ambient flag [4..7], SH [8..43], fill [44..47]
|
|
15108
|
-
// materials/common.ts.
|
|
15109
|
-
const objectLight = new Float32Array(
|
|
15211
|
+
// layers [0..3], ambient flag [4..7], SH [8..43], fill [44..47], jelly
|
|
15212
|
+
// eyes [48..71] — see materials/common.ts.
|
|
15213
|
+
const objectLight = new Float32Array(72)
|
|
15110
15214
|
new Uint32Array(objectLight.buffer)[0] =
|
|
15111
15215
|
isStage || isPlane || isProp ? RENDERING_LAYER_DEFAULT : (RENDERING_LAYER_DEFAULT | RENDERING_LAYER_CHARACTER) >>> 0
|
|
15112
15216
|
const lightBuffer = this.device.createBuffer({
|
|
@@ -15142,6 +15246,7 @@ export class Engine {
|
|
|
15142
15246
|
model,
|
|
15143
15247
|
simulateWhileHidden: false,
|
|
15144
15248
|
castShadow: true,
|
|
15249
|
+
jellyEyes: null,
|
|
15145
15250
|
basePath,
|
|
15146
15251
|
assetReader,
|
|
15147
15252
|
gpuBuffers,
|
|
@@ -17397,8 +17502,16 @@ export class Engine {
|
|
|
17397
17502
|
py += pos.y
|
|
17398
17503
|
pz += pos.z
|
|
17399
17504
|
}
|
|
17400
|
-
|
|
17505
|
+
// The lag scales with how much the shot holds. Eased, the pivot trails
|
|
17506
|
+
// the bone by its speed × tau — nothing in a full-body shot, but in a
|
|
17507
|
+
// close-up of her eye it is most of the frame, and the eye swims out
|
|
17508
|
+
// of it as she moves. So: the full handheld lag once the frame is
|
|
17509
|
+
// FOLLOW_LAG_FULL_HALF tall (half height, model units — about a
|
|
17510
|
+
// full-body shot), shrinking linearly to rigid as the shot closes in.
|
|
17511
|
+
const half = this.camera.radius * Math.tan(this.camera.fov / 2)
|
|
17512
|
+
const tau = this.cameraFollowSmoothing * Math.min(1, half / FOLLOW_LAG_FULL_HALF)
|
|
17401
17513
|
const f = this.cameraFollowPos
|
|
17514
|
+
if (this.cameraFollowTurn) this.turnWithFollowBone(m, tau, deltaTime)
|
|
17402
17515
|
if (tau > 0 && this.cameraFollowSeeded) {
|
|
17403
17516
|
// Exponential lag toward the bone: the handheld-camera feel. The
|
|
17404
17517
|
// orbit pivot trails the target and eases in, never snapping.
|
package/src/graph/slots.ts
CHANGED
|
@@ -57,6 +57,16 @@ const EYE_REAR_GATE = `
|
|
|
57
57
|
}
|
|
58
58
|
`
|
|
59
59
|
|
|
60
|
+
// Eye's jelly (Engine.setModelJellyEyes): the vertex shader moves the iris
|
|
61
|
+
// itself; the fragment only adds the glints, computed once the lighting context
|
|
62
|
+
// exists and added in the epilogue after the graph. Off, they are zero.
|
|
63
|
+
const PLAIN_SAMPLE = ` let tex_s = textureSample(diffuseTexture, diffuseSampler, input.uv);
|
|
64
|
+
`
|
|
65
|
+
const EYE_JELLY_SAMPLE = ` let rz_jelly = rzJellyEye(input.restPos);
|
|
66
|
+
${PLAIN_SAMPLE}`
|
|
67
|
+
const EYE_JELLY_GLOW = ` let rz_jelly_glow = rzJellyGlow(rz_jelly, tex_color, tex_s.a, v, l, sun, shadow);
|
|
68
|
+
`
|
|
69
|
+
|
|
60
70
|
// ── Adjust-tier uniforms — fixed 16-vec4f block (256 B) shared by the single material
|
|
61
71
|
// bind group layout; non-graph draws bind a zero buffer. ──
|
|
62
72
|
const STYLE_UNIFORMS_WGSL = `struct StyleUniforms { p: array<vec4f, 16> };
|
|
@@ -104,8 +114,7 @@ function prelude(renderClass: RenderClass, alphaMode: AlphaMode, blend: StyleBle
|
|
|
104
114
|
const flip =
|
|
105
115
|
renderClass === "eye" ? "" : "\n n = select(-n, n, dot(n, v) >= 0.0);"
|
|
106
116
|
return `@fragment fn fs(input: VertexOutput) -> FSOut {
|
|
107
|
-
|
|
108
|
-
// MMD alpha semantics: material alpha × texture alpha.
|
|
117
|
+
${renderClass === "eye" ? EYE_JELLY_SAMPLE : PLAIN_SAMPLE} // MMD alpha semantics: material alpha × texture alpha.
|
|
109
118
|
let alpha = material.alpha * tex_s.a;
|
|
110
119
|
${discard}
|
|
111
120
|
|
|
@@ -152,7 +161,7 @@ ${gate}
|
|
|
152
161
|
// The normal the lamps' diffuse layer is lit by, for a principled walk to
|
|
153
162
|
// compute it on the way (rzLightsDiffuseOnce). n is final from here on.
|
|
154
163
|
_rzLampN = n;
|
|
155
|
-
|
|
164
|
+
${renderClass === "eye" ? EYE_JELLY_GLOW : ""}
|
|
156
165
|
`
|
|
157
166
|
}
|
|
158
167
|
|
|
@@ -205,7 +214,7 @@ function epilogue(renderClass: RenderClass, alphaMode: AlphaMode, hasOpacity: bo
|
|
|
205
214
|
// it is emission, not a surface colour, so nothing may ramp or shadow it. Zero
|
|
206
215
|
// on every fragment of every material that is not dissolving, which is what
|
|
207
216
|
// keeps this out of the way of a scene that never uses it.
|
|
208
|
-
const BURN = ` + RZ_BURN_COLOR * rz_burn`
|
|
217
|
+
const BURN = ` + RZ_BURN_COLOR * rz_burn${renderClass === "eye" ? " + rz_jelly_glow" : ""}`
|
|
209
218
|
// The scene fog, last, as the game lays it over a lit surface; an
|
|
210
219
|
// emission-only graph takes none (the game's effect shaders have no fog).
|
|
211
220
|
// A premultiplied colour takes its fog premultiplied too: the haze a pane
|
package/src/index.ts
CHANGED
|
@@ -220,6 +220,7 @@ export {
|
|
|
220
220
|
*/
|
|
221
221
|
export { EFFECT_MATH_API, PARTICLE_STRUCT_WGSL } from "./shaders/passes/hosted-api"
|
|
222
222
|
export type { EyeTrackingOptions } from "./model"
|
|
223
|
+
export type { JellyEyeOptions } from "./jelly-eyes"
|
|
223
224
|
|
|
224
225
|
/**
|
|
225
226
|
* The game's own materials (src/unity): a stage package drawn by its translated
|