reze-engine 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ammo-loader.d.ts +0 -1
- package/dist/ammo-loader.d.ts.map +1 -1
- package/dist/ammo-loader.js +0 -3
- package/dist/engine.d.ts +2 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +44 -100
- package/dist/ik-solver.d.ts +7 -2
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +110 -137
- package/dist/math.d.ts +10 -6
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +36 -62
- package/dist/model.d.ts +1 -19
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +24 -93
- package/dist/player.d.ts +6 -20
- package/dist/player.d.ts.map +1 -1
- package/dist/player.js +89 -193
- package/package.json +1 -1
- package/src/ammo-loader.ts +0 -4
- package/src/engine.ts +54 -101
- package/src/ik-solver.ts +121 -178
- package/src/math.ts +43 -82
- package/src/model.ts +26 -101
- package/src/player.ts +116 -212
- package/src/bezier-interpolate.ts +0 -47
- package/src/ik.ts +0 -449
package/dist/ammo-loader.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ammo-loader.d.ts","sourceRoot":"","sources":["../src/ammo-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAKhD,wBAAsB,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC,CAyBtD
|
|
1
|
+
{"version":3,"file":"ammo-loader.d.ts","sourceRoot":"","sources":["../src/ammo-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAKhD,wBAAsB,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC,CAyBtD"}
|
package/dist/ammo-loader.js
CHANGED
package/dist/engine.d.ts
CHANGED
|
@@ -102,7 +102,6 @@ export declare class Engine {
|
|
|
102
102
|
private renderLoopCallback;
|
|
103
103
|
private player;
|
|
104
104
|
private hasAnimation;
|
|
105
|
-
private animationStartTime;
|
|
106
105
|
constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
|
|
107
106
|
init(): Promise<void>;
|
|
108
107
|
private createPipelines;
|
|
@@ -135,6 +134,8 @@ export declare class Engine {
|
|
|
135
134
|
private updateVertexBuffer;
|
|
136
135
|
private setupModelBuffers;
|
|
137
136
|
private setupMaterials;
|
|
137
|
+
private createMaterialUniformBuffer;
|
|
138
|
+
private createUniformBuffer;
|
|
138
139
|
private createTextureFromPath;
|
|
139
140
|
private renderEyes;
|
|
140
141
|
private renderHair;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -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
|
@@ -50,7 +50,6 @@ export class Engine {
|
|
|
50
50
|
this.renderLoopCallback = null;
|
|
51
51
|
this.player = new Player();
|
|
52
52
|
this.hasAnimation = false; // Set to true when loadAnimation is called
|
|
53
|
-
this.animationStartTime = 0; // Track when animation first started (for A-pose prevention)
|
|
54
53
|
this.canvas = canvas;
|
|
55
54
|
if (options) {
|
|
56
55
|
this.ambientColor = options.ambientColor ?? new Vec3(1.0, 1.0, 1.0);
|
|
@@ -1156,8 +1155,8 @@ export class Engine {
|
|
|
1156
1155
|
playAnimation() {
|
|
1157
1156
|
if (!this.hasAnimation || !this.currentModel)
|
|
1158
1157
|
return;
|
|
1159
|
-
const wasPaused = this.player.isPausedState
|
|
1160
|
-
const wasPlaying = this.player.isPlayingState
|
|
1158
|
+
const wasPaused = this.player.isPausedState;
|
|
1159
|
+
const wasPlaying = this.player.isPlayingState;
|
|
1161
1160
|
// Only reset pose and physics if starting from beginning (not resuming)
|
|
1162
1161
|
if (!wasPlaying && !wasPaused) {
|
|
1163
1162
|
// Get initial pose at time 0
|
|
@@ -1191,9 +1190,6 @@ export class Engine {
|
|
|
1191
1190
|
}
|
|
1192
1191
|
// Start playback (or resume if paused)
|
|
1193
1192
|
this.player.play();
|
|
1194
|
-
if (this.animationStartTime === 0) {
|
|
1195
|
-
this.animationStartTime = performance.now();
|
|
1196
|
-
}
|
|
1197
1193
|
}
|
|
1198
1194
|
stopAnimation() {
|
|
1199
1195
|
this.player.stop();
|
|
@@ -1419,22 +1415,7 @@ export class Engine {
|
|
|
1419
1415
|
throw new Error(`Material "${mat.name}" has no diffuse texture`);
|
|
1420
1416
|
const materialAlpha = mat.diffuse[3];
|
|
1421
1417
|
const isTransparent = materialAlpha < 1.0 - Engine.TRANSPARENCY_EPSILON;
|
|
1422
|
-
|
|
1423
|
-
const materialUniformData = new Float32Array(8);
|
|
1424
|
-
materialUniformData[0] = materialAlpha;
|
|
1425
|
-
materialUniformData[1] = 1.0; // alphaMultiplier: 1.0 for non-hair materials
|
|
1426
|
-
materialUniformData[2] = this.rimLightIntensity;
|
|
1427
|
-
materialUniformData[3] = 0.0; // _padding1
|
|
1428
|
-
materialUniformData[4] = 1.0; // rimColor.r
|
|
1429
|
-
materialUniformData[5] = 1.0; // rimColor.g
|
|
1430
|
-
materialUniformData[6] = 1.0; // rimColor.b
|
|
1431
|
-
materialUniformData[7] = 0.0; // isOverEyes
|
|
1432
|
-
const materialUniformBuffer = this.device.createBuffer({
|
|
1433
|
-
label: `material uniform: ${mat.name}`,
|
|
1434
|
-
size: materialUniformData.byteLength,
|
|
1435
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1436
|
-
});
|
|
1437
|
-
this.device.queue.writeBuffer(materialUniformBuffer, 0, materialUniformData);
|
|
1418
|
+
const materialUniformBuffer = this.createMaterialUniformBuffer(mat.name, materialAlpha, 0.0);
|
|
1438
1419
|
// Create bind groups using the shared bind group layout - All pipelines (main, eye, hair multiply, hair opaque) use the same shader and layout
|
|
1439
1420
|
const bindGroup = this.device.createBindGroup({
|
|
1440
1421
|
label: `material bind group: ${mat.name}`,
|
|
@@ -1448,33 +1429,18 @@ export class Engine {
|
|
|
1448
1429
|
{ binding: 5, resource: { buffer: materialUniformBuffer } },
|
|
1449
1430
|
],
|
|
1450
1431
|
});
|
|
1451
|
-
|
|
1432
|
+
const addDrawCall = (draws) => {
|
|
1452
1433
|
if (indexCount > 0) {
|
|
1453
|
-
|
|
1454
|
-
count: indexCount,
|
|
1455
|
-
firstIndex: currentIndexOffset,
|
|
1456
|
-
bindGroup,
|
|
1457
|
-
});
|
|
1434
|
+
draws.push({ count: indexCount, firstIndex: currentIndexOffset, bindGroup });
|
|
1458
1435
|
}
|
|
1436
|
+
};
|
|
1437
|
+
if (mat.isEye) {
|
|
1438
|
+
addDrawCall(this.eyeDraws);
|
|
1459
1439
|
}
|
|
1460
1440
|
else if (mat.isHair) {
|
|
1461
1441
|
// Hair materials: create separate bind groups for over-eyes vs over-non-eyes
|
|
1462
1442
|
const createHairBindGroup = (isOverEyes) => {
|
|
1463
|
-
const
|
|
1464
|
-
uniformData[0] = materialAlpha;
|
|
1465
|
-
uniformData[1] = 1.0; // alphaMultiplier (shader adjusts based on isOverEyes)
|
|
1466
|
-
uniformData[2] = this.rimLightIntensity;
|
|
1467
|
-
uniformData[3] = 0.0; // _padding1
|
|
1468
|
-
uniformData[4] = 1.0; // rimColor.rgb
|
|
1469
|
-
uniformData[5] = 1.0;
|
|
1470
|
-
uniformData[6] = 1.0;
|
|
1471
|
-
uniformData[7] = isOverEyes ? 1.0 : 0.0; // isOverEyes
|
|
1472
|
-
const buffer = this.device.createBuffer({
|
|
1473
|
-
label: `material uniform (${isOverEyes ? "over eyes" : "over non-eyes"}): ${mat.name}`,
|
|
1474
|
-
size: uniformData.byteLength,
|
|
1475
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1476
|
-
});
|
|
1477
|
-
this.device.queue.writeBuffer(buffer, 0, uniformData);
|
|
1443
|
+
const buffer = this.createMaterialUniformBuffer(`${mat.name} (${isOverEyes ? "over eyes" : "over non-eyes"})`, materialAlpha, isOverEyes ? 1.0 : 0.0);
|
|
1478
1444
|
return this.device.createBindGroup({
|
|
1479
1445
|
label: `material bind group (${isOverEyes ? "over eyes" : "over non-eyes"}): ${mat.name}`,
|
|
1480
1446
|
layout: this.mainBindGroupLayout,
|
|
@@ -1504,40 +1470,24 @@ export class Engine {
|
|
|
1504
1470
|
}
|
|
1505
1471
|
}
|
|
1506
1472
|
else if (isTransparent) {
|
|
1507
|
-
|
|
1508
|
-
this.transparentDraws.push({
|
|
1509
|
-
count: indexCount,
|
|
1510
|
-
firstIndex: currentIndexOffset,
|
|
1511
|
-
bindGroup,
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1473
|
+
addDrawCall(this.transparentDraws);
|
|
1514
1474
|
}
|
|
1515
1475
|
else {
|
|
1516
|
-
|
|
1517
|
-
this.opaqueDraws.push({
|
|
1518
|
-
count: indexCount,
|
|
1519
|
-
firstIndex: currentIndexOffset,
|
|
1520
|
-
bindGroup,
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1476
|
+
addDrawCall(this.opaqueDraws);
|
|
1523
1477
|
}
|
|
1524
1478
|
// Edge flag is at bit 4 (0x10) in PMX format
|
|
1525
1479
|
if ((mat.edgeFlag & 0x10) !== 0 && mat.edgeSize > 0) {
|
|
1526
|
-
const materialUniformData = new Float32Array(
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
size: materialUniformData.byteLength,
|
|
1538
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1539
|
-
});
|
|
1540
|
-
this.device.queue.writeBuffer(materialUniformBuffer, 0, materialUniformData);
|
|
1480
|
+
const materialUniformData = new Float32Array([
|
|
1481
|
+
mat.edgeColor[0],
|
|
1482
|
+
mat.edgeColor[1],
|
|
1483
|
+
mat.edgeColor[2],
|
|
1484
|
+
mat.edgeColor[3],
|
|
1485
|
+
mat.edgeSize,
|
|
1486
|
+
0,
|
|
1487
|
+
0,
|
|
1488
|
+
0,
|
|
1489
|
+
]);
|
|
1490
|
+
const materialUniformBuffer = this.createUniformBuffer(`outline material uniform: ${mat.name}`, materialUniformData);
|
|
1541
1491
|
const outlineBindGroup = this.device.createBindGroup({
|
|
1542
1492
|
label: `outline bind group: ${mat.name}`,
|
|
1543
1493
|
layout: this.outlineBindGroupLayout,
|
|
@@ -1548,39 +1498,33 @@ export class Engine {
|
|
|
1548
1498
|
],
|
|
1549
1499
|
});
|
|
1550
1500
|
if (indexCount > 0) {
|
|
1551
|
-
|
|
1552
|
-
this.eyeOutlineDraws
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
this.hairOutlineDraws.push({
|
|
1560
|
-
count: indexCount,
|
|
1561
|
-
firstIndex: currentIndexOffset,
|
|
1562
|
-
bindGroup: outlineBindGroup,
|
|
1563
|
-
});
|
|
1564
|
-
}
|
|
1565
|
-
else if (isTransparent) {
|
|
1566
|
-
this.transparentOutlineDraws.push({
|
|
1567
|
-
count: indexCount,
|
|
1568
|
-
firstIndex: currentIndexOffset,
|
|
1569
|
-
bindGroup: outlineBindGroup,
|
|
1570
|
-
});
|
|
1571
|
-
}
|
|
1572
|
-
else {
|
|
1573
|
-
this.opaqueOutlineDraws.push({
|
|
1574
|
-
count: indexCount,
|
|
1575
|
-
firstIndex: currentIndexOffset,
|
|
1576
|
-
bindGroup: outlineBindGroup,
|
|
1577
|
-
});
|
|
1578
|
-
}
|
|
1501
|
+
const outlineDraws = mat.isEye
|
|
1502
|
+
? this.eyeOutlineDraws
|
|
1503
|
+
: mat.isHair
|
|
1504
|
+
? this.hairOutlineDraws
|
|
1505
|
+
: isTransparent
|
|
1506
|
+
? this.transparentOutlineDraws
|
|
1507
|
+
: this.opaqueOutlineDraws;
|
|
1508
|
+
outlineDraws.push({ count: indexCount, firstIndex: currentIndexOffset, bindGroup: outlineBindGroup });
|
|
1579
1509
|
}
|
|
1580
1510
|
}
|
|
1581
1511
|
currentIndexOffset += indexCount;
|
|
1582
1512
|
}
|
|
1583
1513
|
}
|
|
1514
|
+
createMaterialUniformBuffer(label, alpha, isOverEyes) {
|
|
1515
|
+
const data = new Float32Array(8);
|
|
1516
|
+
data.set([alpha, 1.0, this.rimLightIntensity, 0.0, 1.0, 1.0, 1.0, isOverEyes]);
|
|
1517
|
+
return this.createUniformBuffer(`material uniform: ${label}`, data);
|
|
1518
|
+
}
|
|
1519
|
+
createUniformBuffer(label, data) {
|
|
1520
|
+
const buffer = this.device.createBuffer({
|
|
1521
|
+
label,
|
|
1522
|
+
size: data.byteLength,
|
|
1523
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
1524
|
+
});
|
|
1525
|
+
this.device.queue.writeBuffer(buffer, 0, data);
|
|
1526
|
+
return buffer;
|
|
1527
|
+
}
|
|
1584
1528
|
async createTextureFromPath(path) {
|
|
1585
1529
|
const cached = this.textureCache.get(path);
|
|
1586
1530
|
if (cached) {
|
package/dist/ik-solver.d.ts
CHANGED
|
@@ -13,14 +13,19 @@ export declare class IKSolverSystem {
|
|
|
13
13
|
/**
|
|
14
14
|
* Solve all IK chains
|
|
15
15
|
*/
|
|
16
|
-
static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Float32Array, localTranslations: Float32Array, worldMatrices: Float32Array, ikChainInfo: IKChainInfo[]
|
|
16
|
+
static solve(ikSolvers: IKSolver[], bones: Bone[], localRotations: Float32Array, localTranslations: Float32Array, worldMatrices: Float32Array, ikChainInfo: IKChainInfo[]): void;
|
|
17
17
|
private static solveIK;
|
|
18
18
|
private static solveChain;
|
|
19
19
|
private static limitAngle;
|
|
20
|
+
private static getDistance;
|
|
20
21
|
private static getWorldTranslation;
|
|
22
|
+
private static getQuatFromArray;
|
|
23
|
+
private static setQuatToArray;
|
|
24
|
+
private static extractEulerAngles;
|
|
25
|
+
private static limitEulerAngles;
|
|
26
|
+
private static reconstructQuatFromEuler;
|
|
21
27
|
private static getParentWorldRotationMatrix;
|
|
22
28
|
private static transformNormal;
|
|
23
|
-
private static updateWorldMatrixWithIK;
|
|
24
29
|
private static updateWorldMatrix;
|
|
25
30
|
}
|
|
26
31
|
//# sourceMappingURL=ik-solver.d.ts.map
|
package/dist/ik-solver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"ik-solver.d.ts","sourceRoot":"","sources":["../src/ik-solver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,IAAI,EAAU,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAoE7D;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAS;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAuB;IAExD;;OAEG;WACW,KAAK,CACjB,SAAS,EAAE,QAAQ,EAAE,EACrB,KAAK,EAAE,IAAI,EAAE,EACb,cAAc,EAAE,YAAY,EAC5B,iBAAiB,EAAE,YAAY,EAC/B,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,WAAW,EAAE,GACzB,IAAI;IAMP,OAAO,CAAC,MAAM,CAAC,OAAO;IA4EtB,OAAO,CAAC,MAAM,CAAC,UAAU;IA2FzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,OAAO,CAAC,MAAM,CAAC,WAAW;IAM1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAKlC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B,OAAO,CAAC,MAAM,CAAC,cAAc;IAO7B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAmCjC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAQ/B,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAqBvC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAe3C,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;CA2CjC"}
|
package/dist/ik-solver.js
CHANGED
|
@@ -74,11 +74,8 @@ export class IKSolverSystem {
|
|
|
74
74
|
/**
|
|
75
75
|
* Solve all IK chains
|
|
76
76
|
*/
|
|
77
|
-
static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo
|
|
77
|
+
static solve(ikSolvers, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
|
|
78
78
|
for (const solver of ikSolvers) {
|
|
79
|
-
if (usePhysics && solver.canSkipWhenPhysicsEnabled) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
79
|
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
|
|
83
80
|
}
|
|
84
81
|
}
|
|
@@ -94,10 +91,7 @@ export class IKSolverSystem {
|
|
|
94
91
|
chainInfo.ikRotation = new Quat(0, 0, 0, 1);
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
|
-
|
|
98
|
-
const ikPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
99
|
-
const targetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
100
|
-
if (ikPosition.subtract(targetPosition).length() < this.EPSILON)
|
|
94
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
101
95
|
return;
|
|
102
96
|
// Build IK chains
|
|
103
97
|
const chains = [];
|
|
@@ -106,13 +100,10 @@ export class IKSolverSystem {
|
|
|
106
100
|
}
|
|
107
101
|
// Update chain bones and target bone world matrices (initial state, no IK yet)
|
|
108
102
|
for (let i = chains.length - 1; i >= 0; i--) {
|
|
109
|
-
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices);
|
|
103
|
+
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
110
104
|
}
|
|
111
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices);
|
|
112
|
-
|
|
113
|
-
const updatedIkPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
114
|
-
const updatedTargetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
115
|
-
if (updatedIkPosition.subtract(updatedTargetPosition).length() < this.EPSILON)
|
|
105
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
106
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
116
107
|
return;
|
|
117
108
|
// Solve iteratively
|
|
118
109
|
const iteration = Math.min(solver.iterationCount, 256);
|
|
@@ -124,24 +115,17 @@ export class IKSolverSystem {
|
|
|
124
115
|
this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration);
|
|
125
116
|
}
|
|
126
117
|
}
|
|
127
|
-
|
|
128
|
-
const currentIkPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
129
|
-
const currentTargetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
130
|
-
const distance = currentIkPosition.subtract(currentTargetPosition).length();
|
|
131
|
-
if (distance < this.EPSILON)
|
|
118
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
132
119
|
break;
|
|
133
120
|
}
|
|
134
121
|
// Apply IK rotations to local rotations
|
|
135
122
|
for (const link of solver.links) {
|
|
136
123
|
const chainInfo = ikChainInfo[link.boneIndex];
|
|
137
|
-
if (chainInfo
|
|
124
|
+
if (chainInfo?.ikRotation) {
|
|
138
125
|
const qi = link.boneIndex * 4;
|
|
139
|
-
const localRot =
|
|
126
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
140
127
|
const finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
|
|
141
|
-
localRotations
|
|
142
|
-
localRotations[qi + 1] = finalRot.y;
|
|
143
|
-
localRotations[qi + 2] = finalRot.z;
|
|
144
|
-
localRotations[qi + 3] = finalRot.w;
|
|
128
|
+
this.setQuatToArray(localRotations, qi, finalRot);
|
|
145
129
|
}
|
|
146
130
|
}
|
|
147
131
|
}
|
|
@@ -165,25 +149,20 @@ export class IKSolverSystem {
|
|
|
165
149
|
finalRotationAxis = this.transformNormal(chainRotationAxis, invParentRot).normalize();
|
|
166
150
|
break;
|
|
167
151
|
}
|
|
168
|
-
case InternalSolveAxis.X:
|
|
169
|
-
|
|
170
|
-
const axisX = new Vec3(m[0], m[1], m[2]);
|
|
171
|
-
const dot = chainRotationAxis.dot(axisX);
|
|
172
|
-
finalRotationAxis = new Vec3(dot >= 0 ? 1 : -1, 0, 0);
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
case InternalSolveAxis.Y: {
|
|
176
|
-
const m = parentWorldRotMatrix.values;
|
|
177
|
-
const axisY = new Vec3(m[4], m[5], m[6]);
|
|
178
|
-
const dot = chainRotationAxis.dot(axisY);
|
|
179
|
-
finalRotationAxis = new Vec3(0, dot >= 0 ? 1 : -1, 0);
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
152
|
+
case InternalSolveAxis.X:
|
|
153
|
+
case InternalSolveAxis.Y:
|
|
182
154
|
case InternalSolveAxis.Z: {
|
|
183
155
|
const m = parentWorldRotMatrix.values;
|
|
184
|
-
const
|
|
185
|
-
const
|
|
186
|
-
|
|
156
|
+
const axisOffset = (chain.solveAxis - InternalSolveAxis.X) * 4;
|
|
157
|
+
const axis = new Vec3(m[axisOffset], m[axisOffset + 1], m[axisOffset + 2]);
|
|
158
|
+
const dot = chainRotationAxis.dot(axis);
|
|
159
|
+
const sign = dot >= 0 ? 1 : -1;
|
|
160
|
+
finalRotationAxis =
|
|
161
|
+
chain.solveAxis === InternalSolveAxis.X
|
|
162
|
+
? new Vec3(sign, 0, 0)
|
|
163
|
+
: chain.solveAxis === InternalSolveAxis.Y
|
|
164
|
+
? new Vec3(0, sign, 0)
|
|
165
|
+
: new Vec3(0, 0, sign);
|
|
187
166
|
break;
|
|
188
167
|
}
|
|
189
168
|
default:
|
|
@@ -202,80 +181,23 @@ export class IKSolverSystem {
|
|
|
202
181
|
if (chainInfo) {
|
|
203
182
|
chainInfo.ikRotation = ikRotation.multiply(chainInfo.ikRotation);
|
|
204
183
|
// Apply angle constraints if present
|
|
205
|
-
if (chain.minimumAngle
|
|
184
|
+
if (chain.minimumAngle && chain.maximumAngle) {
|
|
206
185
|
const qi = chainBoneIndex * 4;
|
|
207
|
-
const localRot =
|
|
186
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
208
187
|
chainInfo.localRotation = localRot.clone();
|
|
209
188
|
const combinedRot = chainInfo.ikRotation.multiply(localRot);
|
|
210
|
-
const
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
case InternalEulerRotationOrder.YXZ: {
|
|
215
|
-
rX = Math.asin(-m[9]); // m32
|
|
216
|
-
if (Math.abs(rX) > this.THRESHOLD) {
|
|
217
|
-
rX = rX < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
218
|
-
}
|
|
219
|
-
let cosX = Math.cos(rX);
|
|
220
|
-
if (cosX !== 0)
|
|
221
|
-
cosX = 1 / cosX;
|
|
222
|
-
rY = Math.atan2(m[8] * cosX, m[10] * cosX); // m31, m33
|
|
223
|
-
rZ = Math.atan2(m[1] * cosX, m[5] * cosX); // m12, m22
|
|
224
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
225
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
226
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
227
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(0, 1, 0), rY);
|
|
228
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(1, 0, 0), rX));
|
|
229
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ));
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
case InternalEulerRotationOrder.ZYX: {
|
|
233
|
-
rY = Math.asin(-m[2]); // m13
|
|
234
|
-
if (Math.abs(rY) > this.THRESHOLD) {
|
|
235
|
-
rY = rY < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
236
|
-
}
|
|
237
|
-
let cosY = Math.cos(rY);
|
|
238
|
-
if (cosY !== 0)
|
|
239
|
-
cosY = 1 / cosY;
|
|
240
|
-
rX = Math.atan2(m[6] * cosY, m[10] * cosY); // m23, m33
|
|
241
|
-
rZ = Math.atan2(m[1] * cosY, m[0] * cosY); // m12, m11
|
|
242
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
243
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
244
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
245
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ);
|
|
246
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 1, 0), rY));
|
|
247
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(1, 0, 0), rX));
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
case InternalEulerRotationOrder.XZY: {
|
|
251
|
-
rZ = Math.asin(-m[4]); // m21
|
|
252
|
-
if (Math.abs(rZ) > this.THRESHOLD) {
|
|
253
|
-
rZ = rZ < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
254
|
-
}
|
|
255
|
-
let cosZ = Math.cos(rZ);
|
|
256
|
-
if (cosZ !== 0)
|
|
257
|
-
cosZ = 1 / cosZ;
|
|
258
|
-
rX = Math.atan2(m[6] * cosZ, m[5] * cosZ); // m23, m22
|
|
259
|
-
rY = Math.atan2(m[8] * cosZ, m[0] * cosZ); // m31, m11
|
|
260
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
261
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
262
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
263
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(1, 0, 0), rX);
|
|
264
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ));
|
|
265
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 1, 0), rY));
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
const invertedLocalRotation = localRot.conjugate().normalize();
|
|
270
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(invertedLocalRotation);
|
|
189
|
+
const euler = this.extractEulerAngles(combinedRot, chain.rotationOrder);
|
|
190
|
+
const limited = this.limitEulerAngles(euler, chain.minimumAngle, chain.maximumAngle, useAxis);
|
|
191
|
+
chainInfo.ikRotation = this.reconstructQuatFromEuler(limited, chain.rotationOrder);
|
|
192
|
+
chainInfo.ikRotation = chainInfo.ikRotation.multiply(localRot.conjugate().normalize());
|
|
271
193
|
}
|
|
272
194
|
}
|
|
273
195
|
// Update world matrices for affected bones (using IK-modified rotations)
|
|
274
196
|
for (let i = chainIndex; i >= 0; i--) {
|
|
275
197
|
const link = solver.links[i];
|
|
276
|
-
this.
|
|
198
|
+
this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
|
|
277
199
|
}
|
|
278
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices);
|
|
200
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
279
201
|
}
|
|
280
202
|
static limitAngle(angle, min, max, useAxis) {
|
|
281
203
|
if (angle < min) {
|
|
@@ -290,10 +212,83 @@ export class IKSolverSystem {
|
|
|
290
212
|
return angle;
|
|
291
213
|
}
|
|
292
214
|
}
|
|
215
|
+
static getDistance(boneIndex1, boneIndex2, worldMatrices) {
|
|
216
|
+
const pos1 = this.getWorldTranslation(boneIndex1, worldMatrices);
|
|
217
|
+
const pos2 = this.getWorldTranslation(boneIndex2, worldMatrices);
|
|
218
|
+
return pos1.subtract(pos2).length();
|
|
219
|
+
}
|
|
293
220
|
static getWorldTranslation(boneIndex, worldMatrices) {
|
|
294
221
|
const offset = boneIndex * 16;
|
|
295
222
|
return new Vec3(worldMatrices[offset + 12], worldMatrices[offset + 13], worldMatrices[offset + 14]);
|
|
296
223
|
}
|
|
224
|
+
static getQuatFromArray(array, offset) {
|
|
225
|
+
return new Quat(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
|
|
226
|
+
}
|
|
227
|
+
static setQuatToArray(array, offset, quat) {
|
|
228
|
+
array[offset] = quat.x;
|
|
229
|
+
array[offset + 1] = quat.y;
|
|
230
|
+
array[offset + 2] = quat.z;
|
|
231
|
+
array[offset + 3] = quat.w;
|
|
232
|
+
}
|
|
233
|
+
static extractEulerAngles(quat, order) {
|
|
234
|
+
const rotMatrix = Mat4.fromQuat(quat.x, quat.y, quat.z, quat.w);
|
|
235
|
+
const m = rotMatrix.values;
|
|
236
|
+
switch (order) {
|
|
237
|
+
case InternalEulerRotationOrder.YXZ: {
|
|
238
|
+
let rX = Math.asin(-m[9]);
|
|
239
|
+
if (Math.abs(rX) > this.THRESHOLD)
|
|
240
|
+
rX = rX < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
241
|
+
let cosX = Math.cos(rX);
|
|
242
|
+
if (cosX !== 0)
|
|
243
|
+
cosX = 1 / cosX;
|
|
244
|
+
const rY = Math.atan2(m[8] * cosX, m[10] * cosX);
|
|
245
|
+
const rZ = Math.atan2(m[1] * cosX, m[5] * cosX);
|
|
246
|
+
return new Vec3(rX, rY, rZ);
|
|
247
|
+
}
|
|
248
|
+
case InternalEulerRotationOrder.ZYX: {
|
|
249
|
+
let rY = Math.asin(-m[2]);
|
|
250
|
+
if (Math.abs(rY) > this.THRESHOLD)
|
|
251
|
+
rY = rY < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
252
|
+
let cosY = Math.cos(rY);
|
|
253
|
+
if (cosY !== 0)
|
|
254
|
+
cosY = 1 / cosY;
|
|
255
|
+
const rX = Math.atan2(m[6] * cosY, m[10] * cosY);
|
|
256
|
+
const rZ = Math.atan2(m[1] * cosY, m[0] * cosY);
|
|
257
|
+
return new Vec3(rX, rY, rZ);
|
|
258
|
+
}
|
|
259
|
+
case InternalEulerRotationOrder.XZY: {
|
|
260
|
+
let rZ = Math.asin(-m[4]);
|
|
261
|
+
if (Math.abs(rZ) > this.THRESHOLD)
|
|
262
|
+
rZ = rZ < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
263
|
+
let cosZ = Math.cos(rZ);
|
|
264
|
+
if (cosZ !== 0)
|
|
265
|
+
cosZ = 1 / cosZ;
|
|
266
|
+
const rX = Math.atan2(m[6] * cosZ, m[5] * cosZ);
|
|
267
|
+
const rY = Math.atan2(m[8] * cosZ, m[0] * cosZ);
|
|
268
|
+
return new Vec3(rX, rY, rZ);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
static limitEulerAngles(euler, min, max, useAxis) {
|
|
273
|
+
return new Vec3(this.limitAngle(euler.x, min.x, max.x, useAxis), this.limitAngle(euler.y, min.y, max.y, useAxis), this.limitAngle(euler.z, min.z, max.z, useAxis));
|
|
274
|
+
}
|
|
275
|
+
static reconstructQuatFromEuler(euler, order) {
|
|
276
|
+
const axes = [
|
|
277
|
+
[new Vec3(1, 0, 0), new Vec3(0, 1, 0), new Vec3(0, 0, 1)],
|
|
278
|
+
[new Vec3(0, 0, 1), new Vec3(0, 1, 0), new Vec3(1, 0, 0)],
|
|
279
|
+
[new Vec3(0, 1, 0), new Vec3(1, 0, 0), new Vec3(0, 0, 1)],
|
|
280
|
+
];
|
|
281
|
+
const [axis1, axis2, axis3] = axes[order];
|
|
282
|
+
const [angle1, angle2, angle3] = order === InternalEulerRotationOrder.YXZ
|
|
283
|
+
? [euler.y, euler.x, euler.z]
|
|
284
|
+
: order === InternalEulerRotationOrder.ZYX
|
|
285
|
+
? [euler.z, euler.y, euler.x]
|
|
286
|
+
: [euler.x, euler.z, euler.y];
|
|
287
|
+
let result = Quat.fromAxisAngle(axis1, angle1);
|
|
288
|
+
result = result.multiply(Quat.fromAxisAngle(axis2, angle2));
|
|
289
|
+
result = result.multiply(Quat.fromAxisAngle(axis3, angle3));
|
|
290
|
+
return result;
|
|
291
|
+
}
|
|
297
292
|
static getParentWorldRotationMatrix(boneIndex, bones, worldMatrices) {
|
|
298
293
|
const bone = bones[boneIndex];
|
|
299
294
|
if (bone.parentIndex >= 0) {
|
|
@@ -313,16 +308,18 @@ export class IKSolverSystem {
|
|
|
313
308
|
const m = matrix.values;
|
|
314
309
|
return new Vec3(m[0] * normal.x + m[4] * normal.y + m[8] * normal.z, m[1] * normal.x + m[5] * normal.y + m[9] * normal.z, m[2] * normal.x + m[6] * normal.y + m[10] * normal.z);
|
|
315
310
|
}
|
|
316
|
-
static
|
|
311
|
+
static updateWorldMatrix(boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
|
|
317
312
|
const bone = bones[boneIndex];
|
|
318
313
|
const qi = boneIndex * 4;
|
|
319
314
|
const ti = boneIndex * 3;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const chainInfo = ikChainInfo[boneIndex];
|
|
315
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
316
|
+
// Apply IK rotation if available
|
|
323
317
|
let finalRot = localRot;
|
|
324
|
-
if (
|
|
325
|
-
|
|
318
|
+
if (ikChainInfo) {
|
|
319
|
+
const chainInfo = ikChainInfo[boneIndex];
|
|
320
|
+
if (chainInfo && chainInfo.ikRotation) {
|
|
321
|
+
finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
|
|
322
|
+
}
|
|
326
323
|
}
|
|
327
324
|
const rotateM = Mat4.fromQuat(finalRot.x, finalRot.y, finalRot.z, finalRot.w);
|
|
328
325
|
const localTx = localTranslations[ti];
|
|
@@ -343,30 +340,6 @@ export class IKSolverSystem {
|
|
|
343
340
|
worldMatrices.subarray(worldOffset, worldOffset + 16).set(localM.values);
|
|
344
341
|
}
|
|
345
342
|
}
|
|
346
|
-
static updateWorldMatrix(boneIndex, bones, localRotations, localTranslations, worldMatrices) {
|
|
347
|
-
const bone = bones[boneIndex];
|
|
348
|
-
const qi = boneIndex * 4;
|
|
349
|
-
const ti = boneIndex * 3;
|
|
350
|
-
const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
|
|
351
|
-
const rotateM = Mat4.fromQuat(localRot.x, localRot.y, localRot.z, localRot.w);
|
|
352
|
-
const localTx = localTranslations[ti];
|
|
353
|
-
const localTy = localTranslations[ti + 1];
|
|
354
|
-
const localTz = localTranslations[ti + 2];
|
|
355
|
-
const localM = Mat4.identity()
|
|
356
|
-
.translateInPlace(bone.bindTranslation[0], bone.bindTranslation[1], bone.bindTranslation[2])
|
|
357
|
-
.multiply(rotateM)
|
|
358
|
-
.translateInPlace(localTx, localTy, localTz);
|
|
359
|
-
const worldOffset = boneIndex * 16;
|
|
360
|
-
if (bone.parentIndex >= 0) {
|
|
361
|
-
const parentOffset = bone.parentIndex * 16;
|
|
362
|
-
const parentMat = new Mat4(worldMatrices.subarray(parentOffset, parentOffset + 16));
|
|
363
|
-
const worldMat = parentMat.multiply(localM);
|
|
364
|
-
worldMatrices.subarray(worldOffset, worldOffset + 16).set(worldMat.values);
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
worldMatrices.subarray(worldOffset, worldOffset + 16).set(localM.values);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
343
|
}
|
|
371
344
|
IKSolverSystem.EPSILON = 1.0e-8;
|
|
372
345
|
IKSolverSystem.THRESHOLD = (88 * Math.PI) / 180;
|