reze-engine 0.33.1 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ npm install reze-engine
15
15
  - **Anime-style rendering** — toon-ramp NPR over a Principled GGX BSDF, mixed per material
16
16
  - **Shader-graph materials** — every look is a Blender-style node graph compiled to WGSL; style groups bind any materials to any graph, fully customizable
17
17
  - **HDR pipeline** — bloom, Filmic tone mapping, ASC CDL colour grading, 4× MSAA, Apple-TBDR-friendly targets
18
- - **In-house TS physics** — sequential-impulse rigid bodies for PMX rigs with rest-stable implicit spring-dampers, zero dependencies; structure-of-arrays solver, a world floor so hair and hems rest on the ground instead of clipping through it, and per-frame load shedding that holds framerate on weak devices
18
+ - **In-house TS physics** — sequential-impulse rigid bodies for PMX rigs with rest-stable implicit spring-dampers, zero dependencies; structure-of-arrays solver, scene gravity and wind, a world floor so hair and hems rest on the ground instead of clipping through it, and per-frame load shedding that holds framerate on weak devices
19
19
  - **Math library** — the shared Vec3/Quat/Mat4 layer of the Reze family: euler orders, swing-twist, shortest-arc, look-rotation, zero-alloc `*Into` variants
20
20
  - **VMD animation** — MMD IK with per-chain enable read from the motion, morphs on a GPU compute path, and VMD export
