@realsee/dnalogel
Version:
216 lines (215 loc) • 11.3 kB
JavaScript
var B = Object.defineProperty;
var x = (p, e, t) => e in p ? B(p, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : p[e] = t;
var n = (p, e, t) => (x(p, typeof e != "symbol" ? e + "" : e, t), t);
var M = (p, e, t) => new Promise((l, o) => {
var s = (d) => {
try {
y(t.next(d));
} catch (F) {
o(F);
}
}, I = (d) => {
try {
y(t.throw(d));
} catch (F) {
o(F);
}
}, y = (d) => d.done ? l(d.value) : Promise.resolve(d.value).then(s, I);
y((t = t.apply(p, e)).next());
});
import * as i from "three";
import { DigitalStateMachine as L } from "./DigitalStateMachine.js";
import { Trace as S } from "./Trace.js";
const q = 300;
class D {
constructor(e, t) {
n(this, "model");
n(this, "keyframesManager");
n(this, "keyframes");
n(this, "items");
n(this, "effects");
n(this, "digitalPlayground");
n(this, "state");
n(this, "animationFrameId");
n(this, "curveLine");
n(this, "effectsGroup");
n(this, "effectObjects");
n(this, "container");
n(this, "mixer");
n(this, "action");
n(this, "itemMatrixMap");
n(this, "trace");
// 用于跟踪已处理的needRender keyframeIndex
n(this, "processedNeedRenderKeyframeIndices", /* @__PURE__ */ new Set());
// 跟踪已绑定到骨骼的 keyframe 道具(key: itemKey, value: item object)
n(this, "attachedItems", /* @__PURE__ */ new Map());
// 缓存 RightHand 骨骼
n(this, "rightHandBone", null);
this.model = e, this.model.visible = !1, this.model.mixer = null, this.mixer = new i.AnimationMixer(this.model), this.action = null, this.keyframesManager = new L(), this.keyframes = [], this.items = [], this.effects = [], this.digitalPlayground = t, this.state = {
currentTime: 0,
currentAnimation: null,
currentAnimationRepeat: !1,
playing: !1
}, this.animationFrameId = null, this.itemMatrixMap = /* @__PURE__ */ new Map(), this.trace = new S(), this.curveLine = new i.Line(), this.curveLine.material = new i.LineBasicMaterial({ color: 14467195, linewidth: 5 }), this.effectsGroup = new i.Group(), this.effectObjects = /* @__PURE__ */ new Map(), this.container = new i.Group(), this.container.add(this.model), this.container.add(this.curveLine), this.container.add(this.effectsGroup);
}
playAnimation({ animation: e, repeat: t, switchDuration: l }) {
const o = this.action, s = this.mixer.clipAction(e);
s.reset(), t ? (s.setLoop(i.LoopRepeat, 1 / 0), s.clampWhenFinished = !1) : (s.setLoop(i.LoopOnce, 1), s.clampWhenFinished = !0), o && (s.enabled = !0, s.setEffectiveTimeScale(1), s.crossFadeFrom(o, l / 1e3, !0)), s.play(), o && o !== s && setTimeout(() => {
o.stop();
}, l), this.action = s;
}
pauseAnimation() {
this.action && (this.action.paused = !0), this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.state.playing = !1;
}
stopAnimation() {
this.state.currentAnimation = null, this.mixer.stopAllAction(), this.state.playing = !1;
}
continueAnimation() {
this.action && (this.action.paused = !1), this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.keyframes.length > 0 && this.play(), this.state.playing = !0;
}
attachItem() {
}
init() {
this.state.currentTime = 0, this.model.position.copy(new i.Vector3().fromArray(this.keyframes[0].position)), this.model.quaternion.copy(new i.Quaternion().fromArray(this.keyframes[0].quaternion)), this.model.visible = this.keyframes[0].visible;
}
reset() {
this.state.currentTime = 0, this.keyframes && this.keyframes.length > 0 && (this.model.position.copy(new i.Vector3().fromArray(this.keyframes[0].position)), this.model.quaternion.copy(new i.Quaternion().fromArray(this.keyframes[0].quaternion))), this.model.visible = !1, this.container.visible = !1, this.animationFrameId && cancelAnimationFrame(this.animationFrameId), this.stopAnimation(), this.clearTrace(), this.detachAllKeyframeItems(), this.state.playing = !1;
}
play(e) {
return M(this, null, function* () {
this.clearProcessedNeedRenderKeyframeIndices();
const { keyframes: t, items: l, effects: o } = e || {};
return this.keyframes = t || this.keyframes, this.items = l || this.items, this.effects = o || this.effects, this.state.currentAnimation = null, this.state.currentAnimationRepeat = !1, this.state.playing = !0, new Promise((s, I) => {
this.state.currentTime || this.init();
let y = null;
for (let c = 0; c < this.items.length; c++) {
const h = this.digitalPlayground.getDigitalItem(this.items[c].model);
if (h) {
let a = null;
const u = this.model.children[0].children.find((f) => f instanceof i.Bone), g = this.model.children[0].children.find((f) => f instanceof i.SkinnedMesh);
if (!u || !g)
throw new Error("模型骨骼缺失");
if (this.model.children[0].children[2].traverse((f) => {
f instanceof i.Bone && f.name === "RightHand" && (a = f);
}), !a)
throw new Error("没有找到绑定的骨骼");
a.add(h);
const w = new i.Vector3(), r = new i.Quaternion(), m = new i.Vector3();
new i.Matrix4().fromArray(this.items[c].initialMatrix).decompose(w, r, m), h.position.copy(w), h.quaternion.copy(r), h.scale.copy(m), h.updateMatrixWorld(!0);
}
}
const d = /* @__PURE__ */ new Map(), F = new i.TextureLoader();
for (let c = 0; c < this.effects.length; c++) {
const h = this.effects[c];
if (h.type === "frameSequence") {
const a = h.keyframes;
for (let u = 0; u < a.length; u++)
F.load(a[u].image, (g) => {
g.name = a[u].image, d.set(a[u].image, g);
});
}
}
const v = (c) => {
var g, w;
y === null && (y = c);
const h = c - y;
y = c, this.state.currentTime += h;
const a = this.keyframesManager.getStateByTime(this.state.currentTime, this.keyframes, "model");
this.trace.addPoint(a.translation);
const u = new i.BufferGeometry().setFromPoints(this.trace.tracePoints);
if (this.curveLine.geometry = u, this.model.position.copy(a.translation), this.model.quaternion.copy(a.quaternion), this.model.scale.copy(a.scale), this.model.visible = a.visible, a.isFinal) {
this.model.visible = !1, this.container.visible = !1, this.stopAnimation(), this.model.needsRender = !0, s(!0), this.animationFrameId !== null && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null);
return;
} else if (a.animation) {
const r = this.digitalPlayground.getAnimation(a.animation.url), m = a.animation.needRender, A = a.animation.repeat !== this.state.currentAnimationRepeat;
(r !== this.state.currentAnimation || A || m && !this.hasProcessedNeedRenderForTimestamp(a.keyframeIndex)) && (m && r === this.state.currentAnimation && this.markNeedRenderProcessedForTimestamp(a.keyframeIndex), this.state.currentAnimation = r, this.state.currentAnimationRepeat = a.animation.repeat, this.playAnimation({
animation: r,
repeat: a.animation.repeat,
switchDuration: (g = a.animation.switchDuration) != null ? g : q
})), this.mixer.update(h / 1e3), a.animation.isOver === !0 && (this.action.paused = !0, this.action.time = this.state.currentAnimation.duration, this.mixer.update(0));
}
this.updateKeyframeItems((w = a.animation) == null ? void 0 : w.item);
for (let r = 0; r < this.items.length; r++) {
const m = this.digitalPlayground.getDigitalItem(this.items[r].model);
m && (this.keyframesManager.getStateByTime(this.state.currentTime, this.items[r].keyframes, "item").visible === !0 ? m.visible = !0 : m.visible = !1);
}
for (let r = 0; r < this.effects.length; r++) {
const m = this.effects[r];
if (m.type === "frameSequence") {
const A = m.type + r;
if (!this.effectObjects.has(A)) {
const R = new i.PlaneGeometry(1, 1), b = new i.MeshBasicMaterial({
transparent: !0
}), k = new i.Mesh(R, b);
k.rotateX(-Math.PI / 2), k.position.copy(new i.Vector3().fromArray(m.position)), this.effectObjects.set(A, k), this.effectsGroup.add(k);
}
const f = this.effectObjects.get(A), T = this.keyframesManager.getStateByTime(this.state.currentTime, this.effects[r].keyframes, "effect"), P = d.get(T.image);
f.material.map = P, f.visible = T.visible;
}
}
this.model.needsRender = !0, this.animationFrameId = requestAnimationFrame(v);
};
this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.animationFrameId = requestAnimationFrame(v);
});
});
}
// 用于分段时 更新轨迹
traceUpDate() {
this.trace.clear();
for (let e = 0; e <= this.state.currentTime; e += 100) {
const t = this.keyframesManager.getStateByTime(e, this.keyframes, "model");
this.trace.addPoint(t.translation);
const l = new i.BufferGeometry().setFromPoints(this.trace.tracePoints);
this.curveLine.geometry = l;
}
}
// 清楚轨迹
clearTrace() {
this.trace.clear();
const e = new i.BufferGeometry().setFromPoints(this.trace.tracePoints);
this.curveLine.geometry = e;
}
// 清理已处理的keyframeIndex记录(可选,在适当的时候调用)
clearProcessedNeedRenderKeyframeIndices() {
this.processedNeedRenderKeyframeIndices.clear();
}
// 检查指定keyframeIndex的needRender是否已经处理过
hasProcessedNeedRenderForTimestamp(e) {
return this.processedNeedRenderKeyframeIndices.has(e);
}
// 标记指定keyframeIndex的needRender已经处理过
markNeedRenderProcessedForTimestamp(e) {
this.processedNeedRenderKeyframeIndices.add(e);
}
// 获取并缓存 RightHand 骨骼
getRightHandBone() {
var e;
return this.rightHandBone ? this.rightHandBone : ((e = this.model.children[0].children.find((t) => t instanceof i.Bone)) == null || e.traverse((t) => {
t instanceof i.Bone && t.name === "RightHand" && (this.rightHandBone = t);
}), this.rightHandBone);
}
// 根据当前帧的 items 动态绑定/解绑道具
updateKeyframeItems(e) {
var o;
const t = (e == null ? void 0 : e.url) || null;
for (const [s, I] of this.attachedItems)
t !== s && ((o = I.parent) == null || o.remove(I), this.attachedItems.delete(s));
if (!t)
return;
const l = this.getRightHandBone();
if (l && !this.attachedItems.has(t)) {
const s = this.digitalPlayground.getDigitalItem(t);
s && (l.add(s), this.attachedItems.set(t, s));
}
}
// 解绑所有 keyframe 道具
detachAllKeyframeItems() {
var e;
for (const [, t] of this.attachedItems)
(e = t.parent) == null || e.remove(t);
this.attachedItems.clear();
}
}
export {
D as DigitalHuman
};