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.
@@ -1,4 +1,3 @@
1
1
  import type { AmmoInstance } from "@fred3d/ammo";
2
2
  export declare function loadAmmo(): Promise<AmmoInstance>;
3
- export declare function getAmmoInstance(): AmmoInstance | null;
4
3
  //# sourceMappingURL=ammo-loader.d.ts.map
@@ -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;AAED,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD"}
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"}
@@ -24,6 +24,3 @@ export async function loadAmmo() {
24
24
  })();
25
25
  return ammoPromise;
26
26
  }
27
- export function getAmmoInstance() {
28
- return ammoInstance;
29
- }
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) {
@@ -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[], usePhysics?: boolean): void;
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
@@ -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,EAAiC,MAAM,SAAS,CAAA;AAoE5F;;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,EAC1B,UAAU,GAAE,OAAe,GAC1B,IAAI;IASP,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,uBAAuB;IA8CtC,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAsCjC"}
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, usePhysics = false) {
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
- // Get IK bone and target positions
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
- // Re-read positions after initial update
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
- // Re-read positions after this iteration
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 && chainInfo.ikRotation) {
124
+ if (chainInfo?.ikRotation) {
138
125
  const qi = link.boneIndex * 4;
139
- const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
126
+ const localRot = this.getQuatFromArray(localRotations, qi);
140
127
  const finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
141
- localRotations[qi] = finalRot.x;
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
- const m = parentWorldRotMatrix.values;
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 axisZ = new Vec3(m[8], m[9], m[10]);
185
- const dot = chainRotationAxis.dot(axisZ);
186
- 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);
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 !== null && chain.maximumAngle !== null) {
184
+ if (chain.minimumAngle && chain.maximumAngle) {
206
185
  const qi = chainBoneIndex * 4;
207
- const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
186
+ const localRot = this.getQuatFromArray(localRotations, qi);
208
187
  chainInfo.localRotation = localRot.clone();
209
188
  const combinedRot = chainInfo.ikRotation.multiply(localRot);
210
- const rotMatrix = Mat4.fromQuat(combinedRot.x, combinedRot.y, combinedRot.z, combinedRot.w);
211
- const m = rotMatrix.values;
212
- let rX, rY, rZ;
213
- switch (chain.rotationOrder) {
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.updateWorldMatrixWithIK(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo);
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 updateWorldMatrixWithIK(boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo) {
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
- // Use IK-modified rotation if available
321
- const localRot = new Quat(localRotations[qi], localRotations[qi + 1], localRotations[qi + 2], localRotations[qi + 3]);
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 (chainInfo && chainInfo.ikRotation) {
325
- finalRot = chainInfo.ikRotation.multiply(localRot).normalize();
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;