import bpy
import math
def setup_clear_scene():
"""Clears all mesh objects from the initial scene safely."""
if bpy.context.object and bpy.context.object.mode != 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT')
# Select and delete all mesh objects
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.context.scene.objects:
if obj.type == 'MESH':
obj.select_set(True)
bpy.ops.object.delete()
def get_or_create_collection(collection_name):
"""Creates a custom collection if it doesn't exist and links it to the scene."""
if collection_name in bpy.data.collections:
return bpy.data.collections[collection_name]
new_collection = bpy.data.collections.new(collection_name)
bpy.context.scene.collection.children.link(new_collection)
return new_collection
def create_advanced_material(name, color, roughness=0.5, specular=0.5):
"""Creates a standard Principled BSDF material with specified parameters."""
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
# Get the Principled BSDF node
bsdf = nodes.get("Principled BSDF")
if bsdf:
bsdf.inputs['Base Color'].default_value = color
bsdf.inputs['Roughness'].default_value = roughness
if 'Specular' in bsdf.inputs:
bsdf.inputs['Specular'].default_value = specular
elif 'Specular IOR Level' in bsdf.inputs:
bsdf.inputs['Specular IOR Level'].default_value = specular
return mat
def apply_subdivision_and_smooth(obj, levels=2):
"""Applies Subdivision Surface modifier and enables smooth shading natively."""
if hasattr(obj.data, "polygons"):
for poly in obj.data.polygons:
poly.use_smooth = True
subsurf = obj.modifiers.new(name="Subdivision", type='SUBSURF')
subsurf.levels = levels
subsurf.render_levels = levels
def set_parent_keep_transform(child, parent):
"""Establishes a parent-child relationship while safely preserving world transformation."""
child.parent = parent
child.matrix_parent_inverse = parent.matrix_world.inverted()
def create_rabbit_model():
"""Generates a high-quality stylized rabbit inside a dedicated managing collection."""
setup_clear_scene()
# --- Collection Setup for Better Model Management ---
rabbit_collection = get_or_create_collection("Collection_Rabbit")
# Safely backup and set active layer collection using proper Blender API properties
original_layer_collection = bpy.context.view_layer.active_layer_collection
rabbit_layer_collection = bpy.context.view_layer.layer_collection.children.get(rabbit_collection.name)
if rabbit_layer_collection:
bpy.context.view_layer.active_layer_collection = rabbit_layer_collection
# --- Material Palette Definition ---
white_fur_mat = create_advanced_material("Mat_WhiteFur", (0.95, 0.95, 0.95, 1.0), roughness=0.8, specular=0.2)
ruby_eye_mat = create_advanced_material("Mat_RubyEye", (0.6, 0.01, 0.03, 1.0), roughness=0.05, specular=1.0)
pink_nose_mat = create_advanced_material("Mat_PinkNose", (1.0, 0.5, 0.55, 1.0), roughness=0.4, specular=0.4)
inner_ear_mat = create_advanced_material("Mat_InnerEar", (1.0, 0.75, 0.8, 1.0), roughness=0.6, specular=0.3)
# --- 1. Main Parent Body ---
bpy.ops.mesh.primitive_uv_sphere_add(segments=32, ring_count=16, radius=1.0, location=(0.0, 0.0, 0.0))
body = bpy.context.active_object
body.name = "Rabbit_Body"
body.scale = (1.1, 1.4, 0.95)
body.data.materials.append(white_fur_mat)
apply_subdivision_and_smooth(body, levels=2)
bpy.context.view_layer.update()
# --- 2. Head ---
bpy.ops.mesh.primitive_uv_sphere_add(segments=32, ring_count=16, radius=0.7, location=(0.0, -1.1, 0.75))
head = bpy.context.active_object
head.name = "Rabbit_Head"
head.scale = (1.0, 0.95, 0.95)
head.data.materials.append(white_fur_mat)
apply_subdivision_and_smooth(head, levels=2)
set_parent_keep_transform(head, body)
bpy.context.view_layer.update()
# --- 3. Ears ---
for side in ["R", "L"]:
sign = 1.0 if (side == "R") else -1.0
bpy.ops.mesh.primitive_uv_sphere_add(segments=32, ring_count=16, radius=0.22, location=(0.28 * sign, -1.05, 1.45))
ear = bpy.context.active_object
ear.name = f"Rabbit_Ear_{side}"
ear.scale = (0.75, 0.45, 2.8)
ear.rotation_euler = (0.15, 0.18 * sign, -0.05 * sign)
ear.data.materials.append(white_fur_mat)
ear.data.materials.append(inner_ear_mat)
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
for poly in ear.data.polygons:
if poly.normal.y < -0.35 and abs(poly.normal.x) < 0.75 and poly.center.z < 0.4:
poly.material_index = 1
bpy.ops.object.mode_set(mode='OBJECT')
apply_subdivision_and_smooth(ear, levels=2)
set_parent_keep_transform(ear, head)
# --- 4. Eyes ---
for side in ["R", "L"]:
sign = 1.0 if side == "R" else -1.0
bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=16, radius=0.1, location=(0.44 * sign, -1.54, 0.92))
eye = bpy.context.active_object
eye.name = f"Rabbit_Eye_{side}"
eye.scale = (0.9, 0.6, 0.9)
eye.rotation_euler = (0.1, 0.1 * sign, 0.45 * sign)
eye.data.materials.append(ruby_eye_mat)
apply_subdivision_and_smooth(eye, levels=2)
set_parent_keep_transform(eye, head)
# --- 5. Nose ---
bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=16, radius=0.08, location=(0.0, -1.75, 0.7))
nose = bpy.context.active_object
nose.name = "Rabbit_Nose"
nose.scale = (1.2, 0.8, 0.7)
nose.data.materials.append(pink_nose_mat)
apply_subdivision_and_smooth(nose, levels=2)
set_parent_keep_transform(nose, head)
# --- 6. Front Legs ---
for side in ["R", "L"]:
sign = 1.0 if side == "R" else -1.0
bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=16, radius=0.18, location=(0.4 * sign, -0.9, -0.65))
leg_f = bpy.context.active_object
leg_f.name = f"Rabbit_Leg_Front_{side}"
leg_f.scale = (1.0, 1.3, 0.8)
leg_f.data.materials.append(white_fur_mat)
apply_subdivision_and_smooth(leg_f, levels=2)
set_parent_keep_transform(leg_f, body)
# --- 7. Back Legs ---
for side in ["R", "L"]:
sign = 1.0 if side == "R" else -1.0
bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=16, radius=0.32, location=(0.7 * sign, 0.4, -0.5))
leg_b = bpy.context.active_object
leg_b.name = f"Rabbit_Leg_Back_{side}"
leg_b.scale = (0.9, 1.5, 0.9)
leg_b.data.materials.append(white_fur_mat)
apply_subdivision_and_smooth(leg_b, levels=2)
set_parent_keep_transform(leg_b, body)
# --- 8. Tail ---
bpy.ops.mesh.primitive_uv_sphere_add(segments=16, ring_count=16, radius=0.25, location=(0.0, 1.3, 0.3))
tail = bpy.context.active_object
tail.name = "Rabbit_Tail"
tail.scale = (1.0, 0.9, 1.0)
tail.data.materials.append(white_fur_mat)
apply_subdivision_and_smooth(tail, levels=2)
set_parent_keep_transform(tail, body)
# Restore the original active layer collection context safely
bpy.context.view_layer.active_layer_collection = original_layer_collection
if __name__ == "__main__":
create_rabbit_model()
Comments
Post a Comment