reze-engine 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -6
- package/dist/engine.d.ts +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +3 -0
- package/dist/ik-solver.d.ts +2 -1
- package/dist/ik-solver.d.ts.map +1 -1
- package/dist/ik-solver.js +31 -14
- package/dist/model.d.ts +13 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +168 -8
- package/package.json +1 -1
- package/src/engine.ts +8 -0
- package/src/ik-solver.ts +37 -14
- package/src/model.ts +200 -16
- package/dist/bezier-interpolate.d.ts +0 -15
- package/dist/bezier-interpolate.d.ts.map +0 -1
- package/dist/bezier-interpolate.js +0 -40
- package/dist/engine_ts.d.ts +0 -143
- package/dist/engine_ts.d.ts.map +0 -1
- package/dist/engine_ts.js +0 -1575
- package/dist/ik.d.ts +0 -32
- package/dist/ik.d.ts.map +0 -1
- package/dist/ik.js +0 -337
- package/dist/player.d.ts +0 -64
- package/dist/player.d.ts.map +0 -1
- package/dist/player.js +0 -220
- package/dist/pool-scene.d.ts +0 -52
- package/dist/pool-scene.d.ts.map +0 -1
- package/dist/pool-scene.js +0 -1122
- package/dist/pool.d.ts +0 -38
- package/dist/pool.d.ts.map +0 -1
- package/dist/pool.js +0 -422
- package/dist/rzm-converter.d.ts +0 -12
- package/dist/rzm-converter.d.ts.map +0 -1
- package/dist/rzm-converter.js +0 -40
- package/dist/rzm-loader.d.ts +0 -24
- package/dist/rzm-loader.d.ts.map +0 -1
- package/dist/rzm-loader.js +0 -488
- package/dist/rzm-writer.d.ts +0 -27
- package/dist/rzm-writer.d.ts.map +0 -1
- package/dist/rzm-writer.js +0 -701
package/src/ik-solver.ts
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
import { Mat4, Quat, Vec3 } from "./math"
|
|
8
8
|
import { Bone, IKLink, IKSolver, IKChainInfo } from "./model"
|
|
9
9
|
|
|
10
|
+
// Callback type for updating world matrix (provided by model to handle append transformations)
|
|
11
|
+
export type UpdateWorldMatrixFn = (boneIndex: number, applyIK: boolean) => void
|
|
12
|
+
|
|
10
13
|
const enum InternalEulerRotationOrder {
|
|
11
14
|
YXZ = 0,
|
|
12
15
|
ZYX = 1,
|
|
@@ -89,10 +92,11 @@ export class IKSolverSystem {
|
|
|
89
92
|
localRotations: Quat[],
|
|
90
93
|
localTranslations: Vec3[],
|
|
91
94
|
worldMatrices: Mat4[],
|
|
92
|
-
ikChainInfo: IKChainInfo[]
|
|
95
|
+
ikChainInfo: IKChainInfo[],
|
|
96
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
93
97
|
): void {
|
|
94
98
|
for (const solver of ikSolvers) {
|
|
95
|
-
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo)
|
|
99
|
+
this.solveIK(solver, bones, localRotations, localTranslations, worldMatrices, ikChainInfo, updateWorldMatrix)
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
|
|
@@ -102,7 +106,8 @@ export class IKSolverSystem {
|
|
|
102
106
|
localRotations: Quat[],
|
|
103
107
|
localTranslations: Vec3[],
|
|
104
108
|
worldMatrices: Mat4[],
|
|
105
|
-
ikChainInfo: IKChainInfo[]
|
|
109
|
+
ikChainInfo: IKChainInfo[],
|
|
110
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
106
111
|
): void {
|
|
107
112
|
if (solver.links.length === 0) return
|
|
108
113
|
|
|
@@ -126,10 +131,17 @@ export class IKSolverSystem {
|
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
// Update chain bones and target bone world matrices (initial state, no IK yet)
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
if (updateWorldMatrix) {
|
|
135
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
136
|
+
updateWorldMatrix(chains[i].boneIndex, false)
|
|
137
|
+
}
|
|
138
|
+
updateWorldMatrix(targetBoneIndex, false)
|
|
139
|
+
} else {
|
|
140
|
+
for (let i = chains.length - 1; i >= 0; i--) {
|
|
141
|
+
this.updateWorldMatrix(chains[i].boneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
142
|
+
}
|
|
143
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
131
144
|
}
|
|
132
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
133
145
|
|
|
134
146
|
if (this.getDistance(ikBoneIndex, targetBoneIndex, worldMatrices) < this.EPSILON) return
|
|
135
147
|
|
|
@@ -152,7 +164,8 @@ export class IKSolverSystem {
|
|
|
152
164
|
localTranslations,
|
|
153
165
|
worldMatrices,
|
|
154
166
|
ikChainInfo,
|
|
155
|
-
i < halfIteration
|
|
167
|
+
i < halfIteration,
|
|
168
|
+
updateWorldMatrix
|
|
156
169
|
)
|
|
157
170
|
}
|
|
158
171
|
}
|
|
@@ -182,7 +195,8 @@ export class IKSolverSystem {
|
|
|
182
195
|
localTranslations: Vec3[],
|
|
183
196
|
worldMatrices: Mat4[],
|
|
184
197
|
ikChainInfo: IKChainInfo[],
|
|
185
|
-
useAxis: boolean
|
|
198
|
+
useAxis: boolean,
|
|
199
|
+
updateWorldMatrix?: UpdateWorldMatrixFn
|
|
186
200
|
): void {
|
|
187
201
|
const chainBoneIndex = chain.boneIndex
|
|
188
202
|
const chainPosition = this.getWorldTranslation(chainBoneIndex, worldMatrices)
|
|
@@ -254,13 +268,21 @@ export class IKSolverSystem {
|
|
|
254
268
|
}
|
|
255
269
|
}
|
|
256
270
|
|
|
257
|
-
// Update world matrices for affected bones (using
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
271
|
+
// Update world matrices for affected bones (using callback - handles append correctly)
|
|
272
|
+
if (updateWorldMatrix) {
|
|
273
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
274
|
+
const link = solver.links[i]
|
|
275
|
+
updateWorldMatrix(link.boneIndex, true) // applyIK = true
|
|
276
|
+
}
|
|
277
|
+
updateWorldMatrix(targetBoneIndex, false)
|
|
278
|
+
} else {
|
|
279
|
+
for (let i = chainIndex; i >= 0; i--) {
|
|
280
|
+
const link = solver.links[i]
|
|
281
|
+
this.updateWorldMatrix(link.boneIndex, bones, localRotations, localTranslations, worldMatrices, ikChainInfo)
|
|
282
|
+
}
|
|
283
|
+
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
284
|
+
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
261
285
|
}
|
|
262
|
-
this.updateWorldMatrix(ikBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
263
|
-
this.updateWorldMatrix(targetBoneIndex, bones, localRotations, localTranslations, worldMatrices, undefined)
|
|
264
286
|
}
|
|
265
287
|
|
|
266
288
|
private static limitAngle(angle: number, min: number, max: number, useAxis: boolean): number {
|
|
@@ -410,3 +432,4 @@ export class IKSolverSystem {
|
|
|
410
432
|
}
|
|
411
433
|
}
|
|
412
434
|
}
|
|
435
|
+
|
package/src/model.ts
CHANGED
|
@@ -581,8 +581,12 @@ export class Model {
|
|
|
581
581
|
/**
|
|
582
582
|
* Convert VMD-style relative translation (relative to bind pose world position) to local translation
|
|
583
583
|
* This helper is used by both moveBones and getPoseAtTime to ensure consistent translation handling
|
|
584
|
+
* @param boneIdx - Bone index
|
|
585
|
+
* @param vmdRelativeTranslation - VMD relative translation
|
|
586
|
+
* @param rotation - Optional rotation to use for conversion. If not provided, uses current localRotation.
|
|
587
|
+
* Use animation rotation (from frame) to avoid conflicts when IK modifies rotation.
|
|
584
588
|
*/
|
|
585
|
-
private convertVMDTranslationToLocal(boneIdx: number, vmdRelativeTranslation: Vec3): Vec3 {
|
|
589
|
+
private convertVMDTranslationToLocal(boneIdx: number, vmdRelativeTranslation: Vec3, rotation?: Quat): Vec3 {
|
|
586
590
|
const skeleton = this.skeleton
|
|
587
591
|
const bones = skeleton.bones
|
|
588
592
|
const localRot = this.runtimeSkeleton.localRotations
|
|
@@ -625,7 +629,9 @@ export class Model {
|
|
|
625
629
|
)
|
|
626
630
|
|
|
627
631
|
// Apply inverse rotation to get local translation
|
|
628
|
-
|
|
632
|
+
// Use provided rotation (animation rotation) or fall back to current localRotation
|
|
633
|
+
// Using animation rotation prevents conflicts when IK modifies the rotation
|
|
634
|
+
const localRotation = rotation ?? localRot[boneIdx]
|
|
629
635
|
// Clone to avoid mutating, then conjugate and normalize
|
|
630
636
|
const invRotation = localRotation.clone().conjugate().normalize()
|
|
631
637
|
const rotationMat = Mat4.fromQuat(invRotation.x, invRotation.y, invRotation.z, invRotation.w)
|
|
@@ -717,6 +723,57 @@ export class Model {
|
|
|
717
723
|
this.applyMorphs()
|
|
718
724
|
}
|
|
719
725
|
|
|
726
|
+
/**
|
|
727
|
+
* Atomic pose setter for external animation editors.
|
|
728
|
+
* Sets bone rotations, translations, and morph weights in a single pass,
|
|
729
|
+
* identical to how getPoseAtTime applies VMD poses during playback.
|
|
730
|
+
* Cancels any active tweens on affected bones/morphs.
|
|
731
|
+
*/
|
|
732
|
+
setPose(
|
|
733
|
+
rotations?: Record<string, Quat>,
|
|
734
|
+
translations?: Record<string, Vec3>,
|
|
735
|
+
morphs?: Record<string, number>
|
|
736
|
+
): void {
|
|
737
|
+
const state = this.tweenState
|
|
738
|
+
|
|
739
|
+
if (rotations) {
|
|
740
|
+
for (const [name, quat] of Object.entries(rotations)) {
|
|
741
|
+
const idx = this.runtimeSkeleton.nameIndex[name] ?? -1
|
|
742
|
+
if (idx < 0 || idx >= this.skeleton.bones.length) continue
|
|
743
|
+
|
|
744
|
+
this.runtimeSkeleton.localRotations[idx].set(quat.clone().normalize())
|
|
745
|
+
state.rotActive[idx] = 0
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (translations) {
|
|
750
|
+
for (const [name, vec] of Object.entries(translations)) {
|
|
751
|
+
const idx = this.runtimeSkeleton.nameIndex[name] ?? -1
|
|
752
|
+
if (idx < 0 || idx >= this.skeleton.bones.length) continue
|
|
753
|
+
|
|
754
|
+
const rotation = rotations?.[name]?.clone().normalize()
|
|
755
|
+
const localTranslation = this.convertVMDTranslationToLocal(idx, vec, rotation)
|
|
756
|
+
this.runtimeSkeleton.localTranslations[idx].set(localTranslation)
|
|
757
|
+
state.transActive[idx] = 0
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (morphs) {
|
|
762
|
+
let morphChanged = false
|
|
763
|
+
for (const [name, weight] of Object.entries(morphs)) {
|
|
764
|
+
const idx = this.runtimeMorph.nameIndex[name] ?? -1
|
|
765
|
+
if (idx < 0 || idx >= this.runtimeMorph.weights.length) continue
|
|
766
|
+
|
|
767
|
+
this.runtimeMorph.weights[idx] = Math.max(0, Math.min(1, weight))
|
|
768
|
+
state.morphActive[idx] = 0
|
|
769
|
+
morphChanged = true
|
|
770
|
+
}
|
|
771
|
+
if (morphChanged) {
|
|
772
|
+
this.applyMorphs()
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
720
777
|
private applyMorphs(): void {
|
|
721
778
|
// Reset vertex data to base positions
|
|
722
779
|
this.vertexData.set(this.baseVertexData)
|
|
@@ -1016,9 +1073,12 @@ export class Model {
|
|
|
1016
1073
|
|
|
1017
1074
|
if (!frameB) {
|
|
1018
1075
|
// No interpolation needed - direct assignment
|
|
1019
|
-
|
|
1020
|
-
//
|
|
1021
|
-
const
|
|
1076
|
+
// Use animation frame's rotation for translation conversion to ensure consistency
|
|
1077
|
+
// This prevents conflicts when IK later modifies the rotation
|
|
1078
|
+
const frameRotation = frameA.rotation
|
|
1079
|
+
localRot.set(frameRotation)
|
|
1080
|
+
// Convert VMD relative translation to local translation using animation rotation
|
|
1081
|
+
const localTranslation = this.convertVMDTranslationToLocal(boneIdx, frameA.translation, frameRotation)
|
|
1022
1082
|
localTrans.set(localTranslation)
|
|
1023
1083
|
} else {
|
|
1024
1084
|
const timeA = keyFrames[idx].time
|
|
@@ -1061,8 +1121,10 @@ export class Model {
|
|
|
1061
1121
|
frameA.translation.z + (frameB.translation.z - frameA.translation.z) * tzWeight
|
|
1062
1122
|
)
|
|
1063
1123
|
|
|
1064
|
-
// Convert interpolated VMD translation to local translation
|
|
1065
|
-
|
|
1124
|
+
// Convert interpolated VMD translation to local translation using animation rotation
|
|
1125
|
+
// This ensures translation is computed for the animation rotation, not the runtime rotation
|
|
1126
|
+
// that will be modified by IK, preventing conflicts
|
|
1127
|
+
const localTranslation = this.convertVMDTranslationToLocal(boneIdx, interpolatedVMDTranslation, rotation)
|
|
1066
1128
|
|
|
1067
1129
|
// Direct property writes to avoid object allocation
|
|
1068
1130
|
localRot.set(rotation)
|
|
@@ -1161,14 +1223,136 @@ export class Model {
|
|
|
1161
1223
|
const ikChainInfo = this.runtimeSkeleton.ikChainInfo
|
|
1162
1224
|
if (!ikChainInfo) return
|
|
1163
1225
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
this.
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1226
|
+
// Solve each IK solver sequentially, ensuring consistent state between solvers
|
|
1227
|
+
for (const solver of ikSolvers) {
|
|
1228
|
+
// Recompute ALL world matrices before each solver starts
|
|
1229
|
+
// This ensures each solver sees the effects of previous solvers on localRotations
|
|
1230
|
+
this.computeWorldMatrices()
|
|
1231
|
+
|
|
1232
|
+
// Clear computed set for this solver's pass
|
|
1233
|
+
this.ikComputedSet.clear()
|
|
1234
|
+
|
|
1235
|
+
// Solve this IK chain
|
|
1236
|
+
// Pass callback that uses model's world matrix computation (handles append correctly)
|
|
1237
|
+
IKSolverSystem.solve(
|
|
1238
|
+
[solver], // Solve one at a time
|
|
1239
|
+
this.skeleton.bones,
|
|
1240
|
+
this.runtimeSkeleton.localRotations,
|
|
1241
|
+
this.runtimeSkeleton.localTranslations,
|
|
1242
|
+
this.runtimeSkeleton.worldMatrices,
|
|
1243
|
+
ikChainInfo,
|
|
1244
|
+
(boneIndex, applyIK) => {
|
|
1245
|
+
// Clear computed set for each bone update to allow recomputation in same iteration
|
|
1246
|
+
this.ikComputedSet.delete(boneIndex)
|
|
1247
|
+
this.computeSingleBoneWorldMatrix(boneIndex, applyIK)
|
|
1248
|
+
}
|
|
1249
|
+
)
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// Cached set to track which bones are being computed in current IK pass (to avoid infinite recursion)
|
|
1254
|
+
private ikComputedSet: Set<number> = new Set()
|
|
1255
|
+
|
|
1256
|
+
// Add this new method to compute a single bone's world matrix
|
|
1257
|
+
// Recursively ensures parents are computed first to avoid using stale parent matrices
|
|
1258
|
+
private computeSingleBoneWorldMatrix(boneIndex: number, applyIK: boolean): void {
|
|
1259
|
+
const bones = this.skeleton.bones
|
|
1260
|
+
const localRot = this.runtimeSkeleton.localRotations
|
|
1261
|
+
const localTrans = this.runtimeSkeleton.localTranslations
|
|
1262
|
+
const worldMats = this.runtimeSkeleton.worldMatrices
|
|
1263
|
+
const ikChainInfo = this.runtimeSkeleton.ikChainInfo
|
|
1264
|
+
|
|
1265
|
+
const b = bones[boneIndex]
|
|
1266
|
+
|
|
1267
|
+
// Prevent infinite recursion: if this bone is already being computed in this call chain, skip
|
|
1268
|
+
if (this.ikComputedSet.has(boneIndex)) {
|
|
1269
|
+
return
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// Mark this bone as being computed to prevent infinite recursion
|
|
1273
|
+
this.ikComputedSet.add(boneIndex)
|
|
1274
|
+
|
|
1275
|
+
// Recursively compute parent first if it exists (ensures parent matrix is up-to-date)
|
|
1276
|
+
if (b.parentIndex >= 0) {
|
|
1277
|
+
this.computeSingleBoneWorldMatrix(b.parentIndex, applyIK)
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// Get base rotation
|
|
1281
|
+
let boneRot = localRot[boneIndex]
|
|
1282
|
+
|
|
1283
|
+
// Apply IK rotation if requested
|
|
1284
|
+
if (applyIK && ikChainInfo) {
|
|
1285
|
+
const chainInfo = ikChainInfo[boneIndex]
|
|
1286
|
+
if (chainInfo?.ikRotation) {
|
|
1287
|
+
boneRot = chainInfo.ikRotation.multiply(boneRot).normalize()
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
let rotateM = Mat4.fromQuat(boneRot.x, boneRot.y, boneRot.z, boneRot.w)
|
|
1292
|
+
let addLocalTx = 0, addLocalTy = 0, addLocalTz = 0
|
|
1293
|
+
|
|
1294
|
+
// Handle append transformations (same logic as computeWorldMatrices)
|
|
1295
|
+
const appendParentIdx = b.appendParentIndex
|
|
1296
|
+
const hasAppend = b.appendRotate &&
|
|
1297
|
+
appendParentIdx !== undefined &&
|
|
1298
|
+
appendParentIdx >= 0 &&
|
|
1299
|
+
appendParentIdx < bones.length
|
|
1300
|
+
|
|
1301
|
+
if (hasAppend) {
|
|
1302
|
+
const ratio = b.appendRatio === undefined ? 1 : Math.max(-1, Math.min(1, b.appendRatio))
|
|
1303
|
+
const hasRatio = Math.abs(ratio) > 1e-6
|
|
1304
|
+
|
|
1305
|
+
if (hasRatio) {
|
|
1306
|
+
if (b.appendRotate) {
|
|
1307
|
+
// Get append parent's rotation
|
|
1308
|
+
// During IK solving, use only base local rotation (not IK rotations) to avoid
|
|
1309
|
+
// conflicts with IK rotations that are still being computed incrementally
|
|
1310
|
+
// IK rotations will be applied to localRotations after IK solving completes
|
|
1311
|
+
if (appendParentIdx >= 0) {
|
|
1312
|
+
// Compute append parent's world matrix for dependency order, but use base rotation for append
|
|
1313
|
+
this.computeSingleBoneWorldMatrix(appendParentIdx, applyIK)
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// Use append parent's base local rotation only (IK rotations are applied after solving)
|
|
1317
|
+
let appendRot = localRot[appendParentIdx]
|
|
1318
|
+
|
|
1319
|
+
let ax = appendRot.x, ay = appendRot.y, az = appendRot.z
|
|
1320
|
+
const aw = appendRot.w
|
|
1321
|
+
const absRatio = ratio < 0 ? -ratio : ratio
|
|
1322
|
+
if (ratio < 0) { ax = -ax; ay = -ay; az = -az }
|
|
1323
|
+
|
|
1324
|
+
const appendQuat = new Quat(ax, ay, az, aw)
|
|
1325
|
+
const result = Quat.slerp(Quat.identity(), appendQuat, absRatio)
|
|
1326
|
+
rotateM = Mat4.fromQuat(result.x, result.y, result.z, result.w).multiply(rotateM)
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
if (b.appendMove) {
|
|
1330
|
+
const appendTrans = localTrans[appendParentIdx]
|
|
1331
|
+
addLocalTx = appendTrans.x * ratio
|
|
1332
|
+
addLocalTy = appendTrans.y * ratio
|
|
1333
|
+
addLocalTz = appendTrans.z * ratio
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
const boneTrans = localTrans[boneIndex]
|
|
1339
|
+
const localTx = boneTrans.x + addLocalTx
|
|
1340
|
+
const localTy = boneTrans.y + addLocalTy
|
|
1341
|
+
const localTz = boneTrans.z + addLocalTz
|
|
1342
|
+
|
|
1343
|
+
this.cachedIdentityMat1
|
|
1344
|
+
.setIdentity()
|
|
1345
|
+
.translateInPlace(b.bindTranslation[0], b.bindTranslation[1], b.bindTranslation[2])
|
|
1346
|
+
this.cachedIdentityMat2.setIdentity().translateInPlace(localTx, localTy, localTz)
|
|
1347
|
+
const localM = this.cachedIdentityMat1.multiply(rotateM).multiply(this.cachedIdentityMat2)
|
|
1348
|
+
|
|
1349
|
+
const worldMat = worldMats[boneIndex]
|
|
1350
|
+
if (b.parentIndex >= 0) {
|
|
1351
|
+
const parentMat = worldMats[b.parentIndex]
|
|
1352
|
+
Mat4.multiplyArrays(parentMat.values, 0, localM.values, 0, worldMat.values, 0)
|
|
1353
|
+
} else {
|
|
1354
|
+
worldMat.values.set(localM.values)
|
|
1355
|
+
}
|
|
1172
1356
|
}
|
|
1173
1357
|
|
|
1174
1358
|
private computeWorldMatrices(): void {
|
|
@@ -1261,4 +1445,4 @@ export class Model {
|
|
|
1261
1445
|
// Process all bones (recursion handles dependencies automatically)
|
|
1262
1446
|
for (let i = 0; i < boneCount; i++) computeWorld(i)
|
|
1263
1447
|
}
|
|
1264
|
-
}
|
|
1448
|
+
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bezier interpolation for VMD animations
|
|
3
|
-
* Based on the reference implementation from babylon-mmd
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Bezier interpolation function
|
|
7
|
-
* @param x1 First control point X (0-127, normalized to 0-1)
|
|
8
|
-
* @param x2 Second control point X (0-127, normalized to 0-1)
|
|
9
|
-
* @param y1 First control point Y (0-127, normalized to 0-1)
|
|
10
|
-
* @param y2 Second control point Y (0-127, normalized to 0-1)
|
|
11
|
-
* @param t Interpolation parameter (0-1)
|
|
12
|
-
* @returns Interpolated value (0-1)
|
|
13
|
-
*/
|
|
14
|
-
export declare function bezierInterpolate(x1: number, x2: number, y1: number, y2: number, t: number): number;
|
|
15
|
-
//# sourceMappingURL=bezier-interpolate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bezier-interpolate.d.ts","sourceRoot":"","sources":["../src/bezier-interpolate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgCnG"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bezier interpolation for VMD animations
|
|
3
|
-
* Based on the reference implementation from babylon-mmd
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Bezier interpolation function
|
|
7
|
-
* @param x1 First control point X (0-127, normalized to 0-1)
|
|
8
|
-
* @param x2 Second control point X (0-127, normalized to 0-1)
|
|
9
|
-
* @param y1 First control point Y (0-127, normalized to 0-1)
|
|
10
|
-
* @param y2 Second control point Y (0-127, normalized to 0-1)
|
|
11
|
-
* @param t Interpolation parameter (0-1)
|
|
12
|
-
* @returns Interpolated value (0-1)
|
|
13
|
-
*/
|
|
14
|
-
export function bezierInterpolate(x1, x2, y1, y2, t) {
|
|
15
|
-
// Clamp t to [0, 1]
|
|
16
|
-
t = Math.max(0, Math.min(1, t));
|
|
17
|
-
// Binary search for the t value that gives us the desired x
|
|
18
|
-
// We're solving for t in the Bezier curve: x(t) = 3*(1-t)^2*t*x1 + 3*(1-t)*t^2*x2 + t^3
|
|
19
|
-
let start = 0;
|
|
20
|
-
let end = 1;
|
|
21
|
-
let mid = 0.5;
|
|
22
|
-
// Iterate until we find the t value that gives us the desired x
|
|
23
|
-
for (let i = 0; i < 15; i++) {
|
|
24
|
-
// Evaluate Bezier curve at mid point
|
|
25
|
-
const x = 3 * (1 - mid) * (1 - mid) * mid * x1 + 3 * (1 - mid) * mid * mid * x2 + mid * mid * mid;
|
|
26
|
-
if (Math.abs(x - t) < 0.0001) {
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
if (x < t) {
|
|
30
|
-
start = mid;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
end = mid;
|
|
34
|
-
}
|
|
35
|
-
mid = (start + end) / 2;
|
|
36
|
-
}
|
|
37
|
-
// Now evaluate the y value at this t
|
|
38
|
-
const y = 3 * (1 - mid) * (1 - mid) * mid * y1 + 3 * (1 - mid) * mid * mid * y2 + mid * mid * mid;
|
|
39
|
-
return y;
|
|
40
|
-
}
|
package/dist/engine_ts.d.ts
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { Quat, Vec3 } from "reze-mmd";
|
|
2
|
-
export type EngineOptions = {
|
|
3
|
-
ambientColor?: Vec3;
|
|
4
|
-
bloomIntensity?: number;
|
|
5
|
-
rimLightIntensity?: number;
|
|
6
|
-
cameraDistance?: number;
|
|
7
|
-
cameraTarget?: Vec3;
|
|
8
|
-
};
|
|
9
|
-
export interface EngineStats {
|
|
10
|
-
fps: number;
|
|
11
|
-
frameTime: number;
|
|
12
|
-
}
|
|
13
|
-
export declare class Engine {
|
|
14
|
-
private canvas;
|
|
15
|
-
private device;
|
|
16
|
-
private context;
|
|
17
|
-
private presentationFormat;
|
|
18
|
-
private camera;
|
|
19
|
-
private cameraUniformBuffer;
|
|
20
|
-
private cameraMatrixData;
|
|
21
|
-
private cameraDistance;
|
|
22
|
-
private cameraTarget;
|
|
23
|
-
private lightUniformBuffer;
|
|
24
|
-
private lightData;
|
|
25
|
-
private vertexBuffer;
|
|
26
|
-
private indexBuffer?;
|
|
27
|
-
private resizeObserver;
|
|
28
|
-
private depthTexture;
|
|
29
|
-
private modelPipeline;
|
|
30
|
-
private eyePipeline;
|
|
31
|
-
private hairPipelineOverEyes;
|
|
32
|
-
private hairPipelineOverNonEyes;
|
|
33
|
-
private hairDepthPipeline;
|
|
34
|
-
private outlinePipeline;
|
|
35
|
-
private hairOutlinePipeline;
|
|
36
|
-
private mainBindGroupLayout;
|
|
37
|
-
private outlineBindGroupLayout;
|
|
38
|
-
private jointsBuffer;
|
|
39
|
-
private weightsBuffer;
|
|
40
|
-
private skinMatrixBuffer?;
|
|
41
|
-
private multisampleTexture;
|
|
42
|
-
private readonly sampleCount;
|
|
43
|
-
private renderPassDescriptor;
|
|
44
|
-
private readonly STENCIL_EYE_VALUE;
|
|
45
|
-
private readonly BLOOM_DOWNSCALE_FACTOR;
|
|
46
|
-
private static readonly DEFAULT_BLOOM_THRESHOLD;
|
|
47
|
-
private static readonly DEFAULT_BLOOM_INTENSITY;
|
|
48
|
-
private static readonly DEFAULT_RIM_LIGHT_INTENSITY;
|
|
49
|
-
private static readonly DEFAULT_CAMERA_DISTANCE;
|
|
50
|
-
private static readonly DEFAULT_CAMERA_TARGET;
|
|
51
|
-
private static readonly TRANSPARENCY_EPSILON;
|
|
52
|
-
private static readonly STATS_FPS_UPDATE_INTERVAL_MS;
|
|
53
|
-
private static readonly STATS_FRAME_TIME_ROUNDING;
|
|
54
|
-
private ambientColor;
|
|
55
|
-
private sceneRenderTexture;
|
|
56
|
-
private sceneRenderTextureView;
|
|
57
|
-
private bloomExtractTexture;
|
|
58
|
-
private bloomBlurTexture1;
|
|
59
|
-
private bloomBlurTexture2;
|
|
60
|
-
private bloomExtractPipeline;
|
|
61
|
-
private bloomBlurPipeline;
|
|
62
|
-
private bloomComposePipeline;
|
|
63
|
-
private blurDirectionBuffer;
|
|
64
|
-
private bloomIntensityBuffer;
|
|
65
|
-
private bloomThresholdBuffer;
|
|
66
|
-
private linearSampler;
|
|
67
|
-
private bloomExtractBindGroup?;
|
|
68
|
-
private bloomBlurHBindGroup?;
|
|
69
|
-
private bloomBlurVBindGroup?;
|
|
70
|
-
private bloomComposeBindGroup?;
|
|
71
|
-
private bloomThreshold;
|
|
72
|
-
private bloomIntensity;
|
|
73
|
-
private rimLightIntensity;
|
|
74
|
-
private currentModel;
|
|
75
|
-
private modelDir;
|
|
76
|
-
private physics;
|
|
77
|
-
private materialSampler;
|
|
78
|
-
private textureCache;
|
|
79
|
-
private vertexBufferNeedsUpdate;
|
|
80
|
-
private drawCalls;
|
|
81
|
-
private lastFpsUpdate;
|
|
82
|
-
private framesSinceLastUpdate;
|
|
83
|
-
private lastFrameTime;
|
|
84
|
-
private frameTimeSum;
|
|
85
|
-
private frameTimeCount;
|
|
86
|
-
private stats;
|
|
87
|
-
private animationFrameId;
|
|
88
|
-
private renderLoopCallback;
|
|
89
|
-
private player;
|
|
90
|
-
private hasAnimation;
|
|
91
|
-
constructor(canvas: HTMLCanvasElement, options?: EngineOptions);
|
|
92
|
-
init(): Promise<void>;
|
|
93
|
-
private createRenderPipeline;
|
|
94
|
-
private createPipelines;
|
|
95
|
-
private createBloomPipelines;
|
|
96
|
-
private setupBloom;
|
|
97
|
-
private setupResize;
|
|
98
|
-
private handleResize;
|
|
99
|
-
private setupCamera;
|
|
100
|
-
private setupLighting;
|
|
101
|
-
private setAmbientColor;
|
|
102
|
-
loadAnimation(url: string): Promise<void>;
|
|
103
|
-
playAnimation(): void;
|
|
104
|
-
stopAnimation(): void;
|
|
105
|
-
pauseAnimation(): void;
|
|
106
|
-
seekAnimation(time: number): void;
|
|
107
|
-
getAnimationProgress(): import("./player").AnimationProgress;
|
|
108
|
-
/**
|
|
109
|
-
* Apply animation pose to model
|
|
110
|
-
*/
|
|
111
|
-
private applyPose;
|
|
112
|
-
/**
|
|
113
|
-
* Reset bones and physics to match a given pose
|
|
114
|
-
* @param pose The pose to apply
|
|
115
|
-
* @param resetBonesWithoutKeyframes If true, reset bones that don't have keyframes in the pose to identity
|
|
116
|
-
*/
|
|
117
|
-
private resetBonesAndPhysics;
|
|
118
|
-
getStats(): EngineStats;
|
|
119
|
-
runRenderLoop(callback?: () => void): void;
|
|
120
|
-
stopRenderLoop(): void;
|
|
121
|
-
dispose(): void;
|
|
122
|
-
loadModel(path: string): Promise<void>;
|
|
123
|
-
rotateBones(bones: string[], rotations: Quat[], durationMs?: number): void;
|
|
124
|
-
moveBones(bones: string[], relativeTranslations: Vec3[], durationMs?: number): void;
|
|
125
|
-
setMorphWeight(name: string, weight: number, durationMs?: number): void;
|
|
126
|
-
private updateVertexBuffer;
|
|
127
|
-
private setupModelBuffers;
|
|
128
|
-
private setupMaterials;
|
|
129
|
-
private createMaterialUniformBuffer;
|
|
130
|
-
private createUniformBuffer;
|
|
131
|
-
private createTextureFromPath;
|
|
132
|
-
private renderEyes;
|
|
133
|
-
private renderHair;
|
|
134
|
-
render(): void;
|
|
135
|
-
private applyBloom;
|
|
136
|
-
private updateCameraUniforms;
|
|
137
|
-
private updateRenderTarget;
|
|
138
|
-
private updateModelPose;
|
|
139
|
-
private computeSkinMatrices;
|
|
140
|
-
private drawOutlines;
|
|
141
|
-
private updateStats;
|
|
142
|
-
}
|
|
143
|
-
//# sourceMappingURL=engine_ts.d.ts.map
|
package/dist/engine_ts.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine_ts.d.ts","sourceRoot":"","sources":["../src/engine_ts.ts"],"names":[],"mappings":"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"}
|