是否可以动态创建3d模型与骨骼动画,骨骼的bindpose的算法问题

我这边的模型并不是标准的3d模型(不是fbx,gltf等),只能通过代码方式创建模型、蒙皮骨骼动画,但是卡在骨骼动画环节。
发现骨骼动画并不是直接通过clip.tracks实现的,是通过引擎私有的_exoticAnimation: ExoticAnimation 的动画对象实现。
这块我直接通过 js.getClassByName(“cc.animation.ExoticAnimation”); 动态创建来实现没有什么问题。
现在碰到新的问题,骨骼的bindpose的算法,这个里tpos的矩阵是怎么算出来的。
现在有骨骼节点树结构(嵌套关系)。如何计算每一个节点的bindpose矩阵?
是每一个骨骼的本地矩阵向上查找直到根(模型的根)之间的本地矩阵相乘。再取invert吗?

let knightModel = this.knight_model.getComponentInChildren(SkinnedMeshRenderer);
let bone1:Node = this.knight_model.children[0];
let bindpose1:Mat4 = this.getBoneMatrix(bone1, knightModel.skinningRoot)
getBoneMatrix(bone: Node, skinningRoot: Node) {
    let matrix = math.mat4();
    let temp = math.mat4();
    while (bone !== skinningRoot) {
        math.Mat4.fromRTS(temp, bone.rotation, bone.position, bone.scale);
        math.Mat4.multiply(matrix, temp, matrix);
        bone = bone.parent!;
    }
    return matrix;
}

这个tpose就是将你网格变换到骨骼空间的矩阵

你不用研究那个exoticAnimation,那个是内部使用的,你就通过tracks去做trs动画好了,有什么问题你就在这里问

先设置track path,就是你要做哪个骨骼的动画,你需要指定一个骨骼的路径,和“rotation”、“position”、“scake”中的一个。这部分你可以参考下动画文档。

然后设置下track的曲线。

最后,你如果“骨架资源”也是自己生成的,那就填充一下每个骨骼的tpose,这里也要路径,这个路径是相对于哪的呢?就是skinned mesh renderer的skinng root

感谢您的回复,上面计算tpose的矩阵是当前骨骼节点到skinngroot之间的本地矩阵相乘,这个经验证是正确的(通过创建ExoticAnimation方式就可以正确动画显示)。
之前测试过,骨骼动画并不能通过clip.tracks来更新网格,
先设置anim.useBakedAnimation = false, 然后创建动画剪辑,创建动画帧代码片段如下,但并没有效果,模型处于混乱状态(无规则扭动).
粗略看了下引擎代码(并不确定),貌似骨骼动画并不是直接并不是直接通过读取clip.tracks来设置蒙皮的cc_joints数据,只能通过ExoticAnimation来创建数据直接提交gpu,代码中设置骨骼节点RTS并不会直接影响模型动画显示,就可以得出这个结论,不知道后续版本是否会支持。暂时先通过创建ExoticAnimation解决问题,只是当骨骼数量超过30时,显示出现问题,需要对模型进行拆分成多不超过30骨骼之后,暂时解决了,后续如果有其它办法再替换。
let clip = new AnimationClip(clipData.name);

clipData.tracks.forEach((trackData) => {
let bone = info.index[trackData.bone];
let trackPath = bone.path;
let path = new animation.TrackPath().toHierarchy(trackPath);
switch (trackData.type) {
case “scale”: {
let track = new animation.VectorTrack();
track.componentsCount = 3;
track.path = path.toProperty(‘scale’);
let ch = track.channels();
trackData.frames.forEach((frame) => {
let t = frame.id * rate;
ch[0].curve.addKeyFrame(t, frame.val[0]);
ch[1].curve.addKeyFrame(t, frame.val[1]);
ch[2].curve.addKeyFrame(t, frame.val[2]);
});
clip.addTrack(track);
break;
}
case “position”: {
let track = new animation.VectorTrack();
track.componentsCount = 3;
track.path = path.toProperty(‘position’);
let ch = track.channels();
trackData.frames.forEach((frame) => {
let t = frame.id * rate;
ch[0].curve.addKeyFrame(t, frame.val[0]);
ch[1].curve.addKeyFrame(t, frame.val[1]);
ch[2].curve.addKeyFrame(t, frame.val[2]);
});
clip.addTrack(track);
break;
}
case “rotation”: {
let track = new animation.QuatTrack();
track.path = path.toProperty(‘rotation’);
let ch = track.channel;
trackData.frames.forEach((frame) => {
let t = frame.id * rate;
ch.curve.addKeyFrame(t, { value: { x: frame.val[0], y: frame.val[1], z: frame.val[2], w: frame.val[3] } });
});
clip.addTrack(track);
break;
}
default:
console.warn("[track]unknowType:" + trackData.type);
break;
}
});

anim.clips = clips;

类似threejs这样,直接代码修改骨骼节点RTS,改变骨骼蒙皮。当前引擎应该无法实现,而通过动画对象clip.tracks修改骨骼节点就同样无法实现了。。不知道是不是我的方式不对。 Three.js中文文档

另外,引擎里导入fbx,会自动根据骨骼数量,当超过30时,自动进行切分多个subMesh,这块的代码并没有找到,不知道是否有地方可以参考一下。

切分模型之后,之后可以正常显示动画了。问题解决

该主题在最后一个回复创建后14天后自动关闭。不再允许新的回复。