Weisl / Collider-Tools

This addon allows you to create collider meshes more easily. It provides different operators to generate primitve colliders or convex mesh colliders out of a selection.
GNU General Public License v3.0
29 stars 6 forks source link

Generate Capsule collider #387

Closed Weisl closed 1 year ago

Weisl commented 1 year ago

ChatGPT code:

bl_info = {
    "name": "Bounding Capsule",
    "author": "Your Name",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Object",
    "description": "Generate a bounding capsule for a selected object",
    "category": "Object"
}

import bpy
import math

# Function to calculate the distance between two points
def distance(p1, p2):
    return math.sqrt(sum((p1[i] - p2[i]) ** 2 for i in range(len(p1))))

# Function to calculate the distance between a point and a line segment
def point_line_segment_distance(p, p1, p2):
    v = [p2[i] - p1[i] for i in range(len(p1))]
    w = [p[i] - p1[i] for i in range(len(p1))]

    t = max(0, min(1, sum(w[i] * v[i] for i in range(len(v))) / sum(v[i] * v[i] for i in range(len(v)))))
    closest_point = [p1[i] + t * v[i] for i in range(len(p1))]
    return distance(p, closest_point)

# Function to calculate the radius and height of the bounding capsule
def calculate_radius_height(points):
    max_distance = 0
    for i in range(len(points)):
        for j in range(i + 1, len(points)):
            d = distance(points[i], points[j])
            if d > max_distance:
                max_distance = d

    radius = max_distance / 2
    height = max_distance - radius
    return radius, height

# Operator to generate the bounding capsule
class OBJECT_OT_generate_bounding_capsule(bpy.types.Operator):
    bl_idname = "object.generate_bounding_capsule"
    bl_label = "Generate Bounding Capsule"
    bl_description = "Generate a bounding capsule for the selected object"

    def execute(self, context):
        # Check if there is an active object and it's selected
        if bpy.context.active_object and bpy.context.active_object.select_get():
            selected_object = bpy.context.active_object

            # Get the object's vertices
            vertices = [selected_object.matrix_world @ v.co for v in selected_object.data.vertices]
            points = [list(vertex) for vertex in vertices]

            # Calculate the radius and height of the bounding capsule
            radius, height = calculate_radius_height(points)

            # Create a new mesh object for the cylinder
            bpy.ops.mesh.primitive_cylinder_add(radius=radius, depth=height)
            cylinder = bpy.context.object

            # Create a new mesh object for the top hemisphere
            bpy.ops.mesh.primitive_uv_sphere_add(radius=radius, location=(0, 0, height/2))
            top_hemisphere = bpy.context.object

            # Create a new mesh object for the bottom hemisphere
            bpy.ops.mesh.primitive_uv_sphere_add(radius=radius, location=(0, 0, -height/2))
            bottom_hemisphere = bpy.context.object

            # Combine the objects into a single object
            bpy.ops.object.select_all(action='DESELECT')
            cylinder.select_set(True)
            top_hemisphere.select_set(True)
            bottom_hemisphere.select_set(True)
            bpy.context.view_layer.objects.active = cylinder
            bpy.ops.object.join()

            # Get the combined object
            bounding_capsule = bpy.context.object

            # Move the bounding capsule to the same location as the original object
            bounding_capsule.location = selected_object.location

            # Align the bounding capsule with the original object's rotation
            bounding_capsule.rotation_euler = selected_object.rotation_euler

            # Set the bounding capsule as the parent of the original object
            selected_object.parent = bounding_capsule

        else:
            self.report({'ERROR'}, "No selected object found.")

        return {'FINISHED'}

# Panel to display the Generate Bounding Capsule button
class OBJECT_PT_bounding_capsule_panel(bpy.types.Panel):
    bl_idname = "OBJECT_PT_bounding_capsule_panel"
    bl_label = "Bounding Capsule"
    bl_category = "Tool"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"

    def draw(self, context):
        layout = self.layout

        row = layout.row()
        row.operator("object.generate_bounding_capsule", text="Generate Bounding Capsule")

# Register the addon
def register():
    bpy.utils.register_class(OBJECT_OT_generate_bounding_capsule)
    bpy.utils.register_class(OBJECT_PT_bounding_capsule_panel)

def unregister():
    bpy.utils.unregister_class(OBJECT_OT_generate_bounding_capsule)
    bpy.utils.unregister_class(OBJECT_PT_bounding_capsule_panel)

if __name__ == "__main__":
    register()