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 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;
@@ -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
- // Create material uniform data
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
- if (mat.isEye) {
1432
+ const addDrawCall = (draws) => {
1452
1433
  if (indexCount > 0) {
1453
- this.eyeDraws.push({
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 uniformData = new Float32Array(8);
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
- if (indexCount > 0) {
1508
- this.transparentDraws.push({
1509
- count: indexCount,
1510
- firstIndex: currentIndexOffset,
1511
- bindGroup,
1512
- });
1513
- }
1473
+ addDrawCall(this.transparentDraws);
1514
1474
  }
1515
1475
  else {
1516
- if (indexCount > 0) {
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(8);
1527
- materialUniformData[0] = mat.edgeColor[0]; // edgeColor.r
1528
- materialUniformData[1] = mat.edgeColor[1]; // edgeColor.g
1529
- materialUniformData[2] = mat.edgeColor[2]; // edgeColor.b
1530
- materialUniformData[3] = mat.edgeColor[3]; // edgeColor.a
1531
- materialUniformData[4] = mat.edgeSize;
1532
- materialUniformData[5] = 0.0; // isOverEyes
1533
- materialUniformData[6] = 0.0;
1534
- materialUniformData[7] = 0.0;
1535
- const materialUniformBuffer = this.device.createBuffer({
1536
- label: `outline material uniform: ${mat.name}`,
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
- if (mat.isEye) {
1552
- this.eyeOutlineDraws.push({
1553
- count: indexCount,
1554
- firstIndex: currentIndexOffset,
1555
- bindGroup: outlineBindGroup,
1556
- });
1557
- }
1558
- else if (mat.isHair) {
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) {
@@ -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;
@@ -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;IAgGtB,OAAO,CAAC,MAAM,CAAC,UAAU;IAoKzB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYzB,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAKlC,OAAO,CAAC,MAAM,CAAC,4BAA4B;IAe3C,OAAO,CAAC,MAAM,CAAC,eAAe;IAS9B,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAiDjC"}
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
- // Get IK bone and target positions
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
- // Re-read positions after initial update
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
- // Re-read positions after this iteration
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 && chainInfo.ikRotation) {
124
+ if (chainInfo?.ikRotation) {
135
125
  const qi = link.boneIndex * 4;
136
- const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
126
+ const localRot = this.getQuatFromArray(localRotations, qi);
137
127
  const finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
138
- localRotations[qi] = finalRot.x;
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
- const m = parentWorldRotMatrix.values;
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 axisZ = new Vec3(m[8], m[9], m[10]);
182
- const dot = chainRotationAxis.dot(axisZ);
183
- finalRotationAxis = new Vec3(0, 0, dot >= 0 ? 1 : -1);
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 !== null && chain.maximumAngle !== null) {
184
+ if (chain.minimumAngle && chain.maximumAngle) {
203
185
  const qi = chainBoneIndex * 4;
204
- const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
186
+ const localRot = this.getQuatFromArray(localRotations, qi);
205
187
  chainInfo.localRotation = localRot.clone();
206
188
  const combinedRot = chainInfo.ikRotation.multiply(localRot);
207
- const rotMatrix = Mat4.fromQuat(combinedRot.x, combinedRot.y, combinedRot.z, combinedRot.w);
208
- const m = rotMatrix.values;
209
- let rX, rY, rZ;
210
- switch (chain.rotationOrder) {
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
- // Get local rotation
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
@@ -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"}