以编程方式在 Three.js 中创建骨架
Programatically create skeleton in Three.js
我正在 Three.js 中加载机械模型(例如机械臂)。遗憾的是,我使用的模型没有骨架,但我有关节的位置、轴等。为了使用例如像 Three-IK 这样的反向运动学解算器,我想根据这些参数创建骨架。因为我想使用许多不同的模型,所以我宁愿不要手动创建骨架,而是用代码创建。
我已经尝试了一个多星期,以根据这些反映模型的值创建有效的骨骼结构,但没有成功。例如,如果我使用关节的位置创建骨骼链,我会得到一个非常长的骨架,这与我使用的位置完全不匹配。
let boneParent;
let bonepos = [];
let bones = [];
model.traverse(child => {
switch(child.type) {
case "joint":
let p = new Vector3();
child.getWorldPosition(p);
bonepos.push(p);
let bone = new Bone();
boneParent && boneParent.add(p);
bone.worldToLocal(p.clone());
bone.position.copy(p);
bone.rotation.copy(child.rotation);
bone.scale.copy(child.scale);
boneParent = bone;
bones.push(bone);
break;
}
});
showPoints(scene, bonepos, 0xff0000);
const skeletonHelper = new SkeletonHelper(bones[0]);
skeletonHelper.visible = true;
scene.add(skeletonHelper);
上面的代码生成下面的屏幕截图。红色标记是我从机器人关节得到的位置,蜿蜒到远处的线是 SkeletonHelper 可视化的骨架。
所以我的问题是:我似乎不太了解Three.js中骨骼是如何处理的。我怎样才能创建一个骨架来反映我现有模型的关节位置和方向?
提前致谢!
child.getWorldPosition(p);
恐怕将世界 space 中的位置应用到 Bone.position
代表 local space 中的位置是不正确的。
boneParent = bone;
这一行看起来也有问题。一个骨骼可以有多个子元素。在我看来,您的代码没有考虑这个用例。
经过一番折腾,我找到了解决办法:
let root = new Bone();
let parent = root;
let pos = new Vector3();
for (let joint of robot.arm.movable) {
let link = robot.getLinkForJoint(joint);
link.getWorldPosition(pos);
let bone = new Bone();
parent.add(bone);
parent.lookAt(pos);
parent.updateMatrixWorld(); // crucial for worldToLocal!
bone.position.copy(bone.worldToLocal(pos));
parent = bone;
}
重要的部分是在 lookAt() 之后 调用 updateMatrixWOrld() 以便 bone.worldToLocal()
正常工作。另外 lookAt()
省去了很多矩阵麻烦 :)
我正在 Three.js 中加载机械模型(例如机械臂)。遗憾的是,我使用的模型没有骨架,但我有关节的位置、轴等。为了使用例如像 Three-IK 这样的反向运动学解算器,我想根据这些参数创建骨架。因为我想使用许多不同的模型,所以我宁愿不要手动创建骨架,而是用代码创建。
我已经尝试了一个多星期,以根据这些反映模型的值创建有效的骨骼结构,但没有成功。例如,如果我使用关节的位置创建骨骼链,我会得到一个非常长的骨架,这与我使用的位置完全不匹配。
let boneParent;
let bonepos = [];
let bones = [];
model.traverse(child => {
switch(child.type) {
case "joint":
let p = new Vector3();
child.getWorldPosition(p);
bonepos.push(p);
let bone = new Bone();
boneParent && boneParent.add(p);
bone.worldToLocal(p.clone());
bone.position.copy(p);
bone.rotation.copy(child.rotation);
bone.scale.copy(child.scale);
boneParent = bone;
bones.push(bone);
break;
}
});
showPoints(scene, bonepos, 0xff0000);
const skeletonHelper = new SkeletonHelper(bones[0]);
skeletonHelper.visible = true;
scene.add(skeletonHelper);
上面的代码生成下面的屏幕截图。红色标记是我从机器人关节得到的位置,蜿蜒到远处的线是 SkeletonHelper 可视化的骨架。
所以我的问题是:我似乎不太了解Three.js中骨骼是如何处理的。我怎样才能创建一个骨架来反映我现有模型的关节位置和方向?
提前致谢!
child.getWorldPosition(p);
恐怕将世界 space 中的位置应用到 Bone.position
代表 local space 中的位置是不正确的。
boneParent = bone;
这一行看起来也有问题。一个骨骼可以有多个子元素。在我看来,您的代码没有考虑这个用例。
经过一番折腾,我找到了解决办法:
let root = new Bone();
let parent = root;
let pos = new Vector3();
for (let joint of robot.arm.movable) {
let link = robot.getLinkForJoint(joint);
link.getWorldPosition(pos);
let bone = new Bone();
parent.add(bone);
parent.lookAt(pos);
parent.updateMatrixWorld(); // crucial for worldToLocal!
bone.position.copy(bone.worldToLocal(pos));
parent = bone;
}
重要的部分是在 lookAt() 之后 调用 updateMatrixWOrld() 以便 bone.worldToLocal()
正常工作。另外 lookAt()
省去了很多矩阵麻烦 :)