reze-engine 0.54.16 → 0.55.1
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/camera.d.ts +13 -0
- package/dist/camera.d.ts.map +1 -1
- package/dist/camera.js +53 -2
- package/dist/engine.d.ts +317 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1263 -27
- package/dist/graph/presets/pool_floor.d.ts +3 -0
- package/dist/graph/presets/pool_floor.d.ts.map +1 -0
- package/dist/graph/presets/pool_floor.js +42 -0
- package/dist/graph/presets/water.d.ts +3 -0
- package/dist/graph/presets/water.d.ts.map +1 -0
- package/dist/graph/presets/water.js +31 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -0
- package/dist/overlay.d.ts +200 -0
- package/dist/overlay.d.ts.map +1 -0
- package/dist/overlay.js +806 -0
- package/dist/physics/autofit.d.ts +147 -0
- package/dist/physics/autofit.d.ts.map +1 -0
- package/dist/physics/autofit.js +501 -0
- package/dist/pmx-document.d.ts +218 -0
- package/dist/pmx-document.d.ts.map +1 -0
- package/dist/pmx-document.js +685 -0
- package/dist/shaders/passes/composite.d.ts.map +1 -1
- package/dist/shaders/passes/composite.js +18 -1
- package/dist/shaders/passes/field-blit.d.ts +26 -0
- package/dist/shaders/passes/field-blit.d.ts.map +1 -0
- package/dist/shaders/passes/field-blit.js +65 -0
- package/dist/shaders/passes/ground-noise.d.ts +7 -0
- package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
- package/dist/shaders/passes/ground-noise.js +88 -0
- package/dist/shaders/passes/ground.d.ts.map +1 -1
- package/dist/shaders/passes/ground.js +63 -17
- package/dist/shaders/passes/overlay.d.ts +3 -0
- package/dist/shaders/passes/overlay.d.ts.map +1 -0
- package/dist/shaders/passes/overlay.js +164 -0
- package/dist/shaders/passes/sim.d.ts +34 -0
- package/dist/shaders/passes/sim.d.ts.map +1 -0
- package/dist/shaders/passes/sim.js +169 -0
- package/dist/shaders/passes/wireframe.d.ts +2 -0
- package/dist/shaders/passes/wireframe.d.ts.map +1 -0
- package/dist/shaders/passes/wireframe.js +107 -0
- package/dist/shaders/score-api.d.ts +10 -0
- package/dist/shaders/score-api.d.ts.map +1 -0
- package/dist/shaders/score-api.js +114 -0
- package/package.json +1 -1
- package/src/camera.ts +60 -2
- package/src/engine.ts +1359 -25
- package/src/index.ts +50 -0
- package/src/model.ts +9 -0
- package/src/overlay.ts +1000 -0
- package/src/pmx-document.ts +882 -0
- package/src/shaders/passes/composite.ts +18 -1
- package/src/shaders/passes/ground.ts +65 -17
- package/src/shaders/passes/overlay.ts +166 -0
- package/src/shaders/passes/wireframe.ts +108 -0
package/dist/camera.d.ts
CHANGED
|
@@ -35,6 +35,19 @@ export declare class Camera {
|
|
|
35
35
|
maxZ: number;
|
|
36
36
|
lowerBetaLimit: number;
|
|
37
37
|
upperBetaLimit: number;
|
|
38
|
+
/**
|
|
39
|
+
* Orbit roll, radians — the lean the orbit itself cannot state.
|
|
40
|
+
*
|
|
41
|
+
* alpha and beta are a yaw and a pitch about an upright axis, and lookAt is
|
|
42
|
+
* handed world up, so an orbiting shot is level by construction. This tips
|
|
43
|
+
* that up vector about the eye→target line, which leaves WHERE the camera is
|
|
44
|
+
* and WHAT it looks at exactly as they were.
|
|
45
|
+
*
|
|
46
|
+
* That is the whole reason it lives here rather than in a pose pushed from
|
|
47
|
+
* outside: a rolled shot still follows a bone, still orbits, still zooms. A
|
|
48
|
+
* pose replaces all of that with one frozen answer.
|
|
49
|
+
*/
|
|
50
|
+
roll: number;
|
|
38
51
|
private _viewMat;
|
|
39
52
|
private _projMat;
|
|
40
53
|
vmdDriven: boolean;
|
package/dist/camera.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../src/camera.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAQ,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAyBpD,qBAAa,MAAM;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,IAAI,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAI;IAClB;;;oFAGgF;IAChF,IAAI,EAAE,MAAM,CAAiB;IAC7B,GAAG,EAAE,MAAM,CAAU;IACrB;+EAC2E;IAC3E,SAAS,UAAQ;IAGjB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,iBAAiB,CAAY;IACrC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,oBAAoB,CAAY;IAGxC,kBAAkB,EAAE,MAAM,CAAQ;IAClC,cAAc,EAAE,MAAM,CAAS;IAC/B,cAAc,EAAE,MAAM,CAAO;IAC7B,cAAc,EAAE,MAAM,CAAO;IAC7B,IAAI,EAAE,MAAM,CAAO;IACnB,IAAI,EAAE,MAAM,CAAU;IACtB,cAAc,EAAE,MAAM,CAAQ;IAC9B,cAAc,EAAE,MAAM,CAAkB;
|
|
1
|
+
{"version":3,"file":"camera.d.ts","sourceRoot":"","sources":["../src/camera.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAQ,IAAI,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAyBpD,qBAAa,MAAM;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,IAAI,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAI;IAClB;;;oFAGgF;IAChF,IAAI,EAAE,MAAM,CAAiB;IAC7B,GAAG,EAAE,MAAM,CAAU;IACrB;+EAC2E;IAC3E,SAAS,UAAQ;IAGjB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,WAAW,CAAiB;IACpC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,WAAW,CAAsB;IACzC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,YAAY,CAAiB;IACrC,OAAO,CAAC,eAAe,CAAsB;IAC7C,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,iBAAiB,CAAY;IACrC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,oBAAoB,CAAY;IAGxC,kBAAkB,EAAE,MAAM,CAAQ;IAClC,cAAc,EAAE,MAAM,CAAS;IAC/B,cAAc,EAAE,MAAM,CAAO;IAC7B,cAAc,EAAE,MAAM,CAAO;IAC7B,IAAI,EAAE,MAAM,CAAO;IACnB,IAAI,EAAE,MAAM,CAAU;IACtB,cAAc,EAAE,MAAM,CAAQ;IAC9B,cAAc,EAAE,MAAM,CAAkB;IACxC;;;;;;;;;;;OAWG;IACH,IAAI,EAAE,MAAM,CAAI;IAGhB,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAiC;IAKjD,SAAS,EAAE,OAAO,CAAQ;IAC1B,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,YAAY,CAAuB;gBAE/B,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAE,MAAoB;IAmBhG,WAAW,IAAI,IAAI;IAQnB;wFACoF;IACpF,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAOpC,0FAA0F;IAC1F;;;;;;;;;;OAUG;IACH,OAAO,IAAI,UAAU;IAuBrB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI;IAelC,OAAO,CAAC,MAAM;IAUd;;;;;;;;;;;OAWG;IACH,cAAc,IAAI,IAAI;IAItB,aAAa,IAAI,IAAI;IAqErB,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,SAAS;IAiBjB,kFAAkF;IAClF,OAAO,CAAC,mBAAmB;IAK3B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,oBAAoB;IAM5B,mBAAmB,IAAI,IAAI;IAW3B,aAAa,CAAC,MAAM,EAAE,iBAAiB;IAiBvC,aAAa;IAkBb,cAAc,CAAC,MAAM,EAAE,OAAO;IAS9B,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;IAsBnB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,WAAW;IAuFnB,OAAO,CAAC,UAAU;CA+BnB"}
|
package/dist/camera.js
CHANGED
|
@@ -54,6 +54,19 @@ export class Camera {
|
|
|
54
54
|
this.maxZ = FAR_CAP;
|
|
55
55
|
this.lowerBetaLimit = 0.001;
|
|
56
56
|
this.upperBetaLimit = Math.PI - 0.001;
|
|
57
|
+
/**
|
|
58
|
+
* Orbit roll, radians — the lean the orbit itself cannot state.
|
|
59
|
+
*
|
|
60
|
+
* alpha and beta are a yaw and a pitch about an upright axis, and lookAt is
|
|
61
|
+
* handed world up, so an orbiting shot is level by construction. This tips
|
|
62
|
+
* that up vector about the eye→target line, which leaves WHERE the camera is
|
|
63
|
+
* and WHAT it looks at exactly as they were.
|
|
64
|
+
*
|
|
65
|
+
* That is the whole reason it lives here rather than in a pose pushed from
|
|
66
|
+
* outside: a rolled shot still follows a bone, still orbits, still zooms. A
|
|
67
|
+
* pose replaces all of that with one frozen answer.
|
|
68
|
+
*/
|
|
69
|
+
this.roll = 0;
|
|
57
70
|
// Reused each frame so getViewMatrix/getProjectionMatrix don't allocate a Mat4 per call.
|
|
58
71
|
this._viewMat = new Mat4(new Float32Array(16));
|
|
59
72
|
this._projMat = new Mat4(new Float32Array(16));
|
|
@@ -126,7 +139,10 @@ export class Camera {
|
|
|
126
139
|
// NEGATIVE to match: in a VMD the camera sits behind its target.
|
|
127
140
|
return {
|
|
128
141
|
target: new Vec3(this.target.x, this.target.y, this.target.z),
|
|
129
|
-
|
|
142
|
+
// z carries the roll, so a rolled orbit exports and reads back as the
|
|
143
|
+
// same shot rather than a level one — the AE rig and the VMD writer both
|
|
144
|
+
// take this channel.
|
|
145
|
+
rotation: new Vec3(this.beta - Math.PI / 2, -this.alpha, this.roll),
|
|
130
146
|
distance: -this.radius,
|
|
131
147
|
fov: this.fov,
|
|
132
148
|
};
|
|
@@ -199,7 +215,42 @@ export class Camera {
|
|
|
199
215
|
}
|
|
200
216
|
const eye = this.getPosition();
|
|
201
217
|
const t = this.target;
|
|
202
|
-
|
|
218
|
+
if (this.roll === 0) {
|
|
219
|
+
Mat4.lookAtInto(this._viewMat.values, eye.x, eye.y, eye.z, t.x, t.y, t.z, 0, 1, 0);
|
|
220
|
+
return this._viewMat;
|
|
221
|
+
}
|
|
222
|
+
// Roll = the up vector, turned about the view axis. Build the shot's own
|
|
223
|
+
// basis first (forward, then right, then a true up), because world up is
|
|
224
|
+
// only the camera's up while the shot is level — which is the thing this is
|
|
225
|
+
// about to stop being.
|
|
226
|
+
let fx = t.x - eye.x;
|
|
227
|
+
let fy = t.y - eye.y;
|
|
228
|
+
let fz = t.z - eye.z;
|
|
229
|
+
const fl = Math.hypot(fx, fy, fz) || 1;
|
|
230
|
+
fx /= fl;
|
|
231
|
+
fy /= fl;
|
|
232
|
+
fz /= fl;
|
|
233
|
+
// right = forward × worldUp, with worldUp = (0,1,0), which is (−fz, 0, fx).
|
|
234
|
+
//
|
|
235
|
+
// WRITTEN THE OTHER WAY ROUND ONCE, and it did not fail quietly: that is
|
|
236
|
+
// worldUp × forward, so `right` pointed left, `up` below came out as right ×
|
|
237
|
+
// forward = DOWN, and the camera turned upside down the moment roll left
|
|
238
|
+
// zero. Degenerate only when the shot looks straight up or down, where
|
|
239
|
+
// beta's own limits already keep it from arriving.
|
|
240
|
+
let rx = -fz;
|
|
241
|
+
let ry = 0;
|
|
242
|
+
let rz = fx;
|
|
243
|
+
const rl = Math.hypot(rx, ry, rz) || 1;
|
|
244
|
+
rx /= rl;
|
|
245
|
+
ry /= rl;
|
|
246
|
+
rz /= rl;
|
|
247
|
+
// up = right × forward
|
|
248
|
+
const ux = ry * fz - rz * fy;
|
|
249
|
+
const uy = rz * fx - rx * fz;
|
|
250
|
+
const uz = rx * fy - ry * fx;
|
|
251
|
+
const c = Math.cos(this.roll);
|
|
252
|
+
const sn = Math.sin(this.roll);
|
|
253
|
+
Mat4.lookAtInto(this._viewMat.values, eye.x, eye.y, eye.z, t.x, t.y, t.z, ux * c + rx * sn, uy * c + ry * sn, uz * c + rz * sn);
|
|
203
254
|
return this._viewMat;
|
|
204
255
|
}
|
|
205
256
|
// Get camera's right and up vectors for panning
|
package/dist/engine.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { type ParamKey } from "./param-track";
|
|
|
9
9
|
import { type EffectWindow } from "./effect-schedule";
|
|
10
10
|
import { type HdrImage } from "./hdr";
|
|
11
11
|
import { type LyricLine, type LyricRect } from "./shaders/lyrics-api";
|
|
12
|
+
import { type BoneOverlayOptions, type JointOverlayOptions, type OverlayPrimitive, type RigidbodyOverlayOptions } from "./overlay";
|
|
12
13
|
import { type CompileOptions, type StyleSlot } from "./graph/compile";
|
|
13
14
|
import type { AlphaMode, RenderClass } from "./graph/render-class";
|
|
14
15
|
import type { ApplyStyleGroupResult, ApplyStyleGroupsResult, StyleGroup } from "./graph/style-group";
|
|
@@ -428,6 +429,19 @@ interface ModelInstance {
|
|
|
428
429
|
materialMorphTargets: MaterialMorphTarget[] | null;
|
|
429
430
|
/** The same targets by PMX material index, so a named offset is one lookup. */
|
|
430
431
|
materialMorphByIndex: Map<number, MaterialMorphTarget> | null;
|
|
432
|
+
/** The mesh's unique edges as a line-list index buffer, built on first use.
|
|
433
|
+
* Deduplicated: an interior edge belongs to two triangles, so drawing the
|
|
434
|
+
* triangle list's edges directly would draw most of the mesh twice.
|
|
435
|
+
*
|
|
436
|
+
* Keyed by the material the edges were cut from, "" for the whole mesh. A
|
|
437
|
+
* material is a consecutive index run, so scoping is a slice of the same
|
|
438
|
+
* build — and both stay cached, because narrowing to one material and
|
|
439
|
+
* widening back out is the loop somebody auditing a model is in. */
|
|
440
|
+
wireEdges: Map<string, {
|
|
441
|
+
buffer: GPUBuffer;
|
|
442
|
+
count: number;
|
|
443
|
+
bindGroup: GPUBindGroup;
|
|
444
|
+
} | null>;
|
|
431
445
|
physics: RezePhysics | null;
|
|
432
446
|
vertexBufferNeedsUpdate: boolean;
|
|
433
447
|
gpuMorph: GpuMorph | null;
|
|
@@ -530,7 +544,67 @@ export declare class Engine {
|
|
|
530
544
|
private selectionEdgeUniformBuffer;
|
|
531
545
|
private selectionEdgePassDescriptor;
|
|
532
546
|
private selectionSampler;
|
|
547
|
+
private overlayVertexBuffer;
|
|
548
|
+
private overlayInstanceBuffer;
|
|
549
|
+
private overlayInstanceCapacity;
|
|
550
|
+
private overlayPipeline;
|
|
551
|
+
private overlaySolidPipeline;
|
|
552
|
+
private overlayBindGroup;
|
|
553
|
+
private overlayGeometry;
|
|
554
|
+
private overlayPassDescriptor;
|
|
555
|
+
private overlayDepthTexture;
|
|
556
|
+
private overlayMsaaTexture;
|
|
557
|
+
private overlayResolveTexture;
|
|
558
|
+
private overlayUniformBuffer;
|
|
559
|
+
private overlayUniformData;
|
|
560
|
+
private overlayCompositePipeline;
|
|
561
|
+
private overlayCompositeLayout;
|
|
562
|
+
private overlayCompositeBindGroup;
|
|
563
|
+
private overlayCompositePassDescriptor;
|
|
564
|
+
private overlayTargetSize;
|
|
565
|
+
/** The overlay renders multisampled into its own layer; the scene's own depth
|
|
566
|
+
* is discarded before the composite (see the depthRead note in render), so it
|
|
567
|
+
* could not have shared either that or the single-sample swapchain. */
|
|
568
|
+
private static readonly OVERLAY_SAMPLE_COUNT;
|
|
569
|
+
/** Dash period in device pixels — dashes are geometry, so this is only the
|
|
570
|
+
* reference the dashedLine shape is cut against. */
|
|
571
|
+
private static readonly OVERLAY_DASH_PERIOD_PX;
|
|
572
|
+
private overlayLayers;
|
|
573
|
+
private overlayBones;
|
|
574
|
+
private overlayBodies;
|
|
575
|
+
private overlayJoints;
|
|
576
|
+
private overlayVertices;
|
|
577
|
+
private wireframePipeline;
|
|
578
|
+
private wireframeDepthPipeline;
|
|
579
|
+
private wireframeUniformBuffer;
|
|
580
|
+
private wireframeBindGroup;
|
|
581
|
+
/** The seam pass draws in the same frame at a different stroke and alpha, and
|
|
582
|
+
* every queue write lands before the command buffer runs — writing the one
|
|
583
|
+
* buffer twice would give both draws the second value. */
|
|
584
|
+
private wireframeSeamUniformBuffer;
|
|
585
|
+
private wireframeSeamBindGroup;
|
|
586
|
+
/** Same reason: the hovered material draws its own stroke, self-occluding, in
|
|
587
|
+
* the same frame as the base mesh and the seams. */
|
|
588
|
+
private wireframeHoverUniformBuffer;
|
|
589
|
+
private wireframeHoverBindGroup;
|
|
590
|
+
private wireframeSkinLayout;
|
|
591
|
+
private wireframeColorData;
|
|
592
|
+
/** Rebuilt every frame into these, grouped by shape so each shape is one draw. */
|
|
593
|
+
private overlayByShape;
|
|
594
|
+
private overlayScratch;
|
|
595
|
+
private bonePickScratch;
|
|
596
|
+
private overlayInstanceData;
|
|
533
597
|
private selectedBone;
|
|
598
|
+
/** The material a pointer is currently over, or null. Cheap and separate from
|
|
599
|
+
* setVertexOverlay on purpose — the same split setSelectedBone takes from
|
|
600
|
+
* setBoneOverlay — because this is written every frame the pointer moves and
|
|
601
|
+
* the overlay's own option object is not something to reconstruct that often. */
|
|
602
|
+
private hoverMaterial;
|
|
603
|
+
/** The transform gizmo follows setSelectedBone, which is also what selects a
|
|
604
|
+
* bone to INSPECT. A model editor selects bones constantly and poses them
|
|
605
|
+
* rarely, so the two need separating: off leaves selection working and takes
|
|
606
|
+
* the handles away. */
|
|
607
|
+
private gizmoEnabled;
|
|
534
608
|
private gizmoVertexBuffer;
|
|
535
609
|
private gizmoTransformBuffer;
|
|
536
610
|
private gizmoPipeline;
|
|
@@ -1094,6 +1168,28 @@ export declare class Engine {
|
|
|
1094
1168
|
setColorGrading(patch: Partial<ColorGradingOptions>): void;
|
|
1095
1169
|
/** Current grade (for serialization into a scene descriptor). */
|
|
1096
1170
|
getColorGrading(): ColorGradingOptions;
|
|
1171
|
+
/** Sensor grain: how much, and whether it moves. */
|
|
1172
|
+
private grain;
|
|
1173
|
+
/**
|
|
1174
|
+
* Film grain over the rendered scene, 0–1.
|
|
1175
|
+
*
|
|
1176
|
+
* A property of a SENSOR, so it belongs to the camera rather than to any one
|
|
1177
|
+
* subject, and it lands on what the engine drew and on nothing else — never on
|
|
1178
|
+
* a background image or a backdrop video, which arrived with grain of their
|
|
1179
|
+
* own and would be graded rather than matched by a second helping.
|
|
1180
|
+
*
|
|
1181
|
+
* `animated` false freezes it. A still photograph's grain does not move, and
|
|
1182
|
+
* noise crawling over a frozen picture makes the rendering look more alive
|
|
1183
|
+
* than the thing it is standing in.
|
|
1184
|
+
*
|
|
1185
|
+
* Costs one hash per pixel in a pass that already runs, and nothing at all at
|
|
1186
|
+
* zero — the branch is on a uniform.
|
|
1187
|
+
*/
|
|
1188
|
+
setFilmGrain(amount: number, animated?: boolean): void;
|
|
1189
|
+
getFilmGrain(): Readonly<{
|
|
1190
|
+
amount: number;
|
|
1191
|
+
animated: boolean;
|
|
1192
|
+
}>;
|
|
1097
1193
|
setViewTransformOptions(patch: Partial<ViewTransformOptions>): void;
|
|
1098
1194
|
/**
|
|
1099
1195
|
* Whether bloom will actually reach the frame this frame.
|
|
@@ -1643,6 +1739,7 @@ export declare class Engine {
|
|
|
1643
1739
|
setRenderSize(size: null): void;
|
|
1644
1740
|
private handleResize;
|
|
1645
1741
|
private setupGizmo;
|
|
1742
|
+
private setupOverlay;
|
|
1646
1743
|
private setupCamera;
|
|
1647
1744
|
/** Set static camera look-at / orbit center. Clears any model follow binding. */
|
|
1648
1745
|
setCameraTarget(v: Vec3): void;
|
|
@@ -1650,6 +1747,32 @@ export declare class Engine {
|
|
|
1650
1747
|
setCameraTarget(model: Model | null, boneName: string, offset?: Vec3): void;
|
|
1651
1748
|
/** Souls-style follow cam: orbit center tracks a model bone each frame. Shorthand for setCameraTarget(model, boneName, offset). */
|
|
1652
1749
|
setCameraFollow(model: Model | null, boneName?: string, offset?: Vec3, smoothing?: number): void;
|
|
1750
|
+
/** Whether a loaded camera track is allowed to drive (setCameraVmdEnabled).
|
|
1751
|
+
* Held separately from `camera.vmdDriven` because that flag now answers to
|
|
1752
|
+
* two sources, and a track switched off must stay off when the other one
|
|
1753
|
+
* releases the camera. */
|
|
1754
|
+
private cameraVmdEnabled;
|
|
1755
|
+
/** A pose pushed in from outside — see setCameraPose. Reapplied every frame,
|
|
1756
|
+
* so it outranks the orbit AND a loaded track for as long as it is set. */
|
|
1757
|
+
private cameraPoseOverride;
|
|
1758
|
+
/** The one place that decides who is holding the camera. An external pose
|
|
1759
|
+
* wins; a track drives when it is loaded and enabled; otherwise orbit. */
|
|
1760
|
+
private refreshCameraDrive;
|
|
1761
|
+
/**
|
|
1762
|
+
* Aim the camera from outside — a solved match-move, a saved shot, a rig
|
|
1763
|
+
* driving the view from the host's own clock.
|
|
1764
|
+
*
|
|
1765
|
+
* The exact partner of `getCameraPose`, and the same five channels: the shot
|
|
1766
|
+
* as MMD states it, roll included. Orbit cannot express roll, so this is the
|
|
1767
|
+
* only way a tilted camera reaches the engine.
|
|
1768
|
+
*
|
|
1769
|
+
* Reapplied every frame while set, which makes it authoritative rather than
|
|
1770
|
+
* advisory — nothing the transport or a loaded track does moves it. Pass null
|
|
1771
|
+
* to release, and whatever was driving before takes the camera back.
|
|
1772
|
+
*/
|
|
1773
|
+
setCameraPose(pose: CameraPose | null): void;
|
|
1774
|
+
/** The pose currently forced from outside, or null when nothing is. */
|
|
1775
|
+
getCameraPoseOverride(): CameraPose | null;
|
|
1653
1776
|
/** Load a camera VMD (dedicated camera file, or any VMD's camera block) and drive the shot
|
|
1654
1777
|
* from it. Default-on once a non-empty track loads; toggle with setCameraVmdEnabled. */
|
|
1655
1778
|
loadCameraVmd(url: string): Promise<void>;
|
|
@@ -1774,12 +1897,42 @@ export declare class Engine {
|
|
|
1774
1897
|
private transportTime;
|
|
1775
1898
|
/** Current orbit eye position (spherical coords resolved to a point). */
|
|
1776
1899
|
getCameraPosition(): Vec3;
|
|
1900
|
+
/**
|
|
1901
|
+
* The live orbit, read in ONE call.
|
|
1902
|
+
*
|
|
1903
|
+
* A host that stores the shot has to be able to ask where the camera actually
|
|
1904
|
+
* IS, because a drag on the canvas moves this and nothing else — and a
|
|
1905
|
+
* document that never asks will happily write back the angle it last set,
|
|
1906
|
+
* discarding whatever the person just did with the mouse. Reading the four
|
|
1907
|
+
* separately invites a torn set across a frame boundary; this cannot tear.
|
|
1908
|
+
*
|
|
1909
|
+
* `target` is the orbit's own centre. While the engine is following a bone
|
|
1910
|
+
* that point rides the bone, so a caller storing a FOLLOW offset must keep its
|
|
1911
|
+
* own and take only the angles from here.
|
|
1912
|
+
*/
|
|
1913
|
+
getCameraOrbit(): {
|
|
1914
|
+
alpha: number;
|
|
1915
|
+
beta: number;
|
|
1916
|
+
distance: number;
|
|
1917
|
+
target: Vec3;
|
|
1918
|
+
};
|
|
1777
1919
|
getCameraDistance(): number;
|
|
1778
1920
|
setCameraDistance(d: number): void;
|
|
1779
1921
|
getCameraAlpha(): number;
|
|
1780
1922
|
setCameraAlpha(a: number): void;
|
|
1781
1923
|
getCameraBeta(): number;
|
|
1782
1924
|
setCameraBeta(b: number): void;
|
|
1925
|
+
/**
|
|
1926
|
+
* Roll the orbiting shot, radians — the lean alpha and beta cannot state.
|
|
1927
|
+
*
|
|
1928
|
+
* Tips the up vector about the eye→target line, so the camera stays exactly
|
|
1929
|
+
* where it was and keeps looking at exactly what it looked at. Everything the
|
|
1930
|
+
* orbit does still works underneath it: following a bone, dragging, zooming.
|
|
1931
|
+
*
|
|
1932
|
+
* A camera VMD carries its own roll and ignores this while it drives.
|
|
1933
|
+
*/
|
|
1934
|
+
setCameraRoll(r: number): void;
|
|
1935
|
+
getCameraRoll(): number;
|
|
1783
1936
|
/** Vertical field of view in radians (default π/4). While a camera VMD
|
|
1784
1937
|
* drives the view it animates fov itself; the orbit value set here is
|
|
1785
1938
|
* restored when the VMD releases the camera. */
|
|
@@ -1836,6 +1989,16 @@ export declare class Engine {
|
|
|
1836
1989
|
/** Mirror softness, 0–1: 0 a polished mirror, 1 the softest blur level,
|
|
1837
1990
|
* scaled by how far the reflected geometry sits behind the surface. */
|
|
1838
1991
|
mirrorBlur?: number;
|
|
1992
|
+
/** How soft the received shadow's edge is, 0–1. 0 (default) is the sharp
|
|
1993
|
+
* kernel this has always used, to the bit; 1 spreads the taps fourteen
|
|
1994
|
+
* times as wide, which is the edge an overcast sky throws.
|
|
1995
|
+
*
|
|
1996
|
+
* A property of the LIGHT, applied where the light is received: the sun
|
|
1997
|
+
* in a scene is either a point source with a hard edge or a sky with
|
|
1998
|
+
* none, and a floor that always answers "hard" can only match one of
|
|
1999
|
+
* them. Above 0 the taps go from nine to sixteen, so leave it at 0 for
|
|
2000
|
+
* scenes that want the sharp edge and pay nothing. */
|
|
2001
|
+
shadowSoftness?: number;
|
|
1839
2002
|
}): void;
|
|
1840
2003
|
/**
|
|
1841
2004
|
* The scene's positional lights — an ADDITIVE layer over the sun, which stays
|
|
@@ -1862,6 +2025,12 @@ export declare class Engine {
|
|
|
1862
2025
|
}[] | null): void;
|
|
1863
2026
|
/** How many positional lights the scene is carrying. */
|
|
1864
2027
|
getLightCount(): number;
|
|
2028
|
+
/** Guarded, unlike most private writers here, because its callers are not:
|
|
2029
|
+
* setWorld/setSun are public and can be called before init() finishes
|
|
2030
|
+
* assigning `device` — a scene-settings effect firing on mount races the
|
|
2031
|
+
* engine's own async setup. The state write still lands immediately either
|
|
2032
|
+
* way; only the GPU upload defers, and setupLighting's own writeWorld/
|
|
2033
|
+
* writeSun calls during init pick up whatever was already set. */
|
|
1865
2034
|
private updateLightBuffer;
|
|
1866
2035
|
getStats(): EngineStats;
|
|
1867
2036
|
runRenderLoop(callback?: () => void): void;
|
|
@@ -2001,7 +2170,100 @@ export declare class Engine {
|
|
|
2001
2170
|
getModelTransform(name: string): ModelTransform | null;
|
|
2002
2171
|
markVertexBufferDirty(modelNameOrModel?: string | Model): void;
|
|
2003
2172
|
setSelectedMaterial(modelName: string | null, materialName: string | null): void;
|
|
2173
|
+
/** Show the transform gizmo on the selected bone. On by default. */
|
|
2174
|
+
setGizmoEnabled(on: boolean): void;
|
|
2175
|
+
/** A pointer-driven preview of a pick, not a pick itself — see pickMaterial
|
|
2176
|
+
* for the click that actually selects one. Cheap: a field write, nothing
|
|
2177
|
+
* rebuilt, safe to call every frame the pointer is over the canvas. */
|
|
2178
|
+
setHoveredMaterial(modelName: string | null, materialName: string | null): void;
|
|
2004
2179
|
setSelectedBone(modelName: string | null, boneName: string | null): void;
|
|
2180
|
+
/**
|
|
2181
|
+
* Replace one named layer of overlay primitives. World space, drawn as given
|
|
2182
|
+
* until it is replaced. An empty list removes the layer.
|
|
2183
|
+
*/
|
|
2184
|
+
setOverlay(layer: string, primitives: OverlayPrimitive[]): void;
|
|
2185
|
+
/** Drop one named layer, or every one. Live layers keep drawing. */
|
|
2186
|
+
clearOverlay(layer?: string): void;
|
|
2187
|
+
/**
|
|
2188
|
+
* The bone whose marker is nearest a point on the canvas, or null.
|
|
2189
|
+
*
|
|
2190
|
+
* On the CPU, and exact. A few hundred bones with known world positions is a
|
|
2191
|
+
* loop, not a render pass — and having the answer synchronously is what makes
|
|
2192
|
+
* cycling through overlapping bones possible at all. Only VERTICES justify GPU
|
|
2193
|
+
* picking, at tens of thousands.
|
|
2194
|
+
*
|
|
2195
|
+
* `x`/`y` are CSS pixels relative to the canvas, which is what a MouseEvent
|
|
2196
|
+
* gives once getBoundingClientRect is subtracted.
|
|
2197
|
+
*
|
|
2198
|
+
* It projects boneMarkerPositions, the same points the overlay draws markers
|
|
2199
|
+
* at, so the hit box cannot drift away from the circle you are aiming at.
|
|
2200
|
+
*/
|
|
2201
|
+
pickBone(x: number, y: number, options?: {
|
|
2202
|
+
radiusPx?: number;
|
|
2203
|
+
modelName?: string;
|
|
2204
|
+
}): {
|
|
2205
|
+
modelName: string;
|
|
2206
|
+
boneName: string;
|
|
2207
|
+
boneIndex: number;
|
|
2208
|
+
} | null;
|
|
2209
|
+
/** Skinned positions for picking, grown on demand. One click's worth of work
|
|
2210
|
+
* reused across clicks — a model's vertex count does not change. */
|
|
2211
|
+
private materialPickScratch;
|
|
2212
|
+
/**
|
|
2213
|
+
* The material under a point on the canvas, or null for a miss.
|
|
2214
|
+
*
|
|
2215
|
+
* On the CPU, like pickBone, and for the same reason: a click (or a hover) is
|
|
2216
|
+
* rare and an answer you have synchronously is worth more than one that
|
|
2217
|
+
* arrives a frame later. Tens of thousands of triangles is a loop that costs
|
|
2218
|
+
* a few milliseconds ONCE, against a GPU id pass that costs an attachment and
|
|
2219
|
+
* a readback every frame whether anyone is pointing at the model or not.
|
|
2220
|
+
*
|
|
2221
|
+
* Skinned on the CPU with getSkinMatrices — the same matrices the vertex
|
|
2222
|
+
* shader uses — so the pick lands on the POSED mesh. Bind-pose geometry would
|
|
2223
|
+
* be right on a T-posed model and wrong on every animated one, which is
|
|
2224
|
+
* exactly when someone is clicking around a costume.
|
|
2225
|
+
*
|
|
2226
|
+
* Morph offsets are NOT applied: they move a face, never move it into another
|
|
2227
|
+
* material, and reading them back per click would cost more than the pick.
|
|
2228
|
+
*
|
|
2229
|
+
* `x`/`y` are CSS pixels relative to the canvas, as pickBone takes them.
|
|
2230
|
+
*/
|
|
2231
|
+
pickMaterial(x: number, y: number, options?: {
|
|
2232
|
+
modelName?: string;
|
|
2233
|
+
}): {
|
|
2234
|
+
modelName: string;
|
|
2235
|
+
materialName: string;
|
|
2236
|
+
materialIndex: number;
|
|
2237
|
+
} | null;
|
|
2238
|
+
/** Draw an octahedron per bone of `modelName`, rebuilt each frame. Null off. */
|
|
2239
|
+
setBoneOverlay(modelName: string | null, options?: BoneOverlayOptions): void;
|
|
2240
|
+
/** Draw every rigidbody of `modelName` where the simulation has it, rebuilt
|
|
2241
|
+
* each frame. Null off. */
|
|
2242
|
+
setRigidbodyOverlay(modelName: string | null, options?: RigidbodyOverlayOptions): void;
|
|
2243
|
+
/** Draw a cross per joint of `modelName` plus dashed lines to the bodies it
|
|
2244
|
+
* holds together, rebuilt each frame. Null off. */
|
|
2245
|
+
setJointOverlay(modelName: string | null, options?: JointOverlayOptions): void;
|
|
2246
|
+
/**
|
|
2247
|
+
* Draw `modelName`'s mesh as a wireframe — its vertices and its topology.
|
|
2248
|
+
*
|
|
2249
|
+
* Skinned on the GPU from the model's own vertex buffer and skin matrices, so
|
|
2250
|
+
* it sits on the POSED mesh. The loader's CPU-side positions are bind pose: a
|
|
2251
|
+
* wireframe built from those looks right on a T-posed model and slides off
|
|
2252
|
+
* every animated one, which is exactly the state a user is in while looking at
|
|
2253
|
+
* weights.
|
|
2254
|
+
*
|
|
2255
|
+
* The edge list is deduplicated and built once, on the first frame this is on.
|
|
2256
|
+
*
|
|
2257
|
+
* `material` narrows the wireframe to one material's faces. The mesh still
|
|
2258
|
+
* writes depth in full, so the material reads as part of the body rather than
|
|
2259
|
+
* as a shell floating in front of it — which is the point of scoping it: you
|
|
2260
|
+
* are asking where this material's faces ARE, and an answer that ignores the
|
|
2261
|
+
* torso in front of them is not one.
|
|
2262
|
+
*/
|
|
2263
|
+
setVertexOverlay(modelName: string | null, options?: {
|
|
2264
|
+
xray?: boolean;
|
|
2265
|
+
material?: string | null;
|
|
2266
|
+
}): void;
|
|
2005
2267
|
/** A group's uniform buffer and its maps have the same lifetime — freeing one
|
|
2006
2268
|
* without the other is how a re-apply leaks GPU memory a frame at a time. */
|
|
2007
2269
|
private destroyInstall;
|
|
@@ -2021,6 +2283,15 @@ export declare class Engine {
|
|
|
2021
2283
|
*/
|
|
2022
2284
|
setIKEnabled(enabled: boolean): void;
|
|
2023
2285
|
getIKEnabled(): boolean;
|
|
2286
|
+
/**
|
|
2287
|
+
* Run the solver, or stop it.
|
|
2288
|
+
*
|
|
2289
|
+
* Turning it OFF snaps every body back onto its bone. Merely halting the step
|
|
2290
|
+
* leaves hair and skirts hanging wherever the simulation happened to be — a
|
|
2291
|
+
* pose nothing in the document describes, which is the opposite of what "off"
|
|
2292
|
+
* is asked for: you switch physics off to see what the RIG does, and a frozen
|
|
2293
|
+
* mid-swing is still the solver's answer, just a stale one.
|
|
2294
|
+
*/
|
|
2024
2295
|
setPhysicsEnabled(enabled: boolean): void;
|
|
2025
2296
|
getPhysicsEnabled(): boolean;
|
|
2026
2297
|
/**
|
|
@@ -2342,9 +2613,55 @@ export declare class Engine {
|
|
|
2342
2613
|
private handleCanvasTouch;
|
|
2343
2614
|
private performRaycast;
|
|
2344
2615
|
private renderSelectionPasses;
|
|
2616
|
+
/** The index run `material` owns, or the whole list when it is null. Materials
|
|
2617
|
+
* are consecutive runs in declaration order, so the offset is a prefix sum —
|
|
2618
|
+
* the same walk the draw list does. Returns null for a name the model does
|
|
2619
|
+
* not have, which is what a stale selection looks like after a reload. */
|
|
2620
|
+
private materialIndexRange;
|
|
2621
|
+
/** A cache key no material can collide with — a PMX name is never empty and
|
|
2622
|
+
* never contains a NUL. */
|
|
2623
|
+
private static readonly SEAM_KEY;
|
|
2624
|
+
/**
|
|
2625
|
+
* @param material one material's own edges, or null for the whole mesh
|
|
2626
|
+
* @param seams every material's OUTLINE instead — the borders between them
|
|
2627
|
+
*/
|
|
2628
|
+
private ensureEdgeBuffer;
|
|
2629
|
+
private renderWireframe;
|
|
2630
|
+
/** The bone overlay's options with `selected` filled in from setSelectedBone,
|
|
2631
|
+
* so clicking a bone highlights it without the host mirroring the state. An
|
|
2632
|
+
* explicit `selected` in the options still wins. */
|
|
2633
|
+
private boneOverlayOptions;
|
|
2634
|
+
private boneOptionsScratch;
|
|
2635
|
+
private overlayActive;
|
|
2636
|
+
private overlayModel;
|
|
2637
|
+
/** The primitives a live layer would draw right now. Same list the pass uses,
|
|
2638
|
+
* so a host can show it as data, diff it, or hit-test it on the CPU. */
|
|
2639
|
+
getOverlayPrimitives(layer: "bones" | "rigidbodies" | "joints"): OverlayPrimitive[];
|
|
2640
|
+
private ensureOverlayTargets;
|
|
2641
|
+
private ensureOverlayInstanceCapacity;
|
|
2642
|
+
private renderOverlayPass;
|
|
2345
2643
|
private renderGizmoPass;
|
|
2346
2644
|
private rotateVec3ByQuat;
|
|
2347
2645
|
private unproject;
|
|
2646
|
+
/**
|
|
2647
|
+
* Where a point on the canvas lands on a horizontal plane.
|
|
2648
|
+
*
|
|
2649
|
+
* `px,py` are canvas-relative pixels, top-left origin — what a pointer event
|
|
2650
|
+
* gives you after subtracting the element's rect. Returns null when the ray
|
|
2651
|
+
* cannot reach the plane: parallel to it, or pointing the other way, which is
|
|
2652
|
+
* what a click on the sky above the horizon is.
|
|
2653
|
+
*
|
|
2654
|
+
* The one primitive a placement UI needs. Dragging a thing across the floor is
|
|
2655
|
+
* otherwise three sliders in world units, which asks someone to guess numbers
|
|
2656
|
+
* that have no visible relation to the picture they are looking at — and it
|
|
2657
|
+
* throws away the property that makes pointing work at all: under perspective,
|
|
2658
|
+
* moving something further away makes it smaller by exactly the right amount,
|
|
2659
|
+
* so position and size stop being two controls to tune against each other.
|
|
2660
|
+
*/
|
|
2661
|
+
groundPointAt(px: number, py: number, planeY?: number): Vec3 | null;
|
|
2662
|
+
/** Hand the pointer to something else — a placement drag, a gizmo, a host's own
|
|
2663
|
+
* overlay — so the orbit does not also act on it. */
|
|
2664
|
+
setCameraInputLocked(locked: boolean): void;
|
|
2348
2665
|
private buildMouseRay;
|
|
2349
2666
|
private hitTestGizmo;
|
|
2350
2667
|
private distSegmentRay;
|