@realsee/dnalogel
Version:
372 lines (371 loc) • 15.2 kB
JavaScript
import * as _ from "three";
function J(t) {
const m = [t[12], t[13], t[14]], r = t[0], o = t[4], l = t[8], p = t[1], x = t[5], h = t[9], e = t[2], u = t[6], z = t[10], w = Math.sqrt(r * r + p * p + e * e), q = Math.sqrt(o * o + x * x + u * u), F = Math.sqrt(l * l + h * h + z * z), E = [w, q, F], N = [r / w, o / q, l / F, p / w, x / q, h / F, e / w, u / q, z / F], S = it(N);
return { position: m, quaternion: S, scale: E };
}
function it(t) {
const m = t[0] + t[4] + t[8];
let r, o = [0, 0, 0, 0];
return m > 0 ? (r = Math.sqrt(m + 1) * 2, o[3] = 0.25 * r, o[0] = (t[7] - t[5]) / r, o[1] = (t[2] - t[6]) / r, o[2] = (t[3] - t[1]) / r) : t[0] > t[4] && t[0] > t[8] ? (r = Math.sqrt(1 + t[0] - t[4] - t[8]) * 2, o[3] = (t[7] - t[5]) / r, o[0] = 0.25 * r, o[1] = (t[1] + t[3]) / r, o[2] = (t[2] + t[6]) / r) : t[4] > t[8] ? (r = Math.sqrt(1 + t[4] - t[0] - t[8]) * 2, o[3] = (t[2] - t[6]) / r, o[0] = (t[1] + t[3]) / r, o[1] = 0.25 * r, o[2] = (t[5] + t[7]) / r) : (r = Math.sqrt(1 + t[8] - t[0] - t[4]) * 2, o[3] = (t[3] - t[1]) / r, o[0] = (t[2] + t[6]) / r, o[1] = (t[5] + t[7]) / r, o[2] = 0.25 * r), o;
}
function ot({ x: t, y: m, z: r, order: o = "XYZ" }) {
const l = Math.cos(t / 2), p = Math.cos(m / 2), x = Math.cos(r / 2), h = Math.sin(t / 2), e = Math.sin(m / 2), u = Math.sin(r / 2);
let z, w, q, F;
switch (o) {
case "XYZ":
z = h * p * x + l * e * u, w = l * e * x - h * p * u, q = l * p * u + h * e * x, F = l * p * x - h * e * u;
break;
default:
z = h * p * x + l * e * u, w = l * e * x - h * p * u, q = l * p * u + h * e * x, F = l * p * x - h * e * u;
}
return [z, w, q, F];
}
function W(t) {
if (typeof t == "string" && !isNaN(Number(t)))
return [0, -(Number(t) * Math.PI) / 180, 0];
if (Array.isArray(t) && t.length === 3)
return [t[0], -t[1], t[2]];
}
function D(t, m) {
if (!m)
return t;
const r = ot({ x: m[0], y: m[1], z: m[2] }), [o, l, p, x] = r, [h, e, u, z] = t;
return [
x * h + o * z + l * u - p * e,
x * e - o * u + l * z + p * h,
x * u + o * e - l * h + p * z,
x * z - o * h - l * e - p * u
];
}
function et(t, m) {
const r = new _.Vector3(m.x - t.x, m.y - t.y, m.z - t.z).normalize(), o = new _.Vector3(0, 0, 1), l = new _.Quaternion();
return l.setFromUnitVectors(o, r), [l.x, l.y, l.z, l.w];
}
function st(t, m = 0, r = 300) {
var H, L, O, V;
if (!((H = t.track) != null && H.path) || t.track.path.length === 0) {
const i = J(t.matrix), n = [
{
visible: !0,
timeStamp: 0 + m,
position: i.position,
quaternion: i.quaternion,
scale: i.scale
}
];
return {
name: t.name || "默认角色",
type: "model",
model: t.modelUrl,
keyframes: n
};
}
const o = J(t.matrix);
let l = o.quaternion.slice();
const p = t.track.points.find(
(i) => Math.abs(i.point.x - o.position[0]) < 1e-3 && Math.abs(i.point.y - o.position[1]) < 1e-3 && Math.abs(i.point.z - o.position[2]) < 1e-3
);
let x = t.animationUrl, h = t.repeat === "loop";
const e = [];
if (p) {
let i = 0;
for (const n of p.actions)
if (n.duration > 0) {
const a = typeof n.animationUrl == "string" && n.animationUrl && n.animationUrl.trim() && n.animationUrl !== "none" && n.animationUrl !== "x_turn";
u({
visible: !0,
timeStamp: i,
position: o.position,
quaternion: l,
scale: o.scale,
animation: {
url: a ? n.animationUrl : t.animationUrl,
repeat: !a || (n == null ? void 0 : n.repeat),
needRender: a,
item: (L = n.subAction) != null && L.url ? n.subAction : void 0
}
}), i += n.duration * 1e3;
}
if (!p.actions.some((n) => n.duration > 0)) {
const n = p.actions.find((a) => a.duration > 0 && a.animationUrl !== "none");
n ? (x = n.animationUrl, h = !1, console.log(`初始位置与action point重合,使用动作动画: ${x}`)) : console.log("初始位置与action point重合,但没有有效动作,使用默认动画");
}
} else
console.log("初始位置独立,使用默认移动动画");
function u(i) {
var a, y, f;
i.timeStamp += m, i.animation.url === "none" && delete i.animation;
const n = e.findIndex(($) => $.timeStamp === i.timeStamp);
n !== -1 ? ((a = e[n].animation) == null ? void 0 : a.url) !== ((y = i.animation) == null ? void 0 : y.url) && i.animation && ((f = i.animation) == null ? void 0 : f.url) !== t.animationUrl && (e[n] = i) : e.push(i);
}
u({
visible: !0,
timeStamp: 0,
position: o.position,
quaternion: l,
scale: o.scale,
animation: {
url: x,
repeat: h
}
});
let z = 0;
if (p) {
let i = 0;
for (const n of p.actions)
if (n.duration > 0 || n.animationUrl === "x_turn") {
if (n.animationUrl === "x_turn") {
n.duration = 1;
const a = W(n.rotation);
a && (l = D(l, a));
}
i += n.duration * 1e3, z += n.duration * 1e3, u({
visible: !0,
timeStamp: i,
position: o.position,
quaternion: l,
scale: o.scale,
animation: {
url: t.animationUrl,
// 恢复默认移动动画
repeat: t.repeat === "loop"
}
});
}
console.log(`初始action point处理完成,总延迟: ${z}ms`);
}
function w(i, n) {
return Math.sqrt(Math.pow(n.x - i.x, 2) + Math.pow(n.y - i.y, 2) + Math.pow(n.z - i.z, 2));
}
let q = 0;
const F = [];
for (let i = 0; i < t.track.path.length - 1; i++) {
const n = w(t.track.path[i], t.track.path[i + 1]);
F.push(n), q += n;
}
const E = q / t.track.duration;
console.log(`路径分析:
- 总距离: ${q.toFixed(2)}
- 移动时间: ${t.track.duration}s
- 移动速度: ${E.toFixed(2)} 单位/秒
- 路径段距离: [${F.map((i) => i.toFixed(2)).join(", ")}]`);
const N = /* @__PURE__ */ new Map();
for (const i of t.track.points) {
const n = `${i.point.x.toFixed(3)}_${i.point.y.toFixed(3)}_${i.point.z.toFixed(3)}`;
let a = 1 / 0, y = 0;
for (let f = 0; f < t.track.path.length - 1; f++) {
const $ = k(i.point, t.track.path[f], t.track.path[f + 1]);
$ < a && (a = $, y = f);
}
N.set(n, y);
}
let S = z, j = 0;
const C = /* @__PURE__ */ new Set();
for (let i = 0; i < t.track.path.length - 1; i++) {
const n = t.track.path[i], a = t.track.path[i + 1], y = F[i], f = j / q * t.track.duration * 1e3;
j += y;
const $ = j / q * t.track.duration * 1e3, U = f + S, g = $ + S;
console.log(
`路径段${i}: 距离${y.toFixed(2)}, 基础时间${f.toFixed(0)}-${$.toFixed(
0
)}ms, 实际时间${U.toFixed(0)}-${g.toFixed(0)}ms`
), u({
visible: !0,
timeStamp: U,
position: [n.x, n.y, n.z],
quaternion: l,
scale: o.scale,
animation: {
url: t.animationUrl,
// 默认移动动画
repeat: t.repeat === "loop"
}
});
for (const s of t.track.points) {
if (p && s === p && i === 0) {
console.log("跳过初始action point,已在初始关键帧中处理");
continue;
}
const T = `${s.point.x.toFixed(3)}_${s.point.y.toFixed(3)}_${s.point.z.toFixed(3)}`;
if (C.has(T)) {
console.log(`跳过已处理的点位: [${s.point.x.toFixed(2)}, ${s.point.y.toFixed(2)}, ${s.point.z.toFixed(2)}]`);
continue;
}
if (N.get(T) === i) {
const d = tt(s.point, n, a), M = j - y + y * d, R = M / q * t.track.duration * 1e3 + S;
console.log(
`Action点: 位置[${s.point.x.toFixed(2)}, ${s.point.y.toFixed(2)}, ${s.point.z.toFixed(
2
)}], 距离${M.toFixed(2)}, 到达时间${R.toFixed(0)}ms`
);
let I = t.animationUrl;
const b = s.actions.find((c) => c.duration > 0 && c.animationUrl !== "none"), A = b == null ? void 0 : b.subAction;
b ? (I = b.animationUrl, b.duration > 2, console.log(`到达动作点,使用该点的动画: ${I}`)) : console.log("动作点没有有效动作,使用默认移动动画"), u({
visible: !0,
timeStamp: R,
position: [s.point.x, s.point.y, s.point.z],
quaternion: l,
scale: o.scale,
animation: {
url: I,
item: A != null && A.url ? A : void 0,
repeat: b == null ? void 0 : b.repeat,
duration: b == null ? void 0 : b.duration
}
});
let P = R, K = 0;
for (const c of s.actions)
if (c.duration > 0 || c.animationUrl === "x_turn") {
if (c.animationUrl === "x_turn") {
c.duration = 1;
const G = W(c.rotation);
G && (l = D(l, G));
}
const B = c.animationUrl !== "none" && c.animationUrl !== "x_turn";
u({
visible: !0,
timeStamp: P,
position: [s.point.x, s.point.y, s.point.z],
quaternion: l,
scale: o.scale,
animation: {
url: B ? c.animationUrl : t.animationUrl,
repeat: !B || (c == null ? void 0 : c.repeat),
needRender: B,
item: (O = c.subAction) != null && O.url ? c.subAction : void 0,
duration: c == null ? void 0 : c.duration
}
}), P += c.duration * 1e3, K += c.duration * 1e3, u({
visible: !0,
timeStamp: P,
position: [s.point.x, s.point.y, s.point.z],
quaternion: l,
scale: o.scale,
animation: {
url: t.animationUrl,
repeat: t.repeat === "loop",
item: (V = c.subAction) != null && V.url ? c.subAction : void 0
}
});
}
S += K, C.add(T), console.log(
`点位处理完成,已标记为已处理: [${s.point.x.toFixed(2)}, ${s.point.y.toFixed(2)}, ${s.point.z.toFixed(
2
)}]`
);
}
}
if (i === t.track.path.length - 2) {
const s = $ + S;
u({
visible: !0,
timeStamp: s,
position: [a.x, a.y, a.z],
quaternion: l,
scale: o.scale,
animation: {
url: t.animationUrl,
repeat: t.repeat === "loop"
}
});
}
}
function k(i, n, a) {
const y = i.x - n.x, f = i.y - n.y, $ = i.z - n.z, U = a.x - n.x, g = a.y - n.y, s = a.z - n.z, T = y * U + f * g + $ * s, d = U * U + g * g + s * s;
if (d === 0)
return Math.sqrt(y * y + f * f + $ * $);
let M = T / d;
M < 0 ? M = 0 : M > 1 && (M = 1);
const v = n.x + M * U, R = n.y + M * g, I = n.z + M * s, b = i.x - v, A = i.y - R, P = i.z - I;
return Math.sqrt(b * b + A * A + P * P);
}
function tt(i, n, a) {
const y = a.x - n.x, f = a.y - n.y, $ = a.z - n.z, U = y * y + f * f + $ * $;
if (U === 0)
return 0;
const g = i.x - n.x, s = i.y - n.y, T = i.z - n.z, d = g * y + s * f + T * $;
return Math.max(0, Math.min(1, d / U));
}
e.sort((i, n) => i.timeStamp - n.timeStamp);
const X = [];
for (let i = 0; i < e.length - 1; i++) {
const n = e[i], a = e[i + 1];
if (Math.abs(n.position[0] - a.position[0]) + Math.abs(n.position[1] - a.position[1]) + Math.abs(n.position[2] - a.position[2]) > 1e-3) {
console.log(`找到连续的不同位置关键帧: ${i} -> ${i + 1}`);
const f = E * (r / 1e3), $ = new _.Vector3(n.position[0], n.position[1], n.position[2]), U = new _.Vector3(
a.position[0] - n.position[0],
a.position[1] - n.position[1],
a.position[2] - n.position[2]
).normalize(), g = $.clone().add(U.multiplyScalar(f));
let s = et(
{ x: n.position[0], y: n.position[1], z: n.position[2] },
{ x: a.position[0], y: a.position[1], z: a.position[2] }
);
const T = {
visible: !0,
timeStamp: n.timeStamp + r,
// 加上旋转走路的时间
position: [g.x, g.y, g.z],
// 使用计算后的位置
quaternion: s,
// 使用路径方向的quaternion
scale: o.scale
};
t.animationUrl !== "none" && (T.animation = {
url: t.animationUrl,
repeat: t.repeat === "loop"
}), X.push(T);
for (let d = 0; d < e.length; d++)
if (e[d].timeStamp > n.timeStamp + r)
if (Math.abs(e[d].position[0] - a.position[0]) < 1e-3 && Math.abs(e[d].position[1] - a.position[1]) < 1e-3 && Math.abs(e[d].position[2] - a.position[2]) < 1e-3)
if (d < e.length - 1) {
const M = e[d].quaternion, v = e[d + 1].quaternion;
if (Math.abs(M[0] - v[0]) + Math.abs(M[1] - v[1]) + Math.abs(M[2] - v[2]) + Math.abs(M[3] - v[3]) < 1e-3)
e[d].quaternion = s.slice(), console.log(`关键帧${d}没有旋转,设置为路径方向`);
else {
const I = new _.Quaternion(), b = new _.Quaternion(
M[0],
M[1],
M[2],
M[3]
), A = new _.Quaternion(v[0], v[1], v[2], v[3]), P = b.clone();
P.conjugate(), I.copy(A).multiply(P), e[d].quaternion = s.slice();
const c = new _.Quaternion(
s[0],
s[1],
s[2],
s[3]
).clone().multiply(I);
e[d + 1].quaternion = [c.x, c.y, c.z, c.w], s = [c.x, c.y, c.z, c.w], console.log(`关键帧${d}发生旋转,当前帧设置为路径方向,下一帧设置为路径方向+旋转角度,更新路径方向`), d++;
}
} else
e[d].quaternion = s.slice(), console.log(`最后一个关键帧${d}设置为路径方向`);
else
break;
console.log(`添加旋转动作帧,时间戳: ${n.timeStamp + r}ms`);
}
}
e.push(...X), e.sort((i, n) => i.timeStamp - n.timeStamp);
const Y = t.track.duration * 1e3, Z = Y + S, Q = e[e.length - 1], nt = e.filter(
(i) => i.timeStamp === 0 && Math.abs(i.position[0] - o.position[0]) < 1e-3 && Math.abs(i.position[1] - o.position[1]) < 1e-3 && Math.abs(i.position[2] - o.position[2]) < 1e-3
);
return console.log(`动画转换完成:
- 路径总距离: ${q.toFixed(2)} 单位
- 基础移动时间: ${Y}ms (${t.track.duration}s)
- 移动速度: ${E.toFixed(2)} 单位/秒
- 动作延迟时间: ${S}ms (${(S / 1e3).toFixed(2)}s)
- 计算总时间: ${Z}ms (${(Z / 1e3).toFixed(2)}s)
- 实际最后时间戳: ${Q == null ? void 0 : Q.timeStamp}ms (${((Q == null ? void 0 : Q.timeStamp) / 1e3).toFixed(2)}s)
- 关键帧数量: ${e.length}
- 初始位置关键帧数量: ${nt.length}
- 速度一致性: ${(((Q == null ? void 0 : Q.timeStamp) - S) / 1e3 / t.track.duration * 100).toFixed(1)}% (100%为完全一致)`), {
id: t.id,
name: t.name || "默认角色",
type: "model",
model: t.modelUrl,
keyframes: e
};
}
export {
st as convertMockToPlayer
};