<?php
import bpy
import math
from mathutils import Vector, Euler
# Settings
base_name = "hand"
max_depth = 2
initial_scale = 1.0
scale_factor = 0.30
offsets = [
Vector((0, 0, 10)),
Vector((-0.18, 1.6, 9.4)),
Vector((-0.2, -1.5, 9.4)),
Vector((-0.4, 3.0, 8.3)),
Vector((-2.4, -2.5, 5.7)),
]
rotation_angles = [ # (X, Y, Z) in degrees
( 0, 0, 0),
(-13, 0, 0),
( 10, 0, 0),
( -30, 0, 0),
( 40, 0, -80)
]
# Cleanup: remove all objects except the base
for obj in bpy.data.objects:
if obj.type == 'MESH' and obj.name != base_name:
bpy.data.objects.remove(obj, do_unlink=True)
# Locate original
original = bpy.data.objects.get(base_name)
if not original:
raise ValueError(f"No object named '{base_name}' found.")
original.scale = (1.0, 1.0, 1.0)
def clone_branch(parent_obj, parent_loc, parent_rot, parent_scale, depth):
if depth == 0:
return
for i in range(len(offsets)):
# Compute new scale
new_scale = parent_scale * scale_factor
# Rotate the offset using only the parent’s rotation (not including this level’s rotation yet)
rotated_offset = offsets[i].copy()
rotated_offset.rotate(parent_rot)
# Compute the location
new_loc = parent_loc + rotated_offset * new_scale
# Compute new cumulative rotation (after this level's rotation)
level_rot = Euler([math.radians(a) for a in rotation_angles[i]])
new_rot = parent_rot.copy()
new_rot.rotate(level_rot)
# Duplicate the object
new_obj = parent_obj.copy()
new_obj.data = parent_obj.data.copy()
bpy.context.collection.objects.link(new_obj)
new_obj.scale = (new_scale,) * 3
new_obj.location = new_loc
new_obj.rotation_euler = new_rot
# Recurse into next level with updated transform
clone_branch(new_obj, new_loc, new_rot, new_scale, depth - 1)
# Launch the fractal generation
clone_branch(original, original.location.copy(), original.rotation_euler.copy(), 1.0, max_depth)