[AI Collaboration] Learning English through AI-Driven 3D Modeling: Crafting a Lear's Macaw

Learning English through AI-Driven 3D Modeling: Crafting a Lear's Macaw

The Story

Recreating the striking cobalt plumage of the endangered Lear's Macaw in a 3D environment involves a deep dive into mesh deformation and procedural pattern synthesis. Using the provided reference, the Python script employs bmesh operations to curve the bird's iconic beak and Voronoi textures to simulate the intricate layering of feathers. This project offers a focused way to learn English terminology associated with mesh editing and advanced shader networks in Blender.

Macaw Reference

Reference Image

Macaw 3D Model

3D Model Render


AI's Explanation

  1. Mesh Deformation: "To achieve the distinct hook of the upper beak, I manipulated the vertex coordinates using a quadratic function within a bmesh loop."
  2. Procedural Feathering: "The subtle bump of the feathers was created by piping a Voronoi texture into a bump node, giving the surface a natural, organic feel."
  3. Precision Positioning: "The eye rings and pupils were placed using specific spatial coordinates to mirror the focused expression of the reference macaw."

Key Words and Phrases

Voronoi texture

A procedural texture that divides space into cells, often used in 3D art to create organic patterns like skin, stone, or feathers.

Context: "I used a Voronoi texture to add a feather-like bump."

vertex

The fundamental point in 3D space where edges meet. Manipulating vertices allows you to change the shape of an object.

Context: "The script adjusts each vertex to curve the beak."

bump node

A shader node that simulates small surface details (like texture) by perturbing the surface normals without changing the actual geometry.

Context: "Connect the texture to the bump node for extra detail."

coordinates

A set of numbers used to specify the precise location of a point or object in 3D space (X, Y, Z).

Context: "The script uses precise coordinates for eye placement."

Script Preview

Copy the code below into Blender's Text Editor to generate your own Lear's Macaw model.

Python
import bpy
import bmesh
import math

def create_macaw_material(name, color, roughness=0.5, use_feather_pattern=False):
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    
    nodes.clear()
    
    node_output = nodes.new('ShaderNodeOutputMaterial')
    node_principled = nodes.new('ShaderNodeBsdfPrincipled')
    node_principled.inputs['Base Color'].default_value = color
    node_principled.inputs['Roughness'].default_value = roughness
    links.new(node_principled.outputs['BSDF'], node_output.inputs['Surface'])
    
    if use_feather_pattern:
        tex_coord = nodes.new('ShaderNodeTexCoord')
        mapping = nodes.new('ShaderNodeMapping')
        voronoi = nodes.new('ShaderNodeTexVoronoi')
        bump = nodes.new('ShaderNodeBump')
        
        voronoi.voronoi_dimensions = '3D'
        voronoi.feature = 'F1'
        voronoi.inputs['Scale'].default_value = 15.0 
        
        bump.inputs['Strength'].default_value = 0.15 
        
        links.new(tex_coord.outputs['Object'], mapping.inputs['Vector'])
        links.new(mapping.outputs['Vector'], voronoi.inputs['Vector'])
        links.new(voronoi.outputs['Distance'], bump.inputs['Height'])
        links.new(bump.outputs['Normal'], node_principled.inputs['Normal'])
        
    return mat

def create_part(name, location, scale, material, type='SPHERE', rotation=(0,0,0)):
    if type == 'SPHERE':
        bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=location)
    elif type == 'CYLINDER':
        bpy.ops.mesh.primitive_cylinder_add(radius=1, depth=2, location=location)
    elif type == 'CURVED_BEAK':
        bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=location)
        obj = bpy.context.active_object
        bm = bmesh.new()
        bm.from_mesh(obj.data)
        for v in bm.verts:
            if v.co.y > 0:
                v.co.z -= (v.co.y ** 2) * 0.8
        bm.to_mesh(obj.data)
        bm.free()
    
    obj = bpy.context.active_object
    obj.name = name
    obj.scale = scale
    obj.rotation_euler = rotation
    obj.data.materials.append(material)
    
    bpy.ops.object.shade_smooth()
    mod = obj.modifiers.new(name="Subdiv", type='SUBSURF')
    mod.levels = 2
    return obj

# --- Scene Setup ---
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()

cobalt_blue = (0.0, 0.28, 0.67, 1.0)
pale_yellow = (0.95, 0.9, 0.4, 1.0)
beak_black = (0.02, 0.02, 0.02, 1.0)
leg_gray = (0.12, 0.12, 0.12, 1.0)