21
21
  - **Clip blending & locomotion** — weighted multi-clip pose blending, crossfades, and a game-style character controller (idle/run/sprint speed blend, authored stop skids, code-driven root motion) — the [demo](https://reze.one) is WASD-playable
@@ -90,7 +90,7 @@ engine/src/
90
90
  physics.ts RezePhysics: bone↔body sync, fixed-step accumulator + interpolation
91
91
  solver.ts sequential-impulse PGS (joint + contact rows)
92
92
  contact.ts narrowphase (analytical sphere/box/capsule pairs) + contact pool
93
- constraint.ts 6DOF spring joints · world.ts broadphase + step
93
+ constraint.ts 6DOF spring joints · world.ts step, gravity + wind
94
94
  body.ts SoA rigid-body store · types.ts
95
95
 
96
96
  shaders/
@@ -119,6 +119,8 @@ engine.setMaterialVisible(name, material, visible) / toggleMaterialVisible / isM
119
119
  engine.setIKEnabled(enabled) // engine-wide OFF for hosts that pose bones themselves; ON hands per-chain state to the clip
120
120
  engine.setPhysicsEnabled(enabled)
121
121
  engine.resetPhysics() // re-pose bodies from animation + zero velocities (call if physics explodes)
122
+ engine.setGravity(vec3) / getGravity() // scene-wide; default (0, -98, 0) — MMD scale, where a character is ~18 units tall
123
+ engine.setWind({ direction, strength, turbulence?, frequency? } | null) / getWind() // scene-wide air; strength is in gravity's units, so 10-30 reads as a breeze through hair and skirt
122
124
 
123
125
  engine.setCameraFollow(model, bone?, offset?) / setCameraFollow(null)
124
126
  engine.setCameraTarget(vec3) / setCameraDistance(d) / setCameraAlpha(a) / setCameraBeta(b)
@@ -337,7 +339,9 @@ In-house sequential-impulse rigid-body solver for PMX rigs (sphere / box / capsu
337
339
  - **Discontinuity guards** — a bone-pose jump beyond continuous motion (timeline scrub, long stall) rigidly carries each dynamic body along with its kinematic root's transform delta and zeroes momentum instead of dragging cloth across the gap; correction velocities are clamped (120 u/s linear, 30 rad/s angular), per-step travel is capped, and any body that still goes non-finite is restored to its previous substep pose.
338
340
  - Sleeping is off (cloth must always react); resting bodies bleed micro-velocity via per-PMX damping.
339
341
 
340
- Engine surface is just `setPhysicsEnabled` / `resetPhysics` all tuning (mass, damping, friction, restitution, joint stiffness/limits, collision groups) lives on the PMX rig.
342
+ - **Gravity and wind** are scene-wide and summed once per substep, so wind costs the per-body loop nothing. Wind is an acceleration rather than a drag model: PMX authors already tune per-body damping to get the hang they want, and a second hidden drag term would fight it. Gusting rides a pair of incommensurate sines — one alone is a metronome — and advances on *simulated* time, so an exported take gusts frame-for-frame as its preview did.
343
+
344
+ Engine surface is `setPhysicsEnabled` / `resetPhysics` / `setGravity` / `setWind` — everything else (mass, damping, friction, restitution, joint stiffness/limits, collision groups) lives on the PMX rig.
341
345
 
342
346
  ## Rendering
343
347
 
package/dist/engine.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Quat, Vec3 } from "./math";
2
2
  import { Model } from "./model";
3
3
  import { RezePhysics } from "./physics";
4
+ import type { WindOptions } from "./physics/world";
4
5
  import { type AssetReader } from "./asset-reader";
5
6
  import { type CompileOptions, type StyleSlot } from "./graph/compile";
6
7
  import type { AlphaMode, RenderClass } from "./graph/render-class";
@@ -402,6 +403,8 @@ export declare class Engine {
402
403
  private _nextDefaultModelId;
403
404
  private ikEnabled;
404
405
  private physicsEnabled;
406
+ private gravity;
407
+ private wind;
405
408
  private useGpuMorphs;
406
409
  private cameraAnimation;
407
410
  private cameraTargetModel;
@@ -585,13 +588,6 @@ export declare class Engine {
585
588
  }): void;
586
589
  private updateLightBuffer;
587
590
  getStats(): EngineStats;
588
- /** Frame-rate cap for the render loop, or null for display-rate. On high-refresh
589
- * displays (144/240Hz) rAF runs the WHOLE pipeline — physics, IK, blending,
590
- * passes — that many times per second for no visible gain over ~120 (VMD content
591
- * is 30fps; blending interpolates). Capping restores the per-second budget. */
592
- private maxFPS;
593
- private lastLoopTime;
594
- setMaxFPS(fps: number | null): void;
595
591
  runRenderLoop(callback?: () => void): void;
596
592
  stopRenderLoop(): void;
597
593
  dispose(): void;
@@ -630,6 +626,25 @@ export declare class Engine {
630
626
  getIKEnabled(): boolean;
631
627
  setPhysicsEnabled(enabled: boolean): void;
632
628
  getPhysicsEnabled(): boolean;
629
+ /**
630
+ * Scene gravity, applied to every model's cloth and hair. The default is
631
+ * (0, -98, 0) — MMD's own scale, where a character stands about 20 units
632
+ * tall. Lower magnitudes float; tilting it sideways hangs everything on a
633
+ * slant, which is the cheap way to fake a strong draught.
634
+ */
635
+ setGravity(gravity: Vec3): void;
636
+ getGravity(): Vec3;
637
+ /**
638
+ * Air movement across the scene — null is still air.
639
+ *
640
+ * Applied as an acceleration alongside gravity, so `strength` is in the same
641
+ * units: against the default gravity of 98, a strength of 10-30 reads as a
642
+ * breeze through hair and a skirt without lifting them off the body. Gusting
643
+ * is driven by simulated time rather than wall time, so an exported take
644
+ * gusts exactly as the preview did.
645
+ */
646
+ setWind(wind: WindOptions | null): void;
647
+ getWind(): WindOptions | null;
633
648
  resetPhysics(): void;
634
649
  private forEachInstance;
635
650
  private cpuAnimMs;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
package/dist/engine.js CHANGED
@@ -325,6 +325,10 @@ export class Engine {
325
325
  // IK and physics enabled at engine level (same for all models)
326
326
  this.ikEnabled = true;
327
327
  this.physicsEnabled = true;
328
+ // World-wide, not per-model: MMD treats gravity and wind as properties of the
329
+ // scene, and a model loaded later must arrive into the same air as the rest.
330
+ this.gravity = new Vec3(0, -98, 0);
331
+ this.wind = null;
328
332
  // GPU vertex-morph path. Set false BEFORE loadModel to fall back to the CPU path (A/B).
329
333
  this.useGpuMorphs = true;
330
334
  // VMD camera track (a dedicated camera VMD). When loaded + enabled it drives the shot,
@@ -371,12 +375,6 @@ export class Engine {
371
375
  /** When set, render resolution is pinned to this size instead of tracking the
372
376
  * canvas's CSS size × devicePixelRatio (see setRenderSize). */
373
377
  this.fixedRenderSize = null;
374
- /** Frame-rate cap for the render loop, or null for display-rate. On high-refresh
375
- * displays (144/240Hz) rAF runs the WHOLE pipeline — physics, IK, blending,
376
- * passes — that many times per second for no visible gain over ~120 (VMD content
377
- * is 30fps; blending interpolates). Capping restores the per-second budget. */
378
- this.maxFPS = null;
379
- this.lastLoopTime = 0;
380
378
  // CPU frame-time breakdown (EMA-smoothed into getStats): where a frame's
381
379
  // milliseconds actually go — animation/IK/blending vs physics vs everything
382
380
  // else on the render thread. The first question of any perf report.
@@ -2562,20 +2560,18 @@ export class Engine {
2562
2560
  getStats() {
2563
2561
  return { ...this.stats };
2564
2562
  }
2565
- setMaxFPS(fps) {
2566
- this.maxFPS = fps !== null && fps > 0 ? fps : null;
2567
- }
2563
+ // The render loop runs at display rate, always. A frame-rate cap used to be
2564
+ // offered here for high-refresh displays, on the reasoning that VMD content
2565
+ // is 30fps and running the whole pipeline at 240 buys nothing. Nothing ever
2566
+ // called it — every product in the family chases native refresh, because
2567
+ // dropping frames a display can show is the one thing that reads as cheap.
2568
+ // Physics already decouples: it steps at a fixed 60Hz behind an accumulator
2569
+ // and the drawn pose is interpolated between substeps, so a 240Hz display
2570
+ // costs four interpolations per simulation step, not four simulations.
2568
2571
  runRenderLoop(callback) {
2569
2572
  this.renderLoopCallback = callback || null;
2570
- const loop = (now) => {
2573
+ const loop = () => {
2571
2574
  this.animationFrameId = requestAnimationFrame(loop);
2572
- if (this.maxFPS !== null) {
2573
- // Tolerate rAF jitter: accept frames within ~half a display tick early.
2574
- const minInterval = 1000 / this.maxFPS - 2;
2575
- if (now - this.lastLoopTime < minInterval)
2576
- return;
2577
- this.lastLoopTime = now;
2578
- }
2579
2575
  this.render();
2580
2576
  if (this.renderLoopCallback) {
2581
2577
  this.renderLoopCallback();
@@ -2813,6 +2809,35 @@ export class Engine {
2813
2809
  getPhysicsEnabled() {
2814
2810
  return this.physicsEnabled;
2815
2811
  }
2812
+ /**
2813
+ * Scene gravity, applied to every model's cloth and hair. The default is
2814
+ * (0, -98, 0) — MMD's own scale, where a character stands about 20 units
2815
+ * tall. Lower magnitudes float; tilting it sideways hangs everything on a
2816
+ * slant, which is the cheap way to fake a strong draught.
2817
+ */
2818
+ setGravity(gravity) {
2819
+ this.gravity = new Vec3(gravity.x, gravity.y, gravity.z);
2820
+ this.forEachInstance((inst) => inst.physics?.setGravity(this.gravity));
2821
+ }
2822
+ getGravity() {
2823
+ return new Vec3(this.gravity.x, this.gravity.y, this.gravity.z);
2824
+ }
2825
+ /**
2826
+ * Air movement across the scene — null is still air.
2827
+ *
2828
+ * Applied as an acceleration alongside gravity, so `strength` is in the same
2829
+ * units: against the default gravity of 98, a strength of 10-30 reads as a
2830
+ * breeze through hair and a skirt without lifting them off the body. Gusting
2831
+ * is driven by simulated time rather than wall time, so an exported take
2832
+ * gusts exactly as the preview did.
2833
+ */
2834
+ setWind(wind) {
2835
+ this.wind = wind ? { ...wind, direction: new Vec3(wind.direction.x, wind.direction.y, wind.direction.z) } : null;
2836
+ this.forEachInstance((inst) => inst.physics?.setWind(this.wind));
2837
+ }
2838
+ getWind() {
2839
+ return this.wind ? { ...this.wind, direction: new Vec3(this.wind.direction.x, this.wind.direction.y, this.wind.direction.z) } : null;
2840
+ }
2816
2841
  resetPhysics() {
2817
2842
  this.forEachInstance((inst) => {
2818
2843
  if (!inst.physics)
@@ -2951,6 +2976,13 @@ export class Engine {
2951
2976
  this.device.queue.writeBuffer(indexBuffer, 0, indices);
2952
2977
  const rbs = model.getRigidbodies();
2953
2978
  const physics = rbs.length > 0 ? new RezePhysics(rbs, model.getJoints()) : null;
2979
+ // Adopt the scene's air, or a model added mid-session would fall under
2980
+ // different gravity from the ones already on stage.
2981
+ if (physics) {
2982
+ physics.setGravity(this.gravity);
2983
+ if (this.wind)
2984
+ physics.setWind(this.wind);
2985
+ }
2954
2986
  const shadowBindGroup = this.device.createBindGroup({
2955
2987
  label: `${name}: shadow bind`,
2956
2988
  layout: this.shadowDepthPipeline.getBindGroupLayout(0),
package/dist/index.d.ts CHANGED
@@ -25,4 +25,5 @@ export { VMDWriter } from "./vmd-writer";
25
25
  export { PmxLoader } from "./pmx-loader";
26
26
  export { CameraAnimation, type CameraPose } from "./camera-animation";
27
27
  export { RezePhysics } from "./physics";
28
+ export type { WindOptions } from "./physics/world";
28
29
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { Vec3, Quat, Mat4 } from "../math";
2
2
  import type { Rigidbody, Joint } from "./types";
3
3
  import { RigidBodyStore } from "./body";
4
+ import { type WindOptions } from "./world";
4
5
  export declare class RezePhysics {
5
6
  private rigidbodies;
6
7
  private joints;
@@ -32,6 +33,9 @@ export declare class RezePhysics {
32
33
  private savePrevState;
33
34
  setGravity(gravity: Vec3): void;
34
35
  getGravity(): Vec3;
36
+ /** World-wide air movement. See {@link WindOptions}; null is still air. */
37
+ setWind(wind: WindOptions | null): void;
38
+ getWind(): WindOptions | null;
35
39
  getRigidbodies(): Rigidbody[];
36
40
  getJoints(): Joint[];
37
41
  getStore(): RigidBodyStore;
@@ -1 +1 @@
1
- {"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../../src/physics/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAavC,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,uEAAuE;IACvE,OAAO,CAAC,aAAa,CAAM;IAC3B,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IAMjC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAAc;IAQtC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,eAAe,CAAc;IAMrC,OAAO,CAAC,OAAO,CAAY;IAE3B,OAAO,CAAC,aAAa,CAAY;IAMjC,OAAO,CAAC,WAAW,CAAY;IAG/B,aAAa,SAAI;gBAEL,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,GAAE,KAAK,EAAO;IA6D1D,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,aAAa;IAKrB,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI;IAG/B,UAAU,IAAI,IAAI;IAGlB,cAAc,IAAI,SAAS,EAAE;IAG7B,SAAS,IAAI,KAAK,EAAE;IAGpB,QAAQ,IAAI,cAAc;IAI1B,sBAAsB,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC;IAiBnE,KAAK,CAAC,iBAAiB,EAAE,IAAI,EAAE,GAAG,IAAI;IActC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,uBAAuB,EAAE,YAAY,GAAG,IAAI;IA6ExF,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,uBAAuB;IAqF/B,OAAO,CAAC,yBAAyB;IAgEjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,sBAAsB;IA0C9B,OAAO,CAAC,2BAA2B;IA6EnC,OAAO,CAAC,wBAAwB;IA2BhC,OAAO,CAAC,sBAAsB;IAqC9B,OAAO,CAAC,oBAAoB;CA6D7B"}
1
+ {"version":3,"file":"physics.d.ts","sourceRoot":"","sources":["../../src/physics/physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,SAAS,CAAA;AAYjD,qBAAa,WAAW;IACtB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,KAAK,CAAO;IACpB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,UAAU,CAAO;IACzB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAI;IAChC,uEAAuE;IACvE,OAAO,CAAC,aAAa,CAAM;IAC3B,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAI;IAMjC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,gBAAgB,CAAc;IAQtC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,eAAe,CAAc;IAMrC,OAAO,CAAC,OAAO,CAAY;IAE3B,OAAO,CAAC,aAAa,CAAY;IAMjC,OAAO,CAAC,WAAW,CAAY;IAG/B,aAAa,SAAI;gBAEL,WAAW,EAAE,SAAS,EAAE,EAAE,MAAM,GAAE,KAAK,EAAO;IA6D1D,OAAO,CAAC,mBAAmB;IA4B3B,OAAO,CAAC,aAAa;IAKrB,UAAU,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI;IAG/B,UAAU,IAAI,IAAI;IAGlB,2EAA2E;IAC3E,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI;IAGvC,OAAO,IAAI,WAAW,GAAG,IAAI;IAG7B,cAAc,IAAI,SAAS,EAAE;IAG7B,SAAS,IAAI,KAAK,EAAE;IAGpB,QAAQ,IAAI,cAAc;IAI1B,sBAAsB,IAAI,KAAK,CAAC;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC;IAiBnE,KAAK,CAAC,iBAAiB,EAAE,IAAI,EAAE,GAAG,IAAI;IActC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,uBAAuB,EAAE,YAAY,GAAG,IAAI;IA6ExF,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,uBAAuB;IAqF/B,OAAO,CAAC,yBAAyB;IAgEjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,sBAAsB;IA0C9B,OAAO,CAAC,2BAA2B;IA6EnC,OAAO,CAAC,wBAAwB;IA2BhC,OAAO,CAAC,sBAAsB;IAqC9B,OAAO,CAAC,oBAAoB;CA6D7B"}
@@ -122,6 +122,13 @@ export class RezePhysics {
122
122
  getGravity() {
123
123
  return this.world.gravity;
124
124
  }
125
+ /** World-wide air movement. See {@link WindOptions}; null is still air. */
126
+ setWind(wind) {
127
+ this.world.setWind(wind);
128
+ }
129
+ getWind() {
130
+ return this.world.getWind();
131
+ }
125
132
  getRigidbodies() {
126
133
  return this.rigidbodies;
127
134
  }
@@ -3,14 +3,47 @@ import type { RigidBodyStore } from "./body";
3
3
  import type { SixDofSpringConstraint } from "./constraint";
4
4
  import { type SolverCache } from "./solver";
5
5
  import { type ContactPool } from "./contact";
6
+ /**
7
+ * Air movement across the whole world.
8
+ *
9
+ * Applied as an acceleration alongside gravity, which is the same shape MMD's
10
+ * own wind plugins take and keeps it free: gravity and wind are summed once per
11
+ * substep, so the per-body predict loop is untouched. Terminal velocity comes
12
+ * out of the existing per-body damping rather than a drag model — PMX authors
13
+ * already tune that damping to get the hang they want, and a second, hidden
14
+ * drag term would fight it.
15
+ */
16
+ export interface WindOptions {
17
+ /** Direction the air travels. Normalised on assignment; a zero vector is off. */
18
+ direction: Vec3;
19
+ /** Acceleration along it, in gravity's units — the built-in gravity is 98. */
20
+ strength: number;
21
+ /** Gust depth, clamped to 0–1. 0 is a steady breeze; 1 swings between still
22
+ * and double. It is a clamp rather than a free scalar because past 1 the
23
+ * swing goes negative and the wind blows backwards on every other beat,
24
+ * which is never what a caller meant by "more turbulent". */
25
+ turbulence?: number;
26
+ /** Gusts per second. */
27
+ frequency?: number;
28
+ }
6
29
  export declare class World {
7
30
  readonly gravity: Vec3;
8
31
  solverIterations: number;
9
32
  private dampCacheDt;
10
33
  private linDampFactor;
11
34
  private angDampFactor;
35
+ private windX;
36
+ private windY;
37
+ private windZ;
38
+ private windTurbulence;
39
+ private windFrequency;
40
+ /** Advances with simulated time, not wall time, so a scrubbed or exported
41
+ * take gusts identically to a live one. */
42
+ private windClock;
12
43
  constructor(gravity: Vec3);
13
44
  setGravity(g: Vec3): void;
45
+ setWind(wind: WindOptions | null): void;
46
+ getWind(): WindOptions | null;
14
47
  step(store: RigidBodyStore, constraints: SixDofSpringConstraint[], cache: SolverCache, contacts: ContactPool, dt: number): void;
15
48
  }
16
49
  //# sourceMappingURL=world.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/physics/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAE5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAO1D,qBAAa,KAAK;IAChB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;IACtB,gBAAgB,SAAK;IAIrB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,aAAa,CAA4B;gBAErC,OAAO,EAAE,IAAI;IAIzB,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI;IAMzB,IAAI,CACF,KAAK,EAAE,cAAc,EACrB,WAAW,EAAE,sBAAsB,EAAE,EACrC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,WAAW,EACrB,EAAE,EAAE,MAAM,GACT,IAAI;CA2JR"}
1
+ {"version":3,"file":"world.d.ts","sourceRoot":"","sources":["../../src/physics/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC9B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAE5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAA;AAC7D,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAA;AAO1D;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,SAAS,EAAE,IAAI,CAAA;IACf,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAA;IAChB;;;kEAG8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,KAAK;IAChB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;IACtB,gBAAgB,SAAK;IAIrB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,aAAa,CAA4B;IAIjD,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,KAAK,CAAI;IACjB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,aAAa,CAAO;IAC5B;gDAC4C;IAC5C,OAAO,CAAC,SAAS,CAAI;gBAET,OAAO,EAAE,IAAI;IAIzB,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI;IAMzB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI;IAoBvC,OAAO,IAAI,WAAW,GAAG,IAAI;IAW7B,IAAI,CACF,KAAK,EAAE,cAAc,EACrB,WAAW,EAAE,sBAAsB,EAAE,EACrC,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,WAAW,EACrB,EAAE,EAAE,MAAM,GACT,IAAI;CA0KR"}
@@ -2,11 +2,6 @@ import { Vec3 } from "../math";
2
2
  import { RigidbodyType } from "./types";
3
3
  import { solveConstraints } from "./solver";
4
4
  import { findContacts } from "./contact";
5
- // World step: predict velocities → collide → solve → position correction →
6
- // integrate. Static and kinematic bodies are skipped during predict and
7
- // integrate; the parent class syncs them from bones around the step. The
8
- // solver pass runs on all bodies — kinematic ones have invMass = 0 and
9
- // act as anchors.
10
5
  export class World {
11
6
  constructor(gravity) {
12
7
  this.solverIterations = 10;
@@ -15,6 +10,16 @@ export class World {
15
10
  this.dampCacheDt = -1;
16
11
  this.linDampFactor = null;
17
12
  this.angDampFactor = null;
13
+ // Wind, resolved to a direction × strength at construction of the options so
14
+ // the step loop only multiplies by a gust scalar.
15
+ this.windX = 0;
16
+ this.windY = 0;
17
+ this.windZ = 0;
18
+ this.windTurbulence = 0;
19
+ this.windFrequency = 0.35;
20
+ /** Advances with simulated time, not wall time, so a scrubbed or exported
21
+ * take gusts identically to a live one. */
22
+ this.windClock = 0;
18
23
  this.gravity = new Vec3(gravity.x, gravity.y, gravity.z);
19
24
  }
20
25
  setGravity(g) {
@@ -22,6 +27,35 @@ export class World {
22
27
  this.gravity.y = g.y;
23
28
  this.gravity.z = g.z;
24
29
  }
30
+ setWind(wind) {
31
+ // Shape first, and unconditionally: bailing out early on a zero strength
32
+ // used to leave turbulence and frequency holding whatever a previous call
33
+ // set, so raising the strength again resurrected settings the caller had
34
+ // since replaced.
35
+ this.windTurbulence = Math.min(1, Math.max(0, wind?.turbulence ?? 0));
36
+ this.windFrequency = Math.max(0, wind?.frequency ?? 0.35);
37
+ const d = wind?.direction;
38
+ const len = d ? Math.hypot(d.x, d.y, d.z) : 0;
39
+ if (!wind || !d || len < 1e-9 || wind.strength === 0) {
40
+ this.windX = this.windY = this.windZ = 0;
41
+ return;
42
+ }
43
+ const s = wind.strength / len;
44
+ this.windX = d.x * s;
45
+ this.windY = d.y * s;
46
+ this.windZ = d.z * s;
47
+ }
48
+ getWind() {
49
+ const strength = Math.hypot(this.windX, this.windY, this.windZ);
50
+ if (strength === 0)
51
+ return null;
52
+ return {
53
+ direction: new Vec3(this.windX / strength, this.windY / strength, this.windZ / strength),
54
+ strength,
55
+ turbulence: this.windTurbulence,
56
+ frequency: this.windFrequency,
57
+ };
58
+ }
25
59
  step(store, constraints, cache, contacts, dt) {
26
60
  if (dt <= 0)
27
61
  return;
@@ -34,9 +68,24 @@ export class World {
34
68
  const ldamp = store.linearDamping;
35
69
  const adamp = store.angularDamping;
36
70
  const invMass = store.invMass;
37
- const gx = this.gravity.x;
38
- const gy = this.gravity.y;
39
- const gz = this.gravity.z;
71
+ // Gravity and wind are the same kind of term, so they are summed here and
72
+ // the predict loop below never learns wind exists.
73
+ let gx = this.gravity.x;
74
+ let gy = this.gravity.y;
75
+ let gz = this.gravity.z;
76
+ if (this.windX !== 0 || this.windY !== 0 || this.windZ !== 0) {
77
+ this.windClock += dt;
78
+ let gust = 1;
79
+ if (this.windTurbulence > 0 && this.windFrequency > 0) {
80
+ // Two incommensurate sines: a single one is a metronome, and real gusts
81
+ // do not repeat on a bar line. Stays within 1 ± turbulence.
82
+ const t = this.windClock * this.windFrequency * Math.PI * 2;
83
+ gust = 1 + this.windTurbulence * 0.5 * (Math.sin(t) + Math.sin(t * 0.37 + 1.3));
84
+ }
85
+ gx += this.windX * gust;
86
+ gy += this.windY * gust;
87
+ gz += this.windZ * gust;
88
+ }
40
89
  // 1. Predict — gravity + damping. The pow form (vs the linear
41
90
  // 1−damping·dt approximation) stays stable at high PMX damping
42
91
  // values like 0.99. Factors are cached (damping and dt are constant).
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The tile as 8-bit luminance, plus its mip chain (box-filtered, which is exact
3
+ * for a repeating texture). Mips are the point as much as the speed: procedural
4
+ * noise has no mip chain, so at grazing angles it shimmered.
5
+ */
6
+ export declare function buildGroundNoiseMips(): Uint8Array[];
7
+ //# sourceMappingURL=ground-noise.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ground-noise.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground-noise.ts"],"names":[],"mappings":"AAkDA;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAsCnD"}
@@ -0,0 +1,88 @@
1
+ // Bakes the ground's frosted micro-texture into a seamless, mipmapped tile.
2
+ //
3
+ // The shader used to evaluate four octaves of value noise per pixel — sixteen
4
+ // hash rounds — and the ground covers the entire screen as soon as the camera
5
+ // tilts toward the horizon. This produces the same character of pattern once, at
6
+ // load, so the fragment shader pays one filtered fetch instead.
7
+ //
8
+ // SEAMLESS BY CONSTRUCTION. The original hash was not periodic, so a finite
9
+ // crop of it could never tile. Here every octave's lattice wraps at a whole
10
+ // number of cells across the tile, which makes the result repeat exactly at the
11
+ // edges. The pattern is therefore not pixel-identical to the analytic version —
12
+ // it is the same kind of noise, not the same noise. At the default strength of
13
+ // 0.05 it modulates brightness by ±2.5%, where the repeat is not findable by eye.
14
+ import { GROUND_NOISE_RES, GROUND_NOISE_TILE_WORLD } from "./ground";
15
+ /** Lattice cells across the tile at octave 0. The analytic version sampled fbm
16
+ * at worldXZ × 3, so a tile spanning 8 world units covers 24 base cells — the
17
+ * same spatial frequency the surface had before. */
18
+ const BASE_CELLS = GROUND_NOISE_TILE_WORLD * 3;
19
+ const OCTAVES = 4;
20
+ /** Deterministic lattice hash. Integer coordinates are wrapped by the caller,
21
+ * which is what makes the tile seamless. */
22
+ function hash(ix, iy) {
23
+ let h = Math.imul(ix, 374761393) + Math.imul(iy, 668265263);
24
+ h = Math.imul(h ^ (h >>> 13), 1274126177);
25
+ return ((h ^ (h >>> 16)) >>> 0) / 4294967296;
26
+ }
27
+ /** Value noise on a lattice that repeats every `period` cells. */
28
+ function periodicValueNoise(x, y, period) {
29
+ const ix = Math.floor(x);
30
+ const iy = Math.floor(y);
31
+ const fx = x - ix;
32
+ const fy = y - iy;
33
+ // Smoothstep weights — same curve the WGSL used.
34
+ const ux = fx * fx * (3 - 2 * fx);
35
+ const uy = fy * fy * (3 - 2 * fy);
36
+ const x0 = ((ix % period) + period) % period;
37
+ const y0 = ((iy % period) + period) % period;
38
+ const x1 = (x0 + 1) % period;
39
+ const y1 = (y0 + 1) % period;
40
+ const a = hash(x0, y0);
41
+ const b = hash(x1, y0);
42
+ const c = hash(x0, y1);
43
+ const d = hash(x1, y1);
44
+ return (a + (b - a) * ux) * (1 - uy) + (c + (d - c) * ux) * uy;
45
+ }
46
+ /**
47
+ * The tile as 8-bit luminance, plus its mip chain (box-filtered, which is exact
48
+ * for a repeating texture). Mips are the point as much as the speed: procedural
49
+ * noise has no mip chain, so at grazing angles it shimmered.
50
+ */
51
+ export function buildGroundNoiseMips() {
52
+ const levels = [];
53
+ const res = GROUND_NOISE_RES;
54
+ const base = new Uint8Array(res * res);
55
+ for (let py = 0; py < res; py++) {
56
+ for (let px = 0; px < res; px++) {
57
+ // Texel centre, in units of octave-0 lattice cells.
58
+ const x = ((px + 0.5) / res) * BASE_CELLS;
59
+ const y = ((py + 0.5) / res) * BASE_CELLS;
60
+ let v = 0;
61
+ let amp = 0.5;
62
+ let freq = 1;
63
+ for (let o = 0; o < OCTAVES; o++) {
64
+ v += amp * periodicValueNoise(x * freq, y * freq, BASE_CELLS * freq);
65
+ freq *= 2;
66
+ amp *= 0.5;
67
+ }
68
+ base[py * res + px] = Math.max(0, Math.min(255, Math.round(v * 255)));
69
+ }
70
+ }
71
+ levels.push(base);
72
+ let src = base;
73
+ let size = res;
74
+ while (size > 1) {
75
+ const half = size >> 1;
76
+ const dst = new Uint8Array(half * half);
77
+ for (let y = 0; y < half; y++) {
78
+ for (let x = 0; x < half; x++) {
79
+ const s = y * 2 * size + x * 2;
80
+ dst[y * half + x] = (src[s] + src[s + 1] + src[s + size] + src[s + size + 1] + 2) >> 2;
81
+ }
82
+ }
83
+ levels.push(dst);
84
+ src = dst;
85
+ size = half;
86
+ }
87
+ return levels;
88
+ }
@@ -1,2 +1,2 @@
1
- export declare const GROUND_SHADOW_SHADER_WGSL = "\nstruct CameraUniforms { view: mat4x4f, projection: mat4x4f, viewPos: vec3f, _p: f32, };\nstruct Light { direction: vec4f, color: vec4f, };\nstruct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };\nstruct GroundShadowMat {\n diffuseColor: vec3f, fadeStart: f32,\n fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,\n gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,\n gridLineColor: vec3f, _pad2: f32,\n};\nstruct LightVP { viewProj: mat4x4f, };\n@group(0) @binding(0) var<uniform> camera: CameraUniforms;\n@group(0) @binding(1) var<uniform> light: LightUniforms;\n@group(0) @binding(2) var shadowMap: texture_depth_2d;\n@group(0) @binding(3) var shadowSampler: sampler_comparison;\n@group(0) @binding(4) var<uniform> material: GroundShadowMat;\n@group(0) @binding(5) var<uniform> lightVP: LightVP;\n\nfn hash2(p: vec2f) -> f32 {\n var p3 = fract(vec3f(p.x, p.y, p.x) * 0.1031);\n p3 += dot(p3, vec3f(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));\n return fract((p3.x + p3.y) * p3.z);\n}\nfn valueNoise(p: vec2f) -> f32 {\n let i = floor(p);\n let f = fract(p);\n let u = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash2(i), hash2(i + vec2f(1.0, 0.0)), u.x),\n mix(hash2(i + vec2f(0.0, 1.0)), hash2(i + vec2f(1.0, 1.0)), u.x), u.y);\n}\nfn fbmNoise(p: vec2f) -> f32 {\n var v = 0.0;\n var a = 0.5;\n var pp = p;\n for (var i = 0; i < 4; i++) {\n v += a * valueNoise(pp);\n pp *= 2.0;\n a *= 0.5;\n }\n return v;\n}\n\nstruct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @location(1) normal: vec3f, };\n@vertex fn vs(@location(0) position: vec3f, @location(1) normal: vec3f, @location(2) uv: vec2f) -> VO {\n var o: VO; o.worldPos = position; o.normal = normal;\n o.position = camera.projection * camera.view * vec4f(position, 1.0); return o;\n}\nstruct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };\n@fragment fn fs(i: VO) -> FSOut {\n let n = normalize(i.normal);\n let centerDist = length(i.worldPos.xz);\n let edgeFade = 1.0 - smoothstep(0.0, 1.0, clamp((centerDist - material.fadeStart) / max(material.fadeEnd - material.fadeStart, 0.001), 0.0, 1.0));\n\n let lclip = lightVP.viewProj * vec4f(i.worldPos, 1.0);\n let ndc = lclip.xyz / max(lclip.w, 1e-6);\n let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);\n let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));\n let st = material.pcfTexel;\n let compareZ = ndc.z - 0.0035;\n var vis = 0.0;\n for (var y = -2; y <= 2; y++) {\n for (var x = -2; x <= 2; x++) {\n vis += textureSampleCompare(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);\n }\n }\n vis *= 0.04;\n // Outside the light's frustum there IS no shadow information \u2014 the clamped\n // border samples above compare against unrelated depths and read \"shadowed\",\n // darkening the whole far plane with a visible band at the frustum edge\n // (masked by the opaque surface normally, glaring in green-screen mode where\n // only the shadow-catcher term renders). Fade to fully lit near the border.\n let inZ = select(0.0, 1.0, ndc.z > 0.0 && ndc.z < 1.0);\n let frustum = (1.0 - smoothstep(0.88, 0.96, abs(ndc.x))) * (1.0 - smoothstep(0.88, 0.96, abs(ndc.y))) * inZ;\n vis = mix(1.0, vis, frustum);\n\n // Frosted/matte micro-texture\n let noiseVal = fbmNoise(i.worldPos.xz * 3.0);\n let noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;\n\n // Grid lines \u2014 anti-aliased via screen-space derivatives\n let gp = i.worldPos.xz / material.gridSpacing;\n let gridFrac = abs(fract(gp - 0.5) - 0.5);\n let gridDeriv = fwidth(gp);\n let halfLine = material.gridLineWidth * 0.5;\n let gridLine = 1.0 - min(\n smoothstep(halfLine - gridDeriv.x, halfLine + gridDeriv.x, gridFrac.x),\n smoothstep(halfLine - gridDeriv.y, halfLine + gridDeriv.y, gridFrac.y)\n );\n let sun = light.ambientColor.xyz + light.lights[0].color.xyz * light.lights[0].color.w * max(dot(n, -light.lights[0].direction.xyz), 0.0);\n let dark = (1.0 - vis) * material.shadowStrength;\n var baseColor = material.diffuseColor * sun * (1.0 - dark * 0.65);\n baseColor *= noiseTint;\n let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);\n // Whole-ground opacity fades the SURFACE (color, grid) but the shadow stays \u2014\n // as opacity drops, the received shadow becomes a translucent dark layer\n // (Blender's Shadow Catcher), so models still feel grounded on a photo or\n // 360 backdrop. At opacity 1 this reduces exactly to the plain surface.\n let surfA = edgeFade * material.opacity;\n let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);\n let outA = surfA + catchA;\n var out: FSOut;\n out.color = vec4f(finalColor * surfA, outA);\n // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =\n // outA turns the aux blend into alpha-over, so the drawable alpha goes\n // from outA at the center to 0 at the radial edge \u2014 letting the page\n // background show through under the premultiplied canvas alphaMode.\n out.mask = vec4f(0.0, 1.0, 0.0, outA);\n return out;\n}\n";
1
+ export declare const GROUND_SHADOW_SHADER_WGSL = "\nstruct CameraUniforms { view: mat4x4f, projection: mat4x4f, viewPos: vec3f, _p: f32, };\nstruct Light { direction: vec4f, color: vec4f, };\nstruct LightUniforms { ambientColor: vec4f, lights: array<Light, 4>, };\nstruct GroundShadowMat {\n diffuseColor: vec3f, fadeStart: f32,\n fadeEnd: f32, shadowStrength: f32, pcfTexel: f32, gridSpacing: f32,\n gridLineWidth: f32, gridLineOpacity: f32, noiseStrength: f32, opacity: f32,\n gridLineColor: vec3f, _pad2: f32,\n};\nstruct LightVP { viewProj: mat4x4f, };\n@group(0) @binding(0) var<uniform> camera: CameraUniforms;\n@group(0) @binding(1) var<uniform> light: LightUniforms;\n@group(0) @binding(2) var shadowMap: texture_depth_2d;\n@group(0) @binding(3) var shadowSampler: sampler_comparison;\n@group(0) @binding(4) var<uniform> material: GroundShadowMat;\n@group(0) @binding(5) var<uniform> lightVP: LightVP;\n\nfn hash2(p: vec2f) -> f32 {\n var p3 = fract(vec3f(p.x, p.y, p.x) * 0.1031);\n p3 += dot(p3, vec3f(p3.y + 33.33, p3.z + 33.33, p3.x + 33.33));\n return fract((p3.x + p3.y) * p3.z);\n}\nfn valueNoise(p: vec2f) -> f32 {\n let i = floor(p);\n let f = fract(p);\n let u = f * f * (3.0 - 2.0 * f);\n return mix(mix(hash2(i), hash2(i + vec2f(1.0, 0.0)), u.x),\n mix(hash2(i + vec2f(0.0, 1.0)), hash2(i + vec2f(1.0, 1.0)), u.x), u.y);\n}\nfn fbmNoise(p: vec2f) -> f32 {\n var v = 0.0;\n var a = 0.5;\n var pp = p;\n for (var i = 0; i < 4; i++) {\n v += a * valueNoise(pp);\n pp *= 2.0;\n a *= 0.5;\n }\n return v;\n}\n\nstruct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @location(1) normal: vec3f, };\n@vertex fn vs(@location(0) position: vec3f, @location(1) normal: vec3f, @location(2) uv: vec2f) -> VO {\n var o: VO; o.worldPos = position; o.normal = normal;\n o.position = camera.projection * camera.view * vec4f(position, 1.0); return o;\n}\nstruct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };\n@fragment fn fs(i: VO) -> FSOut {\n // Derivatives first, unconditionally: WGSL requires fwidth in uniform control\n // flow and everything below branches on world position.\n let gp = i.worldPos.xz / material.gridSpacing;\n let gridDeriv = fwidth(gp);\n\n var out: FSOut;\n let n = normalize(i.normal);\n let centerDist = length(i.worldPos.xz);\n let edgeFade = 1.0 - smoothstep(0.0, 1.0, clamp((centerDist - material.fadeStart) / max(material.fadeEnd - material.fadeStart, 0.001), 0.0, 1.0));\n\n // Past the radial fade every term below is multiplied by edgeFade and the\n // pixel is fully transparent. Shading it anyway produces nothing.\n if (edgeFade <= 0.0) {\n out.color = vec4f(0.0);\n out.mask = vec4f(0.0, 1.0, 0.0, 0.0);\n return out;\n }\n\n let lclip = lightVP.viewProj * vec4f(i.worldPos, 1.0);\n let ndc = lclip.xyz / max(lclip.w, 1e-6);\n // Outside the light's frustum there IS no shadow information \u2014 the clamped\n // border samples compare against unrelated depths and read \"shadowed\",\n // darkening the whole far plane with a visible band at the frustum edge\n // (masked by the opaque surface normally, glaring in green-screen mode where\n // only the shadow-catcher term renders). Fade to fully lit near the border.\n let inZ = select(0.0, 1.0, ndc.z > 0.0 && ndc.z < 1.0);\n let frustum = (1.0 - smoothstep(0.88, 0.96, abs(ndc.x))) * (1.0 - smoothstep(0.88, 0.96, abs(ndc.y))) * inZ;\n\n // THE cost of this shader, measured: a full-screen ground ran 25 shadow\n // comparisons per pixel, and each one is hardware-bilinear, so ~100 depth\n // samples per pixel. Gutting the rest of the shader changed nothing; cutting\n // this is what makes looking down cheap.\n //\n // 3x3 at two-texel spacing covers the same +/-2 texel penumbra the 5x5 at\n // one-texel spacing did \u2014 that kernel was oversampled, its taps overlapping\n // almost entirely once the comparison sampler's own 2x2 filter is counted.\n // Nine taps instead of twenty-five for the same blur radius.\n //\n // Skipped altogether outside the light frustum, where the mix below discards\n // the result anyway: the shadow map covers a small area around the character\n // and the ground is vastly larger than it.\n var vis = 1.0;\n if (frustum > 0.0) {\n let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);\n let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));\n let st = material.pcfTexel * 2.0;\n let compareZ = ndc.z - 0.0035;\n var acc = 0.0;\n for (var y = -1; y <= 1; y++) {\n for (var x = -1; x <= 1; x++) {\n // ...Level, not the implicit-derivative form: identical on a single-mip\n // shadow map, and legal inside this branch.\n acc += textureSampleCompareLevel(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);\n }\n }\n vis = mix(1.0, acc * (1.0 / 9.0), frustum);\n }\n\n // Frosted/matte micro-texture. Scenes leaving it at zero were still paying\n // sixteen hash rounds a pixel for a tint of exactly 1.\n var noiseTint = 1.0;\n if (material.noiseStrength != 0.0) {\n let noiseVal = fbmNoise(i.worldPos.xz * 3.0);\n noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;\n }\n\n // Grid lines \u2014 anti-aliased via screen-space derivatives\n let gridFrac = abs(fract(gp - 0.5) - 0.5);\n let halfLine = material.gridLineWidth * 0.5;\n let gridLine = 1.0 - min(\n smoothstep(halfLine - gridDeriv.x, halfLine + gridDeriv.x, gridFrac.x),\n smoothstep(halfLine - gridDeriv.y, halfLine + gridDeriv.y, gridFrac.y)\n );\n let sun = light.ambientColor.xyz + light.lights[0].color.xyz * light.lights[0].color.w * max(dot(n, -light.lights[0].direction.xyz), 0.0);\n let dark = (1.0 - vis) * material.shadowStrength;\n var baseColor = material.diffuseColor * sun * (1.0 - dark * 0.65);\n baseColor *= noiseTint;\n let finalColor = mix(baseColor, material.gridLineColor, gridLine * material.gridLineOpacity * edgeFade);\n // Whole-ground opacity fades the SURFACE (color, grid) but the shadow stays \u2014\n // as opacity drops, the received shadow becomes a translucent dark layer\n // (Blender's Shadow Catcher), so models still feel grounded on a photo or\n // 360 backdrop. At opacity 1 this reduces exactly to the plain surface.\n let surfA = edgeFade * material.opacity;\n let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);\n let outA = surfA + catchA;\n out.color = vec4f(finalColor * surfA, outA);\n // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =\n // outA turns the aux blend into alpha-over, so the drawable alpha goes\n // from outA at the center to 0 at the radial edge \u2014 letting the page\n // background show through under the premultiplied canvas alphaMode.\n out.mask = vec4f(0.0, 1.0, 0.0, outA);\n return out;\n}\n";
2
2
  //# sourceMappingURL=ground.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,2kKA6GrC,CAAA"}
1
+ {"version":3,"file":"ground.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/ground.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,yBAAyB,gpNA8IrC,CAAA"}
@@ -49,40 +49,74 @@ struct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @l
49
49
  }
50
50
  struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
51
51
  @fragment fn fs(i: VO) -> FSOut {
52
+ // Derivatives first, unconditionally: WGSL requires fwidth in uniform control
53
+ // flow and everything below branches on world position.
54
+ let gp = i.worldPos.xz / material.gridSpacing;
55
+ let gridDeriv = fwidth(gp);
56
+
57
+ var out: FSOut;
52
58
  let n = normalize(i.normal);
53
59
  let centerDist = length(i.worldPos.xz);
54
60
  let edgeFade = 1.0 - smoothstep(0.0, 1.0, clamp((centerDist - material.fadeStart) / max(material.fadeEnd - material.fadeStart, 0.001), 0.0, 1.0));
55
61
 
62
+ // Past the radial fade every term below is multiplied by edgeFade and the
63
+ // pixel is fully transparent. Shading it anyway produces nothing.
64
+ if (edgeFade <= 0.0) {
65
+ out.color = vec4f(0.0);
66
+ out.mask = vec4f(0.0, 1.0, 0.0, 0.0);
67
+ return out;
68
+ }
69
+
56
70
  let lclip = lightVP.viewProj * vec4f(i.worldPos, 1.0);
57
71
  let ndc = lclip.xyz / max(lclip.w, 1e-6);
58
- let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
59
- let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));
60
- let st = material.pcfTexel;
61
- let compareZ = ndc.z - 0.0035;
62
- var vis = 0.0;
63
- for (var y = -2; y <= 2; y++) {
64
- for (var x = -2; x <= 2; x++) {
65
- vis += textureSampleCompare(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);
66
- }
67
- }
68
- vis *= 0.04;
69
72
  // Outside the light's frustum there IS no shadow information — the clamped
70
- // border samples above compare against unrelated depths and read "shadowed",
73
+ // border samples compare against unrelated depths and read "shadowed",
71
74
  // darkening the whole far plane with a visible band at the frustum edge
72
75
  // (masked by the opaque surface normally, glaring in green-screen mode where
73
76
  // only the shadow-catcher term renders). Fade to fully lit near the border.
74
77
  let inZ = select(0.0, 1.0, ndc.z > 0.0 && ndc.z < 1.0);
75
78
  let frustum = (1.0 - smoothstep(0.88, 0.96, abs(ndc.x))) * (1.0 - smoothstep(0.88, 0.96, abs(ndc.y))) * inZ;
76
- vis = mix(1.0, vis, frustum);
77
79
 
78
- // Frosted/matte micro-texture
79
- let noiseVal = fbmNoise(i.worldPos.xz * 3.0);
80
- let noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;
80
+ // THE cost of this shader, measured: a full-screen ground ran 25 shadow
81
+ // comparisons per pixel, and each one is hardware-bilinear, so ~100 depth
82
+ // samples per pixel. Gutting the rest of the shader changed nothing; cutting
83
+ // this is what makes looking down cheap.
84
+ //
85
+ // 3x3 at two-texel spacing covers the same +/-2 texel penumbra the 5x5 at
86
+ // one-texel spacing did — that kernel was oversampled, its taps overlapping
87
+ // almost entirely once the comparison sampler's own 2x2 filter is counted.
88
+ // Nine taps instead of twenty-five for the same blur radius.
89
+ //
90
+ // Skipped altogether outside the light frustum, where the mix below discards
91
+ // the result anyway: the shadow map covers a small area around the character
92
+ // and the ground is vastly larger than it.
93
+ var vis = 1.0;
94
+ if (frustum > 0.0) {
95
+ let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
96
+ let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));
97
+ let st = material.pcfTexel * 2.0;
98
+ let compareZ = ndc.z - 0.0035;
99
+ var acc = 0.0;
100
+ for (var y = -1; y <= 1; y++) {
101
+ for (var x = -1; x <= 1; x++) {
102
+ // ...Level, not the implicit-derivative form: identical on a single-mip
103
+ // shadow map, and legal inside this branch.
104
+ acc += textureSampleCompareLevel(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);
105
+ }
106
+ }
107
+ vis = mix(1.0, acc * (1.0 / 9.0), frustum);
108
+ }
109
+
110
+ // Frosted/matte micro-texture. Scenes leaving it at zero were still paying
111
+ // sixteen hash rounds a pixel for a tint of exactly 1.
112
+ var noiseTint = 1.0;
113
+ if (material.noiseStrength != 0.0) {
114
+ let noiseVal = fbmNoise(i.worldPos.xz * 3.0);
115
+ noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;
116
+ }
81
117
 
82
118
  // Grid lines — anti-aliased via screen-space derivatives
83
- let gp = i.worldPos.xz / material.gridSpacing;
84
119
  let gridFrac = abs(fract(gp - 0.5) - 0.5);
85
- let gridDeriv = fwidth(gp);
86
120
  let halfLine = material.gridLineWidth * 0.5;
87
121
  let gridLine = 1.0 - min(
88
122
  smoothstep(halfLine - gridDeriv.x, halfLine + gridDeriv.x, gridFrac.x),
@@ -100,7 +134,6 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
100
134
  let surfA = edgeFade * material.opacity;
101
135
  let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);
102
136
  let outA = surfA + catchA;
103
- var out: FSOut;
104
137
  out.color = vec4f(finalColor * surfA, outA);
105
138
  // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =
106
139
  // outA turns the aux blend into alpha-over, so the drawable alpha goes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reze-engine",
3
- "version": "0.33.1",
3
+ "version": "0.34.0",
4
4
  "description": "A lightweight WebGPU engine for real-time 3D MMD/PMX model rendering",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
package/src/engine.ts CHANGED
@@ -7,6 +7,7 @@ import { VMDLoader } from "./vmd-loader"
7
7
  import { CameraAnimation } from "./camera-animation"
8
8
  import { PmxLoader } from "./pmx-loader"
9
9
  import { RezePhysics } from "./physics"
10
+ import type { WindOptions } from "./physics/world"
10
11
  import {
11
12
  createFetchAssetReader,
12
13
  createFileMapAssetReader,
@@ -799,6 +800,10 @@ export class Engine {
799
800
  // IK and physics enabled at engine level (same for all models)
800
801
  private ikEnabled = true
801
802
  private physicsEnabled = true
803
+ // World-wide, not per-model: MMD treats gravity and wind as properties of the
804
+ // scene, and a model loaded later must arrive into the same air as the rest.
805
+ private gravity = new Vec3(0, -98, 0)
806
+ private wind: WindOptions | null = null
802
807
  // GPU vertex-morph path. Set false BEFORE loadModel to fall back to the CPU path (A/B).
803
808
  private useGpuMorphs = true
804
809
 
@@ -2987,32 +2992,20 @@ export class Engine {
2987
2992
  return { ...this.stats }
2988
2993
  }
2989
2994
 
2990
- /** Frame-rate cap for the render loop, or null for display-rate. On high-refresh
2991
- * displays (144/240Hz) rAF runs the WHOLE pipeline physics, IK, blending,
2992
- * passes that many times per second for no visible gain over ~120 (VMD content
2993
- * is 30fps; blending interpolates). Capping restores the per-second budget. */
2994
- private maxFPS: number | null = null
2995
- private lastLoopTime = 0
2996
-
2997
- setMaxFPS(fps: number | null): void {
2998
- this.maxFPS = fps !== null && fps > 0 ? fps : null
2999
- }
3000
-
2995
+ // The render loop runs at display rate, always. A frame-rate cap used to be
2996
+ // offered here for high-refresh displays, on the reasoning that VMD content
2997
+ // is 30fps and running the whole pipeline at 240 buys nothing. Nothing ever
2998
+ // called it every product in the family chases native refresh, because
2999
+ // dropping frames a display can show is the one thing that reads as cheap.
3000
+ // Physics already decouples: it steps at a fixed 60Hz behind an accumulator
3001
+ // and the drawn pose is interpolated between substeps, so a 240Hz display
3002
+ // costs four interpolations per simulation step, not four simulations.
3001
3003
  runRenderLoop(callback?: () => void) {
3002
3004
  this.renderLoopCallback = callback || null
3003
3005
 
3004
- const loop = (now: number) => {
3006
+ const loop = () => {
3005
3007
  this.animationFrameId = requestAnimationFrame(loop)
3006
-
3007
- if (this.maxFPS !== null) {
3008
- // Tolerate rAF jitter: accept frames within ~half a display tick early.
3009
- const minInterval = 1000 / this.maxFPS - 2
3010
- if (now - this.lastLoopTime < minInterval) return
3011
- this.lastLoopTime = now
3012
- }
3013
-
3014
3008
  this.render()
3015
-
3016
3009
  if (this.renderLoopCallback) {
3017
3010
  this.renderLoopCallback()
3018
3011
  }
@@ -3261,6 +3254,39 @@ export class Engine {
3261
3254
  return this.physicsEnabled
3262
3255
  }
3263
3256
 
3257
+ /**
3258
+ * Scene gravity, applied to every model's cloth and hair. The default is
3259
+ * (0, -98, 0) — MMD's own scale, where a character stands about 20 units
3260
+ * tall. Lower magnitudes float; tilting it sideways hangs everything on a
3261
+ * slant, which is the cheap way to fake a strong draught.
3262
+ */
3263
+ setGravity(gravity: Vec3): void {
3264
+ this.gravity = new Vec3(gravity.x, gravity.y, gravity.z)
3265
+ this.forEachInstance((inst) => inst.physics?.setGravity(this.gravity))
3266
+ }
3267
+
3268
+ getGravity(): Vec3 {
3269
+ return new Vec3(this.gravity.x, this.gravity.y, this.gravity.z)
3270
+ }
3271
+
3272
+ /**
3273
+ * Air movement across the scene — null is still air.
3274
+ *
3275
+ * Applied as an acceleration alongside gravity, so `strength` is in the same
3276
+ * units: against the default gravity of 98, a strength of 10-30 reads as a
3277
+ * breeze through hair and a skirt without lifting them off the body. Gusting
3278
+ * is driven by simulated time rather than wall time, so an exported take
3279
+ * gusts exactly as the preview did.
3280
+ */
3281
+ setWind(wind: WindOptions | null): void {
3282
+ this.wind = wind ? { ...wind, direction: new Vec3(wind.direction.x, wind.direction.y, wind.direction.z) } : null
3283
+ this.forEachInstance((inst) => inst.physics?.setWind(this.wind))
3284
+ }
3285
+
3286
+ getWind(): WindOptions | null {
3287
+ return this.wind ? { ...this.wind, direction: new Vec3(this.wind.direction.x, this.wind.direction.y, this.wind.direction.z) } : null
3288
+ }
3289
+
3264
3290
  resetPhysics(): void {
3265
3291
  this.forEachInstance((inst) => {
3266
3292
  if (!inst.physics) return
@@ -3433,6 +3459,12 @@ export class Engine {
3433
3459
 
3434
3460
  const rbs = model.getRigidbodies()
3435
3461
  const physics = rbs.length > 0 ? new RezePhysics(rbs, model.getJoints()) : null
3462
+ // Adopt the scene's air, or a model added mid-session would fall under
3463
+ // different gravity from the ones already on stage.
3464
+ if (physics) {
3465
+ physics.setGravity(this.gravity)
3466
+ if (this.wind) physics.setWind(this.wind)
3467
+ }
3436
3468
 
3437
3469
  const shadowBindGroup = this.device.createBindGroup({
3438
3470
  label: `${name}: shadow bind`,
@@ -3694,6 +3726,7 @@ export class Engine {
3694
3726
  })
3695
3727
  }
3696
3728
 
3729
+
3697
3730
  // Shadow is cast from the visible sun direction — same vector the shader lights with.
3698
3731
  /** Whether the shadow map needs clearing — see the shadow pass in `render`.
3699
3732
  *
package/src/index.ts CHANGED
@@ -86,4 +86,5 @@ export { VMDLoader, type CameraKeyframe, type IkFrame } from "./vmd-loader"
86
86
  export { VMDWriter } from "./vmd-writer"
87
87
  export { PmxLoader } from "./pmx-loader"
88
88
  export { CameraAnimation, type CameraPose } from "./camera-animation"
89
- export { RezePhysics } from "./physics"
89
+ export { RezePhysics } from "./physics"
90
+ export type { WindOptions } from "./physics/world"
@@ -2,7 +2,7 @@ import { Vec3, Quat, Mat4 } from "../math"
2
2
  import type { Rigidbody, Joint } from "./types"
3
3
  import { RigidbodyType, RigidbodyShape } from "./types"
4
4
  import { RigidBodyStore } from "./body"
5
- import { World } from "./world"
5
+ import { World, type WindOptions } from "./world"
6
6
  import { buildConstraints, type SixDofSpringConstraint } from "./constraint"
7
7
  import { SolverCache } from "./solver"
8
8
  import { ContactPool } from "./contact"
@@ -166,6 +166,13 @@ export class RezePhysics {
166
166
  getGravity(): Vec3 {
167
167
  return this.world.gravity
168
168
  }
169
+ /** World-wide air movement. See {@link WindOptions}; null is still air. */
170
+ setWind(wind: WindOptions | null): void {
171
+ this.world.setWind(wind)
172
+ }
173
+ getWind(): WindOptions | null {
174
+ return this.world.getWind()
175
+ }
169
176
  getRigidbodies(): Rigidbody[] {
170
177
  return this.rigidbodies
171
178
  }
@@ -10,6 +10,30 @@ import { findContacts, type ContactPool } from "./contact"
10
10
  // integrate; the parent class syncs them from bones around the step. The
11
11
  // solver pass runs on all bodies — kinematic ones have invMass = 0 and
12
12
  // act as anchors.
13
+ /**
14
+ * Air movement across the whole world.
15
+ *
16
+ * Applied as an acceleration alongside gravity, which is the same shape MMD's
17
+ * own wind plugins take and keeps it free: gravity and wind are summed once per
18
+ * substep, so the per-body predict loop is untouched. Terminal velocity comes
19
+ * out of the existing per-body damping rather than a drag model — PMX authors
20
+ * already tune that damping to get the hang they want, and a second, hidden
21
+ * drag term would fight it.
22
+ */
23
+ export interface WindOptions {
24
+ /** Direction the air travels. Normalised on assignment; a zero vector is off. */
25
+ direction: Vec3
26
+ /** Acceleration along it, in gravity's units — the built-in gravity is 98. */
27
+ strength: number
28
+ /** Gust depth, clamped to 0–1. 0 is a steady breeze; 1 swings between still
29
+ * and double. It is a clamp rather than a free scalar because past 1 the
30
+ * swing goes negative and the wind blows backwards on every other beat,
31
+ * which is never what a caller meant by "more turbulent". */
32
+ turbulence?: number
33
+ /** Gusts per second. */
34
+ frequency?: number
35
+ }
36
+
13
37
  export class World {
14
38
  readonly gravity: Vec3
15
39
  solverIterations = 10
@@ -20,6 +44,17 @@ export class World {
20
44
  private linDampFactor: Float32Array | null = null
21
45
  private angDampFactor: Float32Array | null = null
22
46
 
47
+ // Wind, resolved to a direction × strength at construction of the options so
48
+ // the step loop only multiplies by a gust scalar.
49
+ private windX = 0
50
+ private windY = 0
51
+ private windZ = 0
52
+ private windTurbulence = 0
53
+ private windFrequency = 0.35
54
+ /** Advances with simulated time, not wall time, so a scrubbed or exported
55
+ * take gusts identically to a live one. */
56
+ private windClock = 0
57
+
23
58
  constructor(gravity: Vec3) {
24
59
  this.gravity = new Vec3(gravity.x, gravity.y, gravity.z)
25
60
  }
@@ -30,6 +65,37 @@ export class World {
30
65
  this.gravity.z = g.z
31
66
  }
32
67
 
68
+ setWind(wind: WindOptions | null): void {
69
+ // Shape first, and unconditionally: bailing out early on a zero strength
70
+ // used to leave turbulence and frequency holding whatever a previous call
71
+ // set, so raising the strength again resurrected settings the caller had
72
+ // since replaced.
73
+ this.windTurbulence = Math.min(1, Math.max(0, wind?.turbulence ?? 0))
74
+ this.windFrequency = Math.max(0, wind?.frequency ?? 0.35)
75
+
76
+ const d = wind?.direction
77
+ const len = d ? Math.hypot(d.x, d.y, d.z) : 0
78
+ if (!wind || !d || len < 1e-9 || wind.strength === 0) {
79
+ this.windX = this.windY = this.windZ = 0
80
+ return
81
+ }
82
+ const s = wind.strength / len
83
+ this.windX = d.x * s
84
+ this.windY = d.y * s
85
+ this.windZ = d.z * s
86
+ }
87
+
88
+ getWind(): WindOptions | null {
89
+ const strength = Math.hypot(this.windX, this.windY, this.windZ)
90
+ if (strength === 0) return null
91
+ return {
92
+ direction: new Vec3(this.windX / strength, this.windY / strength, this.windZ / strength),
93
+ strength,
94
+ turbulence: this.windTurbulence,
95
+ frequency: this.windFrequency,
96
+ }
97
+ }
98
+
33
99
  step(
34
100
  store: RigidBodyStore,
35
101
  constraints: SixDofSpringConstraint[],
@@ -49,9 +115,24 @@ export class World {
49
115
  const adamp = store.angularDamping
50
116
  const invMass = store.invMass
51
117
 
52
- const gx = this.gravity.x
53
- const gy = this.gravity.y
54
- const gz = this.gravity.z
118
+ // Gravity and wind are the same kind of term, so they are summed here and
119
+ // the predict loop below never learns wind exists.
120
+ let gx = this.gravity.x
121
+ let gy = this.gravity.y
122
+ let gz = this.gravity.z
123
+ if (this.windX !== 0 || this.windY !== 0 || this.windZ !== 0) {
124
+ this.windClock += dt
125
+ let gust = 1
126
+ if (this.windTurbulence > 0 && this.windFrequency > 0) {
127
+ // Two incommensurate sines: a single one is a metronome, and real gusts
128
+ // do not repeat on a bar line. Stays within 1 ± turbulence.
129
+ const t = this.windClock * this.windFrequency * Math.PI * 2
130
+ gust = 1 + this.windTurbulence * 0.5 * (Math.sin(t) + Math.sin(t * 0.37 + 1.3))
131
+ }
132
+ gx += this.windX * gust
133
+ gy += this.windY * gust
134
+ gz += this.windZ * gust
135
+ }
55
136
 
56
137
  // 1. Predict — gravity + damping. The pow form (vs the linear
57
138
  // 1−damping·dt approximation) stays stable at high PMX damping
@@ -50,40 +50,74 @@ struct VO { @builtin(position) position: vec4f, @location(0) worldPos: vec3f, @l
50
50
  }
51
51
  struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
52
52
  @fragment fn fs(i: VO) -> FSOut {
53
+ // Derivatives first, unconditionally: WGSL requires fwidth in uniform control
54
+ // flow and everything below branches on world position.
55
+ let gp = i.worldPos.xz / material.gridSpacing;
56
+ let gridDeriv = fwidth(gp);
57
+
58
+ var out: FSOut;
53
59
  let n = normalize(i.normal);
54
60
  let centerDist = length(i.worldPos.xz);
55
61
  let edgeFade = 1.0 - smoothstep(0.0, 1.0, clamp((centerDist - material.fadeStart) / max(material.fadeEnd - material.fadeStart, 0.001), 0.0, 1.0));
56
62
 
63
+ // Past the radial fade every term below is multiplied by edgeFade and the
64
+ // pixel is fully transparent. Shading it anyway produces nothing.
65
+ if (edgeFade <= 0.0) {
66
+ out.color = vec4f(0.0);
67
+ out.mask = vec4f(0.0, 1.0, 0.0, 0.0);
68
+ return out;
69
+ }
70
+
57
71
  let lclip = lightVP.viewProj * vec4f(i.worldPos, 1.0);
58
72
  let ndc = lclip.xyz / max(lclip.w, 1e-6);
59
- let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
60
- let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));
61
- let st = material.pcfTexel;
62
- let compareZ = ndc.z - 0.0035;
63
- var vis = 0.0;
64
- for (var y = -2; y <= 2; y++) {
65
- for (var x = -2; x <= 2; x++) {
66
- vis += textureSampleCompare(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);
67
- }
68
- }
69
- vis *= 0.04;
70
73
  // Outside the light's frustum there IS no shadow information — the clamped
71
- // border samples above compare against unrelated depths and read "shadowed",
74
+ // border samples compare against unrelated depths and read "shadowed",
72
75
  // darkening the whole far plane with a visible band at the frustum edge
73
76
  // (masked by the opaque surface normally, glaring in green-screen mode where
74
77
  // only the shadow-catcher term renders). Fade to fully lit near the border.
75
78
  let inZ = select(0.0, 1.0, ndc.z > 0.0 && ndc.z < 1.0);
76
79
  let frustum = (1.0 - smoothstep(0.88, 0.96, abs(ndc.x))) * (1.0 - smoothstep(0.88, 0.96, abs(ndc.y))) * inZ;
77
- vis = mix(1.0, vis, frustum);
78
80
 
79
- // Frosted/matte micro-texture
80
- let noiseVal = fbmNoise(i.worldPos.xz * 3.0);
81
- let noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;
81
+ // THE cost of this shader, measured: a full-screen ground ran 25 shadow
82
+ // comparisons per pixel, and each one is hardware-bilinear, so ~100 depth
83
+ // samples per pixel. Gutting the rest of the shader changed nothing; cutting
84
+ // this is what makes looking down cheap.
85
+ //
86
+ // 3x3 at two-texel spacing covers the same +/-2 texel penumbra the 5x5 at
87
+ // one-texel spacing did — that kernel was oversampled, its taps overlapping
88
+ // almost entirely once the comparison sampler's own 2x2 filter is counted.
89
+ // Nine taps instead of twenty-five for the same blur radius.
90
+ //
91
+ // Skipped altogether outside the light frustum, where the mix below discards
92
+ // the result anyway: the shadow map covers a small area around the character
93
+ // and the ground is vastly larger than it.
94
+ var vis = 1.0;
95
+ if (frustum > 0.0) {
96
+ let suv = vec2f(ndc.x * 0.5 + 0.5, 0.5 - ndc.y * 0.5);
97
+ let suv_c = clamp(suv, vec2f(0.02), vec2f(0.98));
98
+ let st = material.pcfTexel * 2.0;
99
+ let compareZ = ndc.z - 0.0035;
100
+ var acc = 0.0;
101
+ for (var y = -1; y <= 1; y++) {
102
+ for (var x = -1; x <= 1; x++) {
103
+ // ...Level, not the implicit-derivative form: identical on a single-mip
104
+ // shadow map, and legal inside this branch.
105
+ acc += textureSampleCompareLevel(shadowMap, shadowSampler, suv_c + vec2f(f32(x), f32(y)) * st, compareZ);
106
+ }
107
+ }
108
+ vis = mix(1.0, acc * (1.0 / 9.0), frustum);
109
+ }
110
+
111
+ // Frosted/matte micro-texture. Scenes leaving it at zero were still paying
112
+ // sixteen hash rounds a pixel for a tint of exactly 1.
113
+ var noiseTint = 1.0;
114
+ if (material.noiseStrength != 0.0) {
115
+ let noiseVal = fbmNoise(i.worldPos.xz * 3.0);
116
+ noiseTint = 1.0 + (noiseVal - 0.5) * material.noiseStrength;
117
+ }
82
118
 
83
119
  // Grid lines — anti-aliased via screen-space derivatives
84
- let gp = i.worldPos.xz / material.gridSpacing;
85
120
  let gridFrac = abs(fract(gp - 0.5) - 0.5);
86
- let gridDeriv = fwidth(gp);
87
121
  let halfLine = material.gridLineWidth * 0.5;
88
122
  let gridLine = 1.0 - min(
89
123
  smoothstep(halfLine - gridDeriv.x, halfLine + gridDeriv.x, gridFrac.x),
@@ -101,7 +135,6 @@ struct FSOut { @location(0) color: vec4f, @location(1) mask: vec4f };
101
135
  let surfA = edgeFade * material.opacity;
102
136
  let catchA = dark * 0.65 * edgeFade * (1.0 - material.opacity);
103
137
  let outA = surfA + catchA;
104
- var out: FSOut;
105
138
  out.color = vec4f(finalColor * surfA, outA);
106
139
  // mask.r = 0: ground never contributes to bloom. mask.g = 1.0 with src.a =
107
140
  // outA turns the aux blend into alpha-over, so the drawable alpha goes