如何获取经Skeleton3D骨骼变形后的MeshInstance3D的AABB?
获取骨骼变形后MeshInstance3D的AABB
由于MeshInstance3D.get_aabb()返回的是原始网格的包围盒,不会考虑骨骼蒙皮后的顶点位移,要获取变形后的包围盒,需要手动计算每个顶点经过骨骼变换后的最终位置,再生成对应的AABB。
方法:手动计算蒙皮顶点的全局位置
Godot 3.x 实现代码
func get_skinned_aabb(mesh_instance: MeshInstance3D) -> AABB: var skeleton = mesh_instance.get_skeleton() if not skeleton: return mesh_instance.get_aabb() var mesh = mesh_instance.mesh var surface_count = mesh.get_surface_count() var aabb = AABB() for surface_idx in range(surface_count): var vertex_array = mesh.get_surface_arrays(surface_idx) var vertices = vertex_array[Mesh.ARRAY_VERTEX] var bone_weights = vertex_array.get(Mesh.ARRAY_BONE_WEIGHTS, null) var bone_indices = vertex_array.get(Mesh.ARRAY_BONE_INDICES, null) if not bone_weights or not bone_indices: # 无蒙皮数据的面,直接用原始顶点计算 for vertex in vertices: var global_vertex = mesh_instance.global_transform * vertex aabb.expand(global_vertex) continue # 处理蒙皮顶点:按骨骼权重计算最终位置 for i in range(vertices.size()): var vertex = vertices[i] var weights = bone_weights[i] var indices = bone_indices[i] var final_pos = Vector3.ZERO # 遍历顶点绑定的4个骨骼(Godot蒙皮最多支持4骨骼权重) for j in range(4): var bone_idx = indices[j] var weight = weights[j] if weight == 0: continue var bone_pose = skeleton.get_bone_global_pose(bone_idx) final_pos += (bone_pose.basis * vertex + bone_pose.origin) * weight # 转换到世界空间并扩展AABB final_pos = mesh_instance.global_transform * final_pos aabb.expand(final_pos) return aabb
Godot 4.x 实现代码
Godot 4中API有部分调整,比如骨骼节点获取、全局姿态方法名变更:
func get_skinned_aabb(mesh_instance: MeshInstance3D) -> AABB: var skeleton = mesh_instance.skeleton_node if not skeleton: return mesh_instance.get_aabb() var mesh = mesh_instance.mesh var surface_count = mesh.get_surface_count() var aabb = AABB() for surface_idx in range(surface_count): var vertex_buffer = mesh.surface_get_arrays(surface_idx) var vertices = vertex_buffer[Mesh.ARRAY_VERTEX] var bone_weights = vertex_buffer.get(Mesh.ARRAY_BONE_WEIGHTS, null) var bone_indices = vertex_buffer.get(Mesh.ARRAY_BONE_INDICES, null) if not bone_weights or not bone_indices: for vertex in vertices: var global_vertex = mesh_instance.global_transform * vertex aabb.expand(global_vertex) continue for i in range(vertices.size()): var vertex = vertices[i] var weights = bone_weights[i] var indices = bone_indices[i] var final_pos = Vector3.ZERO for j in range(4): var bone_idx = indices[j] var weight = weights[j] if weight == 0: continue var bone_transform = skeleton.get_bone_global_transform(bone_idx) final_pos += (bone_transform.basis * vertex + bone_transform.origin) * weight final_pos = mesh_instance.global_transform * final_pos aabb.expand(final_pos) return aabb
注意事项
- 该方法需要遍历网格所有顶点,复杂网格频繁调用会有性能开销,建议在骨骼变换完成后缓存结果,避免重复计算。
- 如果网格包含无蒙皮的面(比如静态装饰部分),代码会自动回退到原始顶点计算,保证结果准确。
内容的提问来源于stack exchange,提问作者Manas R. Makde
相关产品推荐
相关产品推荐

