reze-engine 0.33.2 → 0.35.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 +13 -8
- package/dist/engine.d.ts +22 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +40 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/physics/contact.d.ts +3 -0
- package/dist/physics/contact.d.ts.map +1 -1
- package/dist/physics/contact.js +386 -19
- package/dist/physics/manifold.d.ts +13 -0
- package/dist/physics/manifold.d.ts.map +1 -0
- package/dist/physics/manifold.js +68 -0
- package/dist/physics/physics.d.ts +4 -0
- package/dist/physics/physics.d.ts.map +1 -1
- package/dist/physics/physics.js +7 -0
- package/dist/physics/solver.d.ts.map +1 -1
- package/dist/physics/solver.js +64 -4
- package/dist/physics/world.d.ts +33 -0
- package/dist/physics/world.d.ts.map +1 -1
- package/dist/physics/world.js +57 -8
- package/package.json +1 -1
- package/src/engine.ts +44 -0
- package/src/index.ts +2 -1
- package/src/physics/contact.ts +410 -15
- package/src/physics/physics.ts +8 -1
- package/src/physics/solver.ts +64 -3
- package/src/physics/world.ts +84 -3
package/src/physics/world.ts
CHANGED
|
@@ -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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|