reze-engine 0.3.5 → 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/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 +6 -0
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +98 -101
- package/dist/ik.d.ts +32 -0
- package/dist/ik.d.ts.map +1 -0
- package/dist/ik.js +337 -0
- package/dist/math.d.ts +0 -5
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +0 -55
- package/dist/model.d.ts +1 -3
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +11 -41
- package/dist/player.d.ts +6 -20
- package/dist/player.d.ts.map +1 -1
- package/dist/player.js +88 -191
- package/dist/pool-scene.d.ts +52 -0
- package/dist/pool-scene.d.ts.map +1 -0
- package/dist/pool-scene.js +1122 -0
- package/dist/pool.d.ts +38 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +422 -0
- package/package.json +1 -1
- package/src/engine.ts +54 -101
- package/src/ik-solver.ts +106 -124
- package/src/math.ts +0 -74
- package/src/model.ts +12 -44
- package/src/player.ts +115 -210
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
|
@@ -17,7 +17,13 @@ export declare class IKSolverSystem {
|
|
|
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
29
|
private static updateWorldMatrix;
|
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,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;
|
|
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
|
@@ -91,10 +91,7 @@ export class IKSolverSystem {
|
|
|
91
91
|
chainInfo.ikRotation = new Quat(0, 0, 0, 1);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
|
|
95
|
-
const ikPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
96
|
-
const targetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
97
|
-
if (ikPosition.subtract(targetPosition).length() < this.EPSILON)
|
|
94
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
98
95
|
return;
|
|
99
96
|
// Build IK chains
|
|
100
97
|
const chains = [];
|
|
@@ -106,10 +103,7 @@ export class IKSolverSystem {
|
|
|
106
103
|
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
107
104
|
}
|
|
108
105
|
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined);
|
|
109
|
-
|
|
110
|
-
const updatedIkPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
111
|
-
const updatedTargetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
112
|
-
if (updatedIkPosition.subtract(updatedTargetPosition).length() < this.EPSILON)
|
|
106
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
113
107
|
return;
|
|
114
108
|
// Solve iteratively
|
|
115
109
|
const iteration = Math.min(solver.iterationCount, 256);
|
|
@@ -121,24 +115,17 @@ export class IKSolverSystem {
|
|
|
121
115
|
this.solveChain(chain, chainIndex, solver, ikBoneIndex, targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, i < halfIteration);
|
|
122
116
|
}
|
|
123
117
|
}
|
|
124
|
-
|
|
125
|
-
const currentIkPosition = this.getWorldTranslation(ikBoneIndex, worldMatrices);
|
|
126
|
-
const currentTargetPosition = this.getWorldTranslation(targetBoneIndex, worldMatrices);
|
|
127
|
-
const distance = currentIkPosition.subtract(currentTargetPosition).length();
|
|
128
|
-
if (distance < this.EPSILON)
|
|
118
|
+
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON)
|
|
129
119
|
break;
|
|
130
120
|
}
|
|
131
121
|
// Apply IK rotations to local rotations
|
|
132
122
|
for (const link of solver.links) {
|
|
133
123
|
const chainInfo = ikChainInfo[link.boneIndex];
|
|
134
|
-
if (chainInfo
|
|
124
|
+
if (chainInfo?.ikRotation) {
|
|
135
125
|
const qi = link.boneIndex * 4;
|
|
136
|
-
const localRot =
|
|
126
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
137
127
|
const finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
|
|
138
|
-
localRotations
|
|
139
|
-
localRotations[qi + 1] = finalRot.y;
|
|
140
|
-
localRotations[qi + 2] = finalRot.z;
|
|
141
|
-
localRotations[qi + 3] = finalRot.w;
|
|
128
|
+
this.setQuatToArray(localRotations, qi, finalRot);
|
|
142
129
|
}
|
|
143
130
|
}
|
|
144
131
|
}
|
|
@@ -162,25 +149,20 @@ export class IKSolverSystem {
|
|
|
162
149
|
finalRotationAxis = this.transformNormal(chainRotationAxis, invParentRot).normalize();
|
|
163
150
|
break;
|
|
164
151
|
}
|
|
165
|
-
case InternalSolveAxis.X:
|
|
166
|
-
|
|
167
|
-
const axisX = new Vec3(m[0], m[1], m[2]);
|
|
168
|
-
const dot = chainRotationAxis.dot(axisX);
|
|
169
|
-
finalRotationAxis = new Vec3(dot >= 0 ? 1 : -1, 0, 0);
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
case InternalSolveAxis.Y: {
|
|
173
|
-
const m = parentWorldRotMatrix.values;
|
|
174
|
-
const axisY = new Vec3(m[4], m[5], m[6]);
|
|
175
|
-
const dot = chainRotationAxis.dot(axisY);
|
|
176
|
-
finalRotationAxis = new Vec3(0, dot >= 0 ? 1 : -1, 0);
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
152
|
+
case InternalSolveAxis.X:
|
|
153
|
+
case InternalSolveAxis.Y:
|
|
179
154
|
case InternalSolveAxis.Z: {
|
|
180
155
|
const m = parentWorldRotMatrix.values;
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
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);
|
|
184
166
|
break;
|
|
185
167
|
}
|
|
186
168
|
default:
|
|
@@ -199,72 +181,15 @@ export class IKSolverSystem {
|
|
|
199
181
|
if (chainInfo) {
|
|
200
182
|
chainInfo.ikRotation = ikRotation.multiply(chainInfo.ikRotation);
|
|
201
183
|
// Apply angle constraints if present
|
|
202
|
-
if (chain.minimumAngle
|
|
184
|
+
if (chain.minimumAngle && chain.maximumAngle) {
|
|
203
185
|
const qi = chainBoneIndex * 4;
|
|
204
|
-
const localRot =
|
|
186
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
205
187
|
chainInfo.localRotation = localRot.clone();
|
|
206
188
|
const combinedRot = chainInfo.ikRotation.multiply(localRot);
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
case InternalEulerRotationOrder.YXZ: {
|
|
212
|
-
rX = Math.asin(-m[9]); // m32
|
|
213
|
-
if (Math.abs(rX) > this.THRESHOLD) {
|
|
214
|
-
rX = rX < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
215
|
-
}
|
|
216
|
-
let cosX = Math.cos(rX);
|
|
217
|
-
if (cosX !== 0)
|
|
218
|
-
cosX = 1 / cosX;
|
|
219
|
-
rY = Math.atan2(m[8] * cosX, m[10] * cosX); // m31, m33
|
|
220
|
-
rZ = Math.atan2(m[1] * cosX, m[5] * cosX); // m12, m22
|
|
221
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
222
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
223
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
224
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(0, 1, 0), rY);
|
|
225
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(1, 0, 0), rX));
|
|
226
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ));
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
case InternalEulerRotationOrder.ZYX: {
|
|
230
|
-
rY = Math.asin(-m[2]); // m13
|
|
231
|
-
if (Math.abs(rY) > this.THRESHOLD) {
|
|
232
|
-
rY = rY < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
233
|
-
}
|
|
234
|
-
let cosY = Math.cos(rY);
|
|
235
|
-
if (cosY !== 0)
|
|
236
|
-
cosY = 1 / cosY;
|
|
237
|
-
rX = Math.atan2(m[6] * cosY, m[10] * cosY); // m23, m33
|
|
238
|
-
rZ = Math.atan2(m[1] * cosY, m[0] * cosY); // m12, m11
|
|
239
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
240
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
241
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
242
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ);
|
|
243
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 1, 0), rY));
|
|
244
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(1, 0, 0), rX));
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
case InternalEulerRotationOrder.XZY: {
|
|
248
|
-
rZ = Math.asin(-m[4]); // m21
|
|
249
|
-
if (Math.abs(rZ) > this.THRESHOLD) {
|
|
250
|
-
rZ = rZ < 0 ? -this.THRESHOLD : this.THRESHOLD;
|
|
251
|
-
}
|
|
252
|
-
let cosZ = Math.cos(rZ);
|
|
253
|
-
if (cosZ !== 0)
|
|
254
|
-
cosZ = 1 / cosZ;
|
|
255
|
-
rX = Math.atan2(m[6] * cosZ, m[5] * cosZ); // m23, m22
|
|
256
|
-
rY = Math.atan2(m[8] * cosZ, m[0] * cosZ); // m31, m11
|
|
257
|
-
rX = this.limitAngle(rX, chain.minimumAngle.x, chain.maximumAngle.x, useAxis);
|
|
258
|
-
rY = this.limitAngle(rY, chain.minimumAngle.y, chain.maximumAngle.y, useAxis);
|
|
259
|
-
rZ = this.limitAngle(rZ, chain.minimumAngle.z, chain.maximumAngle.z, useAxis);
|
|
260
|
-
chainInfo.ikRotation = Quat.fromAxisAngle(new Vec3(1, 0, 0), rX);
|
|
261
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 0, 1), rZ));
|
|
262
|
-
chainInfo.ikRotation = chainInfo.ikRotation.multiply(Quat.fromAxisAngle(new Vec3(0, 1, 0), rY));
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
const invertedLocalRotation = localRot.conjugate().normalize();
|
|
267
|
-
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());
|
|
268
193
|
}
|
|
269
194
|
}
|
|
270
195
|
// Update world matrices for affected bones (using IK-modified rotations)
|
|
@@ -287,10 +212,83 @@ export class IKSolverSystem {
|
|
|
287
212
|
return angle;
|
|
288
213
|
}
|
|
289
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
|
+
}
|
|
290
220
|
static getWorldTranslation(boneIndex, worldMatrices) {
|
|
291
221
|
const offset = boneIndex * 16;
|
|
292
222
|
return new Vec3(worldMatrices[offset + 12], worldMatrices[offset + 13], worldMatrices[offset + 14]);
|
|
293
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
|
+
}
|
|
294
292
|
static getParentWorldRotationMatrix(boneIndex, bones, worldMatrices) {
|
|
295
293
|
const bone = bones[boneIndex];
|
|
296
294
|
if (bone.parentIndex >= 0) {
|
|
@@ -314,8 +312,7 @@ export class IKSolverSystem {
|
|
|
314
312
|
const bone = bones[boneIndex];
|
|
315
313
|
const qi = boneIndex * 4;
|
|
316
314
|
const ti = boneIndex * 3;
|
|
317
|
-
|
|
318
|
-
const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
|
|
315
|
+
const localRot = this.getQuatFromArray(localRotations, qi);
|
|
319
316
|
// Apply IK rotation if available
|
|
320
317
|
let finalRot = localRot;
|
|
321
318
|
if (ikChainInfo) {
|
package/dist/ik.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Vec3 } from "./math";
|
|
2
|
+
import type { Skeleton } from "./model";
|
|
3
|
+
export interface IKLink {
|
|
4
|
+
boneIndex: number;
|
|
5
|
+
hasLimit: boolean;
|
|
6
|
+
minAngle?: Vec3;
|
|
7
|
+
maxAngle?: Vec3;
|
|
8
|
+
}
|
|
9
|
+
export interface IKChain {
|
|
10
|
+
targetBoneIndex: number;
|
|
11
|
+
effectorBoneIndex: number;
|
|
12
|
+
iterationCount: number;
|
|
13
|
+
rotationConstraint: number;
|
|
14
|
+
links: IKLink[];
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare class IK {
|
|
18
|
+
private chains;
|
|
19
|
+
private computeWorldMatricesCallback?;
|
|
20
|
+
private lastTargetPositions;
|
|
21
|
+
private convergedChains;
|
|
22
|
+
private ikRotations;
|
|
23
|
+
constructor(chains?: IKChain[]);
|
|
24
|
+
setComputeWorldMatricesCallback(callback: () => void): void;
|
|
25
|
+
getChains(): IKChain[];
|
|
26
|
+
enableChain(targetBoneName: string, enabled: boolean): void;
|
|
27
|
+
solve(skeleton: Skeleton, localRotations: Float32Array, localTranslations: Float32Array, worldMatrices: Float32Array): void;
|
|
28
|
+
private solveCCD;
|
|
29
|
+
private applyAngleConstraints;
|
|
30
|
+
private computeWorldMatrices;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ik.d.ts.map
|
package/dist/ik.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ik.d.ts","sourceRoot":"","sources":["../src/ik.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,IAAI,EAAQ,MAAM,QAAQ,CAAA;AACzC,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,WAAW,MAAM;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,QAAQ,CAAC,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;IACtB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,qBAAa,EAAE;IACb,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,4BAA4B,CAAC,CAAY;IAEjD,OAAO,CAAC,mBAAmB,CAA+B;IAE1D,OAAO,CAAC,eAAe,CAAyB;IAEhD,OAAO,CAAC,WAAW,CAA+B;gBAEtC,MAAM,GAAE,OAAO,EAAO;IAMlC,+BAA+B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI3D,SAAS,IAAI,OAAO,EAAE;IAKtB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAU3D,KAAK,CACH,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,YAAY,EAC5B,iBAAiB,EAAE,YAAY,EAC/B,aAAa,EAAE,YAAY,GAC1B,IAAI;IA2FP,OAAO,CAAC,QAAQ;IAqLhB,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,oBAAoB;CAsG7B"}
|