# --- Materials ---
mat_plumage = create_macaw_material("Mat_Plumage", cobalt_blue, use_feather_pattern=True)
mat_skin = create_macaw_material("Mat_YellowSkin", pale_yellow)
mat_beak = create_macaw_material("Mat_Beak", beak_black, roughness=0.1)
mat_leg = create_macaw_material("Mat_Leg", leg_gray, roughness=0.9)
mat_pupil = create_macaw_material("Mat_Pupil", (0, 0, 0, 1), roughness=0.1)

rot_30_rad = math.radians(-30)

# --- Build the Macaw ---
create_part("Body", (0, -0.1, 0.2), (1, 0.8, 1.2), mat_plumage, rotation=(rot_30_rad, 0, 0))
create_part("Neck", (0, 0.15, 1.25), (0.65, 0.6, 0.45), mat_plumage, type='SPHERE', rotation=(rot_30_rad, 0, 0))
create_part("Head", (0, 0.25, 1.45), (0.7, 0.7, 0.7), mat_plumage)
create_part("Upper_Beak", (0, 0.75, 1.55), (0.35, 0.6, 0.5), mat_beak, type='CURVED_BEAK')
create_part("Lower_Beak", (0, 0.55, 1.2), (0.25, 0.3, 0.2), mat_beak, rotation=(0.5, 0, 0))
create_part("Mandible_Patch_L", (0.35, 0.6, 1.35), (0.1, 0.15, 0.2), mat_skin, rotation=(0, 0.3, 0))
create_part("Mandible_Patch_R", (-0.35, 0.6, 1.35), (0.1, 0.15, 0.2), mat_skin, rotation=(0, -0.3, 0))

ring_loc_y = 0.62657
ring_loc_z = 1.55
create_part("Left_Eye_Ring", (0.5, ring_loc_y, ring_loc_z), (0.15, 0.1, 0.15), mat_skin, 
            rotation=(math.radians(-25), math.radians(-153.35), math.radians(-45)))
create_part("Right_Eye_Ring", (-0.5, ring_loc_y, ring_loc_z), (0.15, 0.1, 0.15), mat_skin, 
            rotation=(math.radians(-25), math.radians(153.35), math.radians(45)))

pupil_scale = (0.105, 0.075, 0.105)
pupil_rot_z = math.radians(-45)
pupil_loc_y = 0.68657
pupil_loc_z = 1.5437

create_part("Left_Pupil", (0.53, pupil_loc_y, pupil_loc_z), pupil_scale, mat_pupil, rotation=(0, 0, pupil_rot_z))
create_part("Right_Pupil", (-0.53, pupil_loc_y, pupil_loc_z), pupil_scale, mat_pupil, rotation=(0, 0, -pupil_rot_z))

create_part("Leg_L", (0.35, -0.1, -0.8), (0.22, 0.22, 0.45), mat_leg, type='CYLINDER')
create_part("Leg_R", (-0.35, -0.1, -0.8), (0.22, 0.22, 0.45), mat_leg, type='CYLINDER')
create_part("Toe_L_F", (0.35, 0.15, -1.3), (0.15, 0.3, 0.2), mat_leg, type='CYLINDER', rotation=(math.radians(80.214), 0, 0))
create_part("Toe_L_B", (0.35, -0.25, -1.3), (0.1, 0.25, 0.1), mat_leg, type='CYLINDER', rotation=(math.radians(97.403), 0, 0))
create_part("Toe_R_F", (-0.35, 0.15, -1.3), (0.15, 0.3, 0.2), mat_leg, type='CYLINDER', rotation=(math.radians(80.214), 0, 0))
create_part("Toe_R_B", (-0.35, -0.25, -1.3), (0.1, 0.25, 0.1), mat_leg, type='CYLINDER', rotation=(math.radians(97.403), 0, 0))
create_part("Left_Wing", (0.85, -0.4, -0.2), (0.2, 0.7, 1.3), mat_plumage, rotation=(rot_30_rad, 0, 0))
create_part("Right_Wing", (-0.85, -0.4, -0.2), (0.2, 0.7, 1.3), mat_plumage, rotation=(rot_30_rad, 0, 0))
create_part("Tail", (0, -1.0, -0.3), (0.4, 0.2, 1.8), mat_plumage, rotation=(math.radians(-45), 0, 0))

Comments

Popular posts from this blog

シャキシャキ美味しい!スナップエンドウ、英語でどう言う?

[AI & Seasonal English]: 半夏生編 -「半夏生」で日本の美しい暦と英語を学ぼう!

[AI & Seasonal English] 【スパイス香る】ドイツのクリスマスパン「シュトーレン(Stollen)」の歴史と「しっとり感」を語る英語