You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取经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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:43:12