reze-engine 0.14.0 → 0.15.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/README.md +81 -108
- package/dist/engine.d.ts +1 -7
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +4 -7
- package/dist/gpu-profile.d.ts +19 -0
- package/dist/gpu-profile.d.ts.map +1 -0
- package/dist/gpu-profile.js +120 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/physics/body.d.ts +32 -0
- package/dist/physics/body.d.ts.map +1 -0
- package/dist/physics/body.js +245 -0
- package/dist/physics/constraint.d.ts +30 -0
- package/dist/physics/constraint.d.ts.map +1 -0
- package/dist/physics/constraint.js +115 -0
- package/dist/physics/contact.d.ts +60 -0
- package/dist/physics/contact.d.ts.map +1 -0
- package/dist/physics/contact.js +723 -0
- package/dist/physics/index.d.ts +4 -0
- package/dist/physics/index.d.ts.map +1 -0
- package/dist/physics/index.js +3 -0
- package/dist/physics/physics.d.ts +31 -0
- package/dist/physics/physics.d.ts.map +1 -0
- package/dist/physics/physics.js +209 -0
- package/dist/physics/profile.d.ts +18 -0
- package/dist/physics/profile.d.ts.map +1 -0
- package/dist/physics/profile.js +44 -0
- package/dist/physics/solver.d.ts +5 -0
- package/dist/physics/solver.d.ts.map +1 -0
- package/dist/physics/solver.js +559 -0
- package/dist/physics/types.d.ts +46 -0
- package/dist/physics/types.d.ts.map +1 -0
- package/dist/physics/types.js +12 -0
- package/dist/physics/world.d.ts +12 -0
- package/dist/physics/world.d.ts.map +1 -0
- package/dist/physics/world.js +146 -0
- package/dist/shaders/materials/hair.d.ts +1 -1
- package/dist/shaders/materials/hair.d.ts.map +1 -1
- package/dist/shaders/materials/hair.js +2 -2
- package/package.json +3 -6
- package/src/engine.ts +5 -9
- package/src/index.ts +1 -1
- package/src/physics/body.ts +334 -0
- package/src/physics/constraint.ts +181 -0
- package/src/physics/contact.ts +996 -0
- package/src/physics/index.ts +8 -0
- package/src/physics/physics.ts +253 -0
- package/src/physics/solver.ts +577 -0
- package/src/physics/types.ts +50 -0
- package/src/physics/world.ts +152 -0
- package/src/shaders/materials/hair.ts +2 -2
- package/dist/ammo-loader.d.ts +0 -3
- package/dist/ammo-loader.d.ts.map +0 -1
- package/dist/ammo-loader.js +0 -26
- package/dist/physics.d.ts +0 -86
- package/dist/physics.d.ts.map +0 -1
- package/dist/physics.js +0 -527
- package/dist/shaders/body.d.ts +0 -2
- package/dist/shaders/body.d.ts.map +0 -1
- package/dist/shaders/body.js +0 -199
- package/dist/shaders/classify.d.ts +0 -4
- package/dist/shaders/classify.d.ts.map +0 -1
- package/dist/shaders/classify.js +0 -12
- package/dist/shaders/cloth_rough.d.ts +0 -2
- package/dist/shaders/cloth_rough.d.ts.map +0 -1
- package/dist/shaders/cloth_rough.js +0 -178
- package/dist/shaders/cloth_smooth.d.ts +0 -2
- package/dist/shaders/cloth_smooth.d.ts.map +0 -1
- package/dist/shaders/cloth_smooth.js +0 -174
- package/dist/shaders/default.d.ts +0 -2
- package/dist/shaders/default.d.ts.map +0 -1
- package/dist/shaders/default.js +0 -171
- package/dist/shaders/eye.d.ts +0 -2
- package/dist/shaders/eye.d.ts.map +0 -1
- package/dist/shaders/eye.js +0 -146
- package/dist/shaders/face.d.ts +0 -2
- package/dist/shaders/face.d.ts.map +0 -1
- package/dist/shaders/face.js +0 -199
- package/dist/shaders/hair.d.ts +0 -2
- package/dist/shaders/hair.d.ts.map +0 -1
- package/dist/shaders/hair.js +0 -176
- package/dist/shaders/metal.d.ts +0 -2
- package/dist/shaders/metal.d.ts.map +0 -1
- package/dist/shaders/metal.js +0 -174
- package/dist/shaders/nodes.d.ts +0 -2
- package/dist/shaders/nodes.d.ts.map +0 -1
- package/dist/shaders/nodes.js +0 -456
- package/dist/shaders/stockings.d.ts +0 -2
- package/dist/shaders/stockings.d.ts.map +0 -1
- package/dist/shaders/stockings.js +0 -244
- package/src/ammo-loader.ts +0 -31
- package/src/physics.ts +0 -706
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Rigidbody } from "./types";
|
|
2
|
+
export declare class RigidBodyStore {
|
|
3
|
+
readonly count: number;
|
|
4
|
+
readonly positions: Float32Array;
|
|
5
|
+
readonly orientations: Float32Array;
|
|
6
|
+
readonly linearVelocities: Float32Array;
|
|
7
|
+
readonly angularVelocities: Float32Array;
|
|
8
|
+
readonly invMass: Float32Array;
|
|
9
|
+
readonly invInertia: Float32Array;
|
|
10
|
+
readonly linearDamping: Float32Array;
|
|
11
|
+
readonly angularDamping: Float32Array;
|
|
12
|
+
readonly type: Uint8Array;
|
|
13
|
+
readonly boneIndex: Int32Array;
|
|
14
|
+
readonly friction: Float32Array;
|
|
15
|
+
readonly restitution: Float32Array;
|
|
16
|
+
readonly collisionGroup: Uint16Array;
|
|
17
|
+
readonly willCollideMask: Uint16Array;
|
|
18
|
+
readonly shape: Uint8Array;
|
|
19
|
+
readonly size: Float32Array;
|
|
20
|
+
readonly aabbMin: Float32Array;
|
|
21
|
+
readonly aabbMax: Float32Array;
|
|
22
|
+
readonly bodyOffsetMatrix: Float32Array;
|
|
23
|
+
readonly bodyOffsetInverse: Float32Array;
|
|
24
|
+
private boneOffsetsReady;
|
|
25
|
+
private collisionPairs;
|
|
26
|
+
constructor(rigidbodies: Rigidbody[]);
|
|
27
|
+
updateAabbs(margin?: number): void;
|
|
28
|
+
computeBoneOffsets(boneInverseBindMatrices: Float32Array): void;
|
|
29
|
+
isBoneOffsetsReady(): boolean;
|
|
30
|
+
getCollisionPairs(): Uint16Array;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../../src/physics/body.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AAIvE,qBAAa,cAAc;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,gBAAgB,EAAE,YAAY,CAAA;IACvC,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAA;IAExC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;IAI9B,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAA;IACjC,QAAQ,CAAC,aAAa,EAAE,YAAY,CAAA;IACpC,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAA;IACrC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;IAC9B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAA;IAIlC,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAA;IACpC,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAA;IAErC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAE3B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;IAC9B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;IAI9B,QAAQ,CAAC,gBAAgB,EAAE,YAAY,CAAA;IACvC,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAA;IACxC,OAAO,CAAC,gBAAgB,CAAQ;IAMhC,OAAO,CAAC,cAAc,CAA2B;gBAErC,WAAW,EAAE,SAAS,EAAE;IA4DpC,WAAW,CAAC,MAAM,SAAM,GAAG,IAAI;IA2F/B,kBAAkB,CAAC,uBAAuB,EAAE,YAAY,GAAG,IAAI;IAqD/D,kBAAkB,IAAI,OAAO;IAM7B,iBAAiB,IAAI,WAAW;CAoBjC"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { Mat4, Quat } from "../math";
|
|
2
|
+
import { RigidbodyType, RigidbodyShape } from "./types";
|
|
3
|
+
// SoA storage for all rigid bodies. Per-body state, constants, bone-coupling
|
|
4
|
+
// matrices, and a per-step AABB.
|
|
5
|
+
export class RigidBodyStore {
|
|
6
|
+
constructor(rigidbodies) {
|
|
7
|
+
this.boneOffsetsReady = false;
|
|
8
|
+
// Flat list of (i, j) pairs that survive the static-static + group/mask
|
|
9
|
+
// filter. None of those inputs change after construction, so building this
|
|
10
|
+
// once collapses 60k pair tests/step (349 bodies) down to a few thousand.
|
|
11
|
+
// Built lazily on first access.
|
|
12
|
+
this.collisionPairs = null;
|
|
13
|
+
const N = rigidbodies.length;
|
|
14
|
+
this.count = N;
|
|
15
|
+
this.positions = new Float32Array(N * 3);
|
|
16
|
+
this.orientations = new Float32Array(N * 4);
|
|
17
|
+
this.linearVelocities = new Float32Array(N * 3);
|
|
18
|
+
this.angularVelocities = new Float32Array(N * 3);
|
|
19
|
+
this.invMass = new Float32Array(N);
|
|
20
|
+
this.invInertia = new Float32Array(N);
|
|
21
|
+
this.linearDamping = new Float32Array(N);
|
|
22
|
+
this.angularDamping = new Float32Array(N);
|
|
23
|
+
this.type = new Uint8Array(N);
|
|
24
|
+
this.boneIndex = new Int32Array(N);
|
|
25
|
+
this.bodyOffsetMatrix = new Float32Array(N * 16);
|
|
26
|
+
this.bodyOffsetInverse = new Float32Array(N * 16);
|
|
27
|
+
this.friction = new Float32Array(N);
|
|
28
|
+
this.restitution = new Float32Array(N);
|
|
29
|
+
this.collisionGroup = new Uint16Array(N);
|
|
30
|
+
this.willCollideMask = new Uint16Array(N);
|
|
31
|
+
this.shape = new Uint8Array(N);
|
|
32
|
+
this.size = new Float32Array(N * 3);
|
|
33
|
+
this.aabbMin = new Float32Array(N * 3);
|
|
34
|
+
this.aabbMax = new Float32Array(N * 3);
|
|
35
|
+
for (let i = 0; i < N; i++) {
|
|
36
|
+
const rb = rigidbodies[i];
|
|
37
|
+
const i3 = i * 3;
|
|
38
|
+
const i4 = i * 4;
|
|
39
|
+
this.positions[i3 + 0] = rb.shapePosition.x;
|
|
40
|
+
this.positions[i3 + 1] = rb.shapePosition.y;
|
|
41
|
+
this.positions[i3 + 2] = rb.shapePosition.z;
|
|
42
|
+
const q = Quat.fromEuler(rb.shapeRotation.x, rb.shapeRotation.y, rb.shapeRotation.z);
|
|
43
|
+
this.orientations[i4 + 0] = q.x;
|
|
44
|
+
this.orientations[i4 + 1] = q.y;
|
|
45
|
+
this.orientations[i4 + 2] = q.z;
|
|
46
|
+
this.orientations[i4 + 3] = q.w;
|
|
47
|
+
const dynamic = rb.type === RigidbodyType.Dynamic && rb.mass > 0;
|
|
48
|
+
this.invMass[i] = dynamic ? 1 / rb.mass : 0;
|
|
49
|
+
this.invInertia[i] = dynamic ? computeInvInertia(rb) : 0;
|
|
50
|
+
this.linearDamping[i] = rb.linearDamping;
|
|
51
|
+
this.angularDamping[i] = rb.angularDamping;
|
|
52
|
+
this.type[i] = rb.type;
|
|
53
|
+
this.boneIndex[i] = rb.boneIndex;
|
|
54
|
+
this.friction[i] = rb.friction;
|
|
55
|
+
this.restitution[i] = rb.restitution;
|
|
56
|
+
this.collisionGroup[i] = 1 << (rb.group & 0xf);
|
|
57
|
+
this.willCollideMask[i] = rb.collisionMask & 0xffff;
|
|
58
|
+
this.shape[i] = rb.shape;
|
|
59
|
+
this.size[i * 3 + 0] = rb.size.x;
|
|
60
|
+
this.size[i * 3 + 1] = rb.size.y;
|
|
61
|
+
this.size[i * 3 + 2] = rb.size.z;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// World-space AABBs for every body. Inflated by margin so contacts stay
|
|
65
|
+
// paired across small velocity jitter without recomputing per iteration.
|
|
66
|
+
updateAabbs(margin = 0.5) {
|
|
67
|
+
const N = this.count;
|
|
68
|
+
const pos = this.positions;
|
|
69
|
+
const ori = this.orientations;
|
|
70
|
+
const shapes = this.shape;
|
|
71
|
+
const sz = this.size;
|
|
72
|
+
const minA = this.aabbMin;
|
|
73
|
+
const maxA = this.aabbMax;
|
|
74
|
+
for (let i = 0; i < N; i++) {
|
|
75
|
+
const i3 = i * 3;
|
|
76
|
+
const i4 = i * 4;
|
|
77
|
+
const px = pos[i3 + 0], py = pos[i3 + 1], pz = pos[i3 + 2];
|
|
78
|
+
let hx = 0, hy = 0, hz = 0;
|
|
79
|
+
switch (shapes[i]) {
|
|
80
|
+
case RigidbodyShape.Sphere: {
|
|
81
|
+
const r = sz[i3 + 0];
|
|
82
|
+
hx = hy = hz = r;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case RigidbodyShape.Box: {
|
|
86
|
+
// OBB AABB: half-extents projected by |R|·size.
|
|
87
|
+
const qx = ori[i4 + 0], qy = ori[i4 + 1], qz = ori[i4 + 2], qw = ori[i4 + 3];
|
|
88
|
+
const x2 = qx + qx, y2 = qy + qy, z2 = qz + qz;
|
|
89
|
+
const xx = qx * x2, yy = qy * y2, zz = qz * z2;
|
|
90
|
+
const xy = qx * y2, xz = qx * z2, yz = qy * z2;
|
|
91
|
+
const wx = qw * x2, wy = qw * y2, wz = qw * z2;
|
|
92
|
+
const m00 = Math.abs(1 - (yy + zz)), m01 = Math.abs(xy + wz), m02 = Math.abs(xz - wy);
|
|
93
|
+
const m10 = Math.abs(xy - wz), m11 = Math.abs(1 - (xx + zz)), m12 = Math.abs(yz + wx);
|
|
94
|
+
const m20 = Math.abs(xz + wy), m21 = Math.abs(yz - wx), m22 = Math.abs(1 - (xx + yy));
|
|
95
|
+
const sx = sz[i3 + 0], sy = sz[i3 + 1], szz = sz[i3 + 2];
|
|
96
|
+
hx = m00 * sx + m01 * sy + m02 * szz;
|
|
97
|
+
hy = m10 * sx + m11 * sy + m12 * szz;
|
|
98
|
+
hz = m20 * sx + m21 * sy + m22 * szz;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case RigidbodyShape.Capsule: {
|
|
102
|
+
// After rotation, cap offsets are ±halfH · R·ŷ, so AABB half-
|
|
103
|
+
// extents = |R·ŷ|·halfH + radius.
|
|
104
|
+
const r = sz[i3 + 0];
|
|
105
|
+
const halfH = sz[i3 + 1] * 0.5;
|
|
106
|
+
const qx = ori[i4 + 0], qy = ori[i4 + 1], qz = ori[i4 + 2], qw = ori[i4 + 3];
|
|
107
|
+
// R · (0,1,0) = (2(xy − wz), 1 − 2(xx + zz), 2(yz + wx))
|
|
108
|
+
const rx = 2 * (qx * qy - qw * qz);
|
|
109
|
+
const ry = 1 - 2 * (qx * qx + qz * qz);
|
|
110
|
+
const rz = 2 * (qy * qz + qw * qx);
|
|
111
|
+
hx = Math.abs(rx) * halfH + r;
|
|
112
|
+
hy = Math.abs(ry) * halfH + r;
|
|
113
|
+
hz = Math.abs(rz) * halfH + r;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
minA[i3 + 0] = px - hx - margin;
|
|
118
|
+
minA[i3 + 1] = py - hy - margin;
|
|
119
|
+
minA[i3 + 2] = pz - hz - margin;
|
|
120
|
+
maxA[i3 + 0] = px + hx + margin;
|
|
121
|
+
maxA[i3 + 1] = py + hy + margin;
|
|
122
|
+
maxA[i3 + 2] = pz + hz + margin;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Compute bone-coupling matrices once, on the first step. Bodies with
|
|
126
|
+
// boneIndex < 0 get identity offsets.
|
|
127
|
+
computeBoneOffsets(boneInverseBindMatrices) {
|
|
128
|
+
const N = this.count;
|
|
129
|
+
const offsets = this.bodyOffsetMatrix;
|
|
130
|
+
const inverses = this.bodyOffsetInverse;
|
|
131
|
+
const ori = this.orientations;
|
|
132
|
+
const pos = this.positions;
|
|
133
|
+
const boneIdx = this.boneIndex;
|
|
134
|
+
const totalBones = boneInverseBindMatrices.length / 16;
|
|
135
|
+
const shapeWorldBind = _scratchA;
|
|
136
|
+
const offsetMat = _scratchB;
|
|
137
|
+
for (let i = 0; i < N; i++) {
|
|
138
|
+
const dst = i * 16;
|
|
139
|
+
const b = boneIdx[i];
|
|
140
|
+
if (b < 0 || b >= totalBones) {
|
|
141
|
+
identity16(offsets, dst);
|
|
142
|
+
identity16(inverses, dst);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
// shapeWorldBind = T(shapePosition) · R(shapeRotation)
|
|
146
|
+
const i3 = i * 3;
|
|
147
|
+
const i4 = i * 4;
|
|
148
|
+
Mat4.fromPositionRotationInto(pos[i3 + 0], pos[i3 + 1], pos[i3 + 2], ori[i4 + 0], ori[i4 + 1], ori[i4 + 2], ori[i4 + 3], shapeWorldBind);
|
|
149
|
+
// bodyOffset = boneInverseBind × shapeWorldBind
|
|
150
|
+
Mat4.multiplyArrays(boneInverseBindMatrices, b * 16, shapeWorldBind, 0, offsetMat, 0);
|
|
151
|
+
// Copy into offsets[dst] and invert into inverses[dst].
|
|
152
|
+
offsets.set(offsetMat, dst);
|
|
153
|
+
const inverseTmp = _scratchC;
|
|
154
|
+
const ok = Mat4.inverseInto(offsetMat, inverseTmp);
|
|
155
|
+
if (ok) {
|
|
156
|
+
inverses.set(inverseTmp, dst);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
identity16(inverses, dst);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
this.boneOffsetsReady = true;
|
|
163
|
+
}
|
|
164
|
+
isBoneOffsetsReady() {
|
|
165
|
+
return this.boneOffsetsReady;
|
|
166
|
+
}
|
|
167
|
+
// Pair-filter inputs (invMass, group, mask) are immutable post-construction,
|
|
168
|
+
// so build the candidate-pair list once and reuse every step.
|
|
169
|
+
getCollisionPairs() {
|
|
170
|
+
if (this.collisionPairs !== null)
|
|
171
|
+
return this.collisionPairs;
|
|
172
|
+
const N = this.count;
|
|
173
|
+
const invMass = this.invMass;
|
|
174
|
+
const group = this.collisionGroup;
|
|
175
|
+
const mask = this.willCollideMask;
|
|
176
|
+
const buf = [];
|
|
177
|
+
for (let i = 0; i < N; i++) {
|
|
178
|
+
const gi = group[i];
|
|
179
|
+
const mi = mask[i];
|
|
180
|
+
const dynA = invMass[i] > 0;
|
|
181
|
+
for (let j = i + 1; j < N; j++) {
|
|
182
|
+
if (!dynA && invMass[j] === 0)
|
|
183
|
+
continue;
|
|
184
|
+
if ((mi & group[j]) === 0 || (mask[j] & gi) === 0)
|
|
185
|
+
continue;
|
|
186
|
+
buf.push(i, j);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
this.collisionPairs = new Uint16Array(buf);
|
|
190
|
+
return this.collisionPairs;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const _scratchA = new Float32Array(16);
|
|
194
|
+
const _scratchB = new Float32Array(16);
|
|
195
|
+
const _scratchC = new Float32Array(16);
|
|
196
|
+
// Scalar isotropic inverse inertia. Returns 0 for static bodies (mass = 0).
|
|
197
|
+
// Sphere: I = (2/5)·m·r²
|
|
198
|
+
// Box: I = (1/3)·m·max(a,b,c)²
|
|
199
|
+
// Capsule: I = (1/12)·m·(3r² + h²) (cylinder transverse axis)
|
|
200
|
+
function computeInvInertia(rb) {
|
|
201
|
+
const m = rb.mass;
|
|
202
|
+
if (m <= 0)
|
|
203
|
+
return 0;
|
|
204
|
+
let I;
|
|
205
|
+
switch (rb.shape) {
|
|
206
|
+
case RigidbodyShape.Sphere: {
|
|
207
|
+
const r = rb.size.x;
|
|
208
|
+
I = 0.4 * m * r * r;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case RigidbodyShape.Box: {
|
|
212
|
+
// Largest half-extent so the long axis isn't under-rotated.
|
|
213
|
+
const a = Math.max(rb.size.x, rb.size.y, rb.size.z);
|
|
214
|
+
I = (1 / 3) * m * a * a;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
case RigidbodyShape.Capsule: {
|
|
218
|
+
const r = rb.size.x;
|
|
219
|
+
const h = rb.size.y;
|
|
220
|
+
I = (1 / 12) * m * (3 * r * r + h * h);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
default:
|
|
224
|
+
I = m;
|
|
225
|
+
}
|
|
226
|
+
return I > 0 ? 1 / I : 0;
|
|
227
|
+
}
|
|
228
|
+
function identity16(out, offset) {
|
|
229
|
+
out[offset + 0] = 1;
|
|
230
|
+
out[offset + 1] = 0;
|
|
231
|
+
out[offset + 2] = 0;
|
|
232
|
+
out[offset + 3] = 0;
|
|
233
|
+
out[offset + 4] = 0;
|
|
234
|
+
out[offset + 5] = 1;
|
|
235
|
+
out[offset + 6] = 0;
|
|
236
|
+
out[offset + 7] = 0;
|
|
237
|
+
out[offset + 8] = 0;
|
|
238
|
+
out[offset + 9] = 0;
|
|
239
|
+
out[offset + 10] = 1;
|
|
240
|
+
out[offset + 11] = 0;
|
|
241
|
+
out[offset + 12] = 0;
|
|
242
|
+
out[offset + 13] = 0;
|
|
243
|
+
out[offset + 14] = 0;
|
|
244
|
+
out[offset + 15] = 1;
|
|
245
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Joint, Rigidbody } from "./types";
|
|
2
|
+
export interface SixDofSpringConstraint {
|
|
3
|
+
bodyA: number;
|
|
4
|
+
bodyB: number;
|
|
5
|
+
frameA: Float32Array;
|
|
6
|
+
frameB: Float32Array;
|
|
7
|
+
linearMin: Float32Array;
|
|
8
|
+
linearMax: Float32Array;
|
|
9
|
+
angularMin: Float32Array;
|
|
10
|
+
angularMax: Float32Array;
|
|
11
|
+
springEnabled: Uint8Array;
|
|
12
|
+
springStiffness: Float32Array;
|
|
13
|
+
equilibriumPoint: Float32Array;
|
|
14
|
+
cacheSkip: boolean;
|
|
15
|
+
cacheLeverA: Float32Array;
|
|
16
|
+
cacheLeverB: Float32Array;
|
|
17
|
+
cacheLinAxes: Float32Array;
|
|
18
|
+
cacheLinCrossA: Float32Array;
|
|
19
|
+
cacheLinCrossB: Float32Array;
|
|
20
|
+
cacheLinJacInv: Float32Array;
|
|
21
|
+
cacheLinTargetVel: Float32Array;
|
|
22
|
+
cacheLinActive: Uint8Array;
|
|
23
|
+
cacheAngAxes: Float32Array;
|
|
24
|
+
cacheAngTargetVel: Float32Array;
|
|
25
|
+
cacheAngActive: Uint8Array;
|
|
26
|
+
cacheAngJacInv: number;
|
|
27
|
+
}
|
|
28
|
+
export declare const STOP_ERP = 0.475;
|
|
29
|
+
export declare function buildConstraints(rigidbodies: Rigidbody[], joints: Joint[]): SixDofSpringConstraint[];
|
|
30
|
+
//# sourceMappingURL=constraint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../../src/physics/constraint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAW/C,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IAEb,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,YAAY,CAAA;IAGpB,SAAS,EAAE,YAAY,CAAA;IACvB,SAAS,EAAE,YAAY,CAAA;IACvB,UAAU,EAAE,YAAY,CAAA;IACxB,UAAU,EAAE,YAAY,CAAA;IAExB,aAAa,EAAE,UAAU,CAAA;IACzB,eAAe,EAAE,YAAY,CAAA;IAC7B,gBAAgB,EAAE,YAAY,CAAA;IAK9B,SAAS,EAAE,OAAO,CAAA;IAClB,WAAW,EAAE,YAAY,CAAA;IACzB,WAAW,EAAE,YAAY,CAAA;IACzB,YAAY,EAAE,YAAY,CAAA;IAC1B,cAAc,EAAE,YAAY,CAAA;IAC5B,cAAc,EAAE,YAAY,CAAA;IAC5B,cAAc,EAAE,YAAY,CAAA;IAC5B,iBAAiB,EAAE,YAAY,CAAA;IAC/B,cAAc,EAAE,UAAU,CAAA;IAC1B,YAAY,EAAE,YAAY,CAAA;IAC1B,iBAAiB,EAAE,YAAY,CAAA;IAC/B,cAAc,EAAE,UAAU,CAAA;IAC1B,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,eAAO,MAAM,QAAQ,QAAQ,CAAA;AAM7B,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,SAAS,EAAE,EACxB,MAAM,EAAE,KAAK,EAAE,GACd,sBAAsB,EAAE,CAkF1B"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Mat4 } from "../math";
|
|
2
|
+
export const STOP_ERP = 0.475;
|
|
3
|
+
// Build per-joint constraints from PMX data:
|
|
4
|
+
// frameA = (bodyA_worldBind)^-1 · jointWorldBind
|
|
5
|
+
// frameB = (bodyB_worldBind)^-1 · jointWorldBind
|
|
6
|
+
// Equilibrium is zero on every axis (both frames coincide at bind pose).
|
|
7
|
+
export function buildConstraints(rigidbodies, joints) {
|
|
8
|
+
const out = [];
|
|
9
|
+
const jointWorld = new Float32Array(16);
|
|
10
|
+
const bodyWorld = new Float32Array(16);
|
|
11
|
+
const bodyInv = new Float32Array(16);
|
|
12
|
+
for (let j = 0; j < joints.length; j++) {
|
|
13
|
+
const joint = joints[j];
|
|
14
|
+
const a = joint.rigidbodyIndexA;
|
|
15
|
+
const b = joint.rigidbodyIndexB;
|
|
16
|
+
if (a < 0 || b < 0 || a >= rigidbodies.length || b >= rigidbodies.length)
|
|
17
|
+
continue;
|
|
18
|
+
if (a === b)
|
|
19
|
+
continue;
|
|
20
|
+
const rbA = rigidbodies[a];
|
|
21
|
+
const rbB = rigidbodies[b];
|
|
22
|
+
// jointWorldBind from PMX (Euler XYZ as written by saba reference).
|
|
23
|
+
const jq = eulerToQuat(joint.rotation.x, joint.rotation.y, joint.rotation.z);
|
|
24
|
+
Mat4.fromPositionRotationInto(joint.position.x, joint.position.y, joint.position.z, jq.x, jq.y, jq.z, jq.w, jointWorld);
|
|
25
|
+
const frameA = new Float32Array(16);
|
|
26
|
+
const frameB = new Float32Array(16);
|
|
27
|
+
if (!buildLocalFrame(rbA, jointWorld, bodyWorld, bodyInv, frameA))
|
|
28
|
+
continue;
|
|
29
|
+
if (!buildLocalFrame(rbB, jointWorld, bodyWorld, bodyInv, frameB))
|
|
30
|
+
continue;
|
|
31
|
+
const linearMin = new Float32Array([joint.positionMin.x, joint.positionMin.y, joint.positionMin.z]);
|
|
32
|
+
const linearMax = new Float32Array([joint.positionMax.x, joint.positionMax.y, joint.positionMax.z]);
|
|
33
|
+
// Some PMX rigs encode "free" angular axes as ±π·N which wraps badly
|
|
34
|
+
// in limit comparisons — normalize to [-π, π] up front.
|
|
35
|
+
const angularMin = new Float32Array([
|
|
36
|
+
normalizeAngle(joint.rotationMin.x),
|
|
37
|
+
normalizeAngle(joint.rotationMin.y),
|
|
38
|
+
normalizeAngle(joint.rotationMin.z),
|
|
39
|
+
]);
|
|
40
|
+
const angularMax = new Float32Array([
|
|
41
|
+
normalizeAngle(joint.rotationMax.x),
|
|
42
|
+
normalizeAngle(joint.rotationMax.y),
|
|
43
|
+
normalizeAngle(joint.rotationMax.z),
|
|
44
|
+
]);
|
|
45
|
+
const springEnabled = new Uint8Array(6);
|
|
46
|
+
const springStiffness = new Float32Array(6);
|
|
47
|
+
springStiffness[0] = joint.springPosition.x;
|
|
48
|
+
springStiffness[1] = joint.springPosition.y;
|
|
49
|
+
springStiffness[2] = joint.springPosition.z;
|
|
50
|
+
springStiffness[3] = joint.springRotation.x;
|
|
51
|
+
springStiffness[4] = joint.springRotation.y;
|
|
52
|
+
springStiffness[5] = joint.springRotation.z;
|
|
53
|
+
for (let i = 0; i < 6; i++)
|
|
54
|
+
springEnabled[i] = springStiffness[i] !== 0 ? 1 : 0;
|
|
55
|
+
out.push({
|
|
56
|
+
bodyA: a,
|
|
57
|
+
bodyB: b,
|
|
58
|
+
frameA,
|
|
59
|
+
frameB,
|
|
60
|
+
linearMin,
|
|
61
|
+
linearMax,
|
|
62
|
+
angularMin,
|
|
63
|
+
angularMax,
|
|
64
|
+
springEnabled,
|
|
65
|
+
springStiffness,
|
|
66
|
+
equilibriumPoint: new Float32Array(6),
|
|
67
|
+
cacheSkip: false,
|
|
68
|
+
cacheLeverA: new Float32Array(3),
|
|
69
|
+
cacheLeverB: new Float32Array(3),
|
|
70
|
+
cacheLinAxes: new Float32Array(9),
|
|
71
|
+
cacheLinCrossA: new Float32Array(9),
|
|
72
|
+
cacheLinCrossB: new Float32Array(9),
|
|
73
|
+
cacheLinJacInv: new Float32Array(3),
|
|
74
|
+
cacheLinTargetVel: new Float32Array(3),
|
|
75
|
+
cacheLinActive: new Uint8Array(3),
|
|
76
|
+
cacheAngAxes: new Float32Array(9),
|
|
77
|
+
cacheAngTargetVel: new Float32Array(3),
|
|
78
|
+
cacheAngActive: new Uint8Array(3),
|
|
79
|
+
cacheAngJacInv: 0,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
// frame = bodyWorldBind^-1 · jointWorld. False if bodyWorldBind is singular.
|
|
85
|
+
function buildLocalFrame(rb, jointWorld, bodyWorld, bodyInv, out) {
|
|
86
|
+
const q = eulerToQuat(rb.shapeRotation.x, rb.shapeRotation.y, rb.shapeRotation.z);
|
|
87
|
+
Mat4.fromPositionRotationInto(rb.shapePosition.x, rb.shapePosition.y, rb.shapePosition.z, q.x, q.y, q.z, q.w, bodyWorld);
|
|
88
|
+
if (!Mat4.inverseInto(bodyWorld, bodyInv))
|
|
89
|
+
return false;
|
|
90
|
+
Mat4.multiplyArrays(bodyInv, 0, jointWorld, 0, out, 0);
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function normalizeAngle(a) {
|
|
94
|
+
const twoPi = Math.PI * 2;
|
|
95
|
+
a = a % twoPi;
|
|
96
|
+
if (a < -Math.PI)
|
|
97
|
+
a += twoPi;
|
|
98
|
+
else if (a > Math.PI)
|
|
99
|
+
a -= twoPi;
|
|
100
|
+
return a;
|
|
101
|
+
}
|
|
102
|
+
// ZXY left-handed Euler → quat (matches Quat.fromEuler), inlined to skip
|
|
103
|
+
// the allocation per joint at build time.
|
|
104
|
+
function eulerToQuat(rx, ry, rz) {
|
|
105
|
+
const cx = Math.cos(rx * 0.5), sx = Math.sin(rx * 0.5);
|
|
106
|
+
const cy = Math.cos(ry * 0.5), sy = Math.sin(ry * 0.5);
|
|
107
|
+
const cz = Math.cos(rz * 0.5), sz = Math.sin(rz * 0.5);
|
|
108
|
+
const w = cy * cx * cz + sy * sx * sz;
|
|
109
|
+
const x = cy * sx * cz + sy * cx * sz;
|
|
110
|
+
const y = sy * cx * cz - cy * sx * sz;
|
|
111
|
+
const z = cy * cx * sz - sy * sx * cz;
|
|
112
|
+
const len = Math.hypot(x, y, z, w) || 1;
|
|
113
|
+
const inv = 1 / len;
|
|
114
|
+
return { x: x * inv, y: y * inv, z: z * inv, w: w * inv };
|
|
115
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { RigidBodyStore } from "./body";
|
|
2
|
+
export declare const CONTACT_MARGIN = 0.04;
|
|
3
|
+
export interface Contact {
|
|
4
|
+
bodyA: number;
|
|
5
|
+
bodyB: number;
|
|
6
|
+
rAx: number;
|
|
7
|
+
rAy: number;
|
|
8
|
+
rAz: number;
|
|
9
|
+
rBx: number;
|
|
10
|
+
rBy: number;
|
|
11
|
+
rBz: number;
|
|
12
|
+
nx: number;
|
|
13
|
+
ny: number;
|
|
14
|
+
nz: number;
|
|
15
|
+
depth: number;
|
|
16
|
+
friction: number;
|
|
17
|
+
restitution: number;
|
|
18
|
+
appliedNormalImpulse: number;
|
|
19
|
+
appliedFrictionImpulse1: number;
|
|
20
|
+
appliedFrictionImpulse2: number;
|
|
21
|
+
cAxN: number;
|
|
22
|
+
cAyN: number;
|
|
23
|
+
cAzN: number;
|
|
24
|
+
cBxN: number;
|
|
25
|
+
cByN: number;
|
|
26
|
+
cBzN: number;
|
|
27
|
+
jacInvN: number;
|
|
28
|
+
bounceVel: number;
|
|
29
|
+
t1x: number;
|
|
30
|
+
t1y: number;
|
|
31
|
+
t1z: number;
|
|
32
|
+
cAxT1: number;
|
|
33
|
+
cAyT1: number;
|
|
34
|
+
cAzT1: number;
|
|
35
|
+
cBxT1: number;
|
|
36
|
+
cByT1: number;
|
|
37
|
+
cBzT1: number;
|
|
38
|
+
jacInvT1: number;
|
|
39
|
+
t2x: number;
|
|
40
|
+
t2y: number;
|
|
41
|
+
t2z: number;
|
|
42
|
+
cAxT2: number;
|
|
43
|
+
cAyT2: number;
|
|
44
|
+
cAzT2: number;
|
|
45
|
+
cBxT2: number;
|
|
46
|
+
cByT2: number;
|
|
47
|
+
cBzT2: number;
|
|
48
|
+
jacInvT2: number;
|
|
49
|
+
}
|
|
50
|
+
export declare class ContactPool {
|
|
51
|
+
private pool;
|
|
52
|
+
count: number;
|
|
53
|
+
acquire(): Contact;
|
|
54
|
+
reset(): void;
|
|
55
|
+
get(i: number): Contact;
|
|
56
|
+
}
|
|
57
|
+
export declare function aabbOverlap(store: RigidBodyStore, a: number, b: number): boolean;
|
|
58
|
+
export declare function generateContacts(store: RigidBodyStore, a: number, b: number, pool: ContactPool): void;
|
|
59
|
+
export declare function findContacts(store: RigidBodyStore, pool: ContactPool): void;
|
|
60
|
+
//# sourceMappingURL=contact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../../src/physics/contact.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAO5C,eAAO,MAAM,cAAc,OAAO,CAAA;AAElC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IAEb,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IAEX,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IAEnB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,uBAAuB,EAAE,MAAM,CAAA;IAC/B,uBAAuB,EAAE,MAAM,CAAA;IAI/B,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;IACxC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IAEjB,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;IACrC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAA;IAEhB,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;IACrC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;IAC3C,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;IAC3C,QAAQ,EAAE,MAAM,CAAA;CACjB;AA8BD,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAgB;IAC5B,KAAK,SAAI;IAET,OAAO,IAAI,OAAO;IAelB,KAAK,IAAI,IAAI;IAGb,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO;CAGxB;AASD,wBAAgB,WAAW,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAahF;AAkxBD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAuCrG;AA4BD,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAS3E"}
|