ThreeJS技术问询:如何在绑定骨骼的网格(Rigged Mesh)上标记点位?
基于ThreeJS实现骨骼形变网格的标记点同步方案
最优方案:复用骨骼权重与矩阵实时计算位置
这是最直接高效的实现方式,无需额外骨骼或纹理,核心逻辑复用ThreeJS自身的蒙皮计算机制:
- 点击拾取关键数据:用
Raycaster检测点击,获取目标网格、点击交点,以及交点对应的网格顶点索引(或直接取交点的局部空间坐标)。 - 提取顶点绑定信息:从网格的
skinIndex和skinWeight属性中,拿到该顶点绑定的骨骼索引及对应权重值(ThreeJS默认每个顶点最多绑定4根骨骼)。 - 实时更新标记点坐标:每帧动画更新后,遍历顶点绑定的骨骼,用骨骼的
worldMatrix变换顶点局部位置,再按权重加权求和,将结果赋值给标记点的position。
对你现有思路的分析
- 新增骨骼方案:可行但冗余。可以通过权重占比最高的骨骼作为父级,但需要手动创建骨骼、设置父子关系、分配权重,步骤繁琐,远不如直接计算位置高效。
- 绑定特定顶点:这正是最优方案的核心——不需要把顶点“赋值给变量”,而是直接利用顶点自带的骨骼绑定数据,复现蒙皮形变后的位置,完全符合需求。
- 纹理实现方案:完全没必要,会无端增加渲染开销,不符合你的轻量化需求。
关键代码示例
// 假设已通过Raycaster获取:目标网格skinnedMesh、点击顶点索引vertexIndex、标记点marker const geometry = skinnedMesh.geometry; const skinIndex = geometry.attributes.skinIndex; const skinWeight = geometry.attributes.skinWeight; const skeleton = skinnedMesh.skeleton; // 获取顶点的局部初始位置 const localVertexPos = new THREE.Vector3(); localVertexPos.fromBufferAttribute(geometry.attributes.position, vertexIndex); // 每帧更新标记点位置的函数 function updateMarker() { const finalPos = new THREE.Vector3(0, 0, 0); // 遍历顶点绑定的4根骨骼(ThreeJS默认上限) for (let i = 0; i < 4; i++) { const boneIdx = skinIndex.getX(vertexIndex, i); const weight = skinWeight.getX(vertexIndex, i); if (weight === 0) continue; const bone = skeleton.bones[boneIdx]; const transformedPos = localVertexPos.clone().applyMatrix4(bone.matrixWorld); finalPos.add(transformedPos.multiplyScalar(weight)); } marker.position.copy(finalPos); } // 在动画循环中调用更新函数 function animate() { requestAnimationFrame(animate); updateMarker(); renderer.render(scene, camera); }
内容的提问来源于stack exchange,提问作者Anson Kao
相关产品推荐
相关产品推荐

