Learning English through AI-Driven 3D Modeling: Crafting a Giraffe

Learning English through AI-Driven 3D Modeling: Crafting a Giraffe

The Story

The giraffe is instantly recognizable for its towering height, elongated neck, and beautiful, distinct camouflage spots. Translating these organic features into a stylized, blocky 3D figurine involves balancing geometric simplicity with precise procedural texturing. By using a Python script in Blender, we can build a charming low-poly version of a giraffe that utilizes mathematical principles to align its long limbs and a continuous Voronoi texture to generate its iconic pattern. This project offers an excellent path to master the English vocabulary associated with programmatic coordinates, edge softening, and spatial proportions within a 3D pipeline.

Reference photo of a giraffe in the savanna
Reference Image
3D giraffe model created with Python script
3D Model Render

AI's Explanation

  1. Seamless Patterning: "To prevent the giraffe's spots from stretching over the elongated neck and legs, I linked the 'Object' output of the Texture Coordinate node to the Voronoi texture, ensuring an even distribution across all dimensions."
  2. Edge Softening: "To transform generic blocks into a polished, toy-like aesthetic, the script applies a Bevel modifier with multiple segments to smoothly round off the sharp corners of the body segments."
  3. Anatomical Proportions: "Establishing realistic Proportions required calculated rotations. I tilted the torso and neck using precise mathematical radians to capture the giraffe's majestic, upward-reaching stance."

Key Words and Phrases

Voronoi

A type of procedural noise function that divides space into cell-like regions based on distance to specific points. It is ideal for generating biological patterns like giraffe spots, scales, or cracked mud.

Context: "I used a Voronoi node to generate the organic spot pattern programmatically."

Bevel

An operation or modifier that slants or rounds off the sharp edges of a 3D object. In blocky modeling styles, this captures light reflections nicely and gives models a physical, tangible quality.

Context: "Adding a Bevel modifier removes the razor-sharp edges from the cube primitives."

Proportions

The comparative relation between things or magnitudes as to size, quantity, or ratio. Keeping the relative scale of the limbs and neck realistic ensures the animal looks convincing even when stylized.

Context: "Adjusting the neck length was essential to capture the correct Proportions of the giraffe."

Script Preview

Copy the code below into Blender's Text Editor to generate your own Toy Giraffe figurine.

Python
import bpy
import math

def create_giraffe_material():
    """Creates a Voronoi material that won't stretch."""
    mat = bpy.data.materials.new(name="Giraffe_Pattern")
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    
    for n in nodes: nodes.remove(n)
    
    output = nodes.new(type='ShaderNodeOutputMaterial')
    bsdf = nodes.new(type='ShaderNodeBsdfPrincipled')
    ramp = nodes.new(type='ShaderNodeValToRGB')
    voronoi = nodes.new(type='ShaderNodeTexVoronoi')
    coord = nodes.new(type='ShaderNodeTexCoord')

    links.new(coord.outputs['Object'], voronoi.inputs['Vector'])

    voronoi.voronoi_dimensions = '3D'
    voronoi.feature = 'F1'
    if hasattr(voronoi, "distance"):
        voronoi.distance = 'EUCLIDEAN'
    else:
        voronoi.distance_metric = 'EUCLIDEAN'
        
    voronoi.inputs['Scale'].default_value = 4.5 
    voronoi.inputs['Randomness'].default_value = 0.8
    
    ramp.color_ramp.interpolation = 'CONSTANT'
    ramp.color_ramp.elements[0].position = 0.55
    ramp.color_ramp.elements[0].color = (0.32, 0.15, 0.05, 1) # Dark Brown
    ramp.color_ramp.elements[1].position = 0.60
    ramp.color_ramp.elements[1].color = (0.9, 0.8, 0.7, 1)    # Cream

    links.new(voronoi.outputs['Distance'], ramp.inputs['Fac'])
    links.new(ramp.outputs['Color'], bsdf.inputs['Base Color'])
    
    # Glossy plastic figurine finish
    bsdf.inputs['Roughness'].default_value = 0.3
    
    links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])
    return mat

def create_part(name, scale, location, rotation=(0, 0, 0), color=None, material=None, bevel_width=0.04, shape='CUBE'):
    if shape == 'SPHERE':
        bpy.ops.mesh.primitive_uv_sphere_add(radius=0.5, segments=32, ring_count=16)
    else:
        bpy.ops.mesh.primitive_cube_add(size=1)
        
    obj = bpy.context.active_object
    obj.name = name
    obj.scale = scale
    obj.location = location
    obj.rotation_euler = rotation
    
    # Apply scale to prevent distortion
    bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
    
    # Add Bevel Modifier for rounded edges, or smooth shade for spheres
    if shape == 'CUBE' and bevel_width > 0:
        bevel_mod = obj.modifiers.new(name="Bevel", type='BEVEL')
        bevel_mod.width = bevel_width
        bevel_mod.segments = 4
        bpy.ops.object.shade_smooth()
    elif shape == 'SPHERE':
        bpy.ops.object.shade_smooth()
    
    if material:
        obj.data.materials.append(material)
    elif color:
        mat = bpy.data.materials.new(name=f"Mat_{name}")
        mat.use_nodes = True
        bsdf = mat.node_tree.nodes["Principled BSDF"]
        bsdf.inputs['Base Color'].default_value = color
        bsdf.inputs['Roughness'].default_value = 0.3
        obj.data.materials.append(mat)
    return obj

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

pattern_mat = create_giraffe_material()
BROWN = (0.6, 0.3, 0.1, 1)
CREAM = (0.9, 0.8, 0.7, 1)
DARK = (0.05, 0.02, 0.01, 1)

# Proportions
torso_rot = math.radians(12)
torso_loc = (0, 0, 3.2)

# Main Body Parts
create_part("Torso", (1.0, 1.8, 1.2), torso_loc, (torso_rot, 0, 0), material=pattern_mat, bevel_width=0.08)

neck_angle, neck_l, neck_loc = math.radians(-25), 3.5, (0, 1.15, 5.2)
create_part("Neck", (0.4, 0.4, neck_l), neck_loc, (neck_angle, 0, 0), material=pattern_mat, bevel_width=0.04)

h_y = neck_loc[1] + (math.sin(-neck_angle) * (neck_l/2)) + 0.3
h_z = neck_loc[2] + (math.cos(-neck_angle) * (neck_l/2)) + 0.1
create_part("Head", (0.5, 1.0, 0.5), (0, h_y, h_z), (math.radians(10), 0, 0), material=pattern_mat, bevel_width=0.05)

# Legs and Joints Setup (Slim legs with larger pattern-matching sphere joints)
f_y, f_z = torso_loc[1] + (math.cos(torso_rot) * 0.8), torso_loc[2] + (math.sin(torso_rot) * 0.8)
b_y, b_z = torso_loc[1] - (math.cos(torso_rot) * 0.8), torso_loc[2] - (math.sin(torso_rot) * 0.8)

leg_data = [("FL", -0.4, f_y, f_z, 3.35), ("FR", 0.4, f_y, f_z, 3.35),
            ("BL", -0.4, b_y, b_z, 3.0), ("BR", 0.4, b_y, b_z, 3.0)]

for name, x, y, az, h in leg_data:
    joint_z = az - 0.1 
    create_part(f"Joint_{name}", (0.35, 0.35, 0.35), (x, y, joint_z), material=pattern_mat, shape='SPHERE')
    create_part(name, (0.2, 0.2, h), (x, y, joint_z - (h/2)), material=pattern_mat, bevel_width=0.02)

# Detail Parts
create_part("Ear_L", (0.3, 0.1, 0.2), (-0.32, h_y - 0.15, h_z + 0.3), (0, 0, math.radians(30)), color=BROWN, bevel_width=0.02)
create_part("Ear_R", (0.3, 0.1, 0.2), (0.32, h_y - 0.15, h_z + 0.3), (0, 0, math.radians(-30)), color=BROWN, bevel_width=0.02)

create_part("Ossicone_L", (0.1, 0.1, 0.4), (-0.15, h_y - 0.1, h_z + 0.4), color=DARK, bevel_width=0.01)
create_part("Ossicone_R", (0.1, 0.1, 0.4), (0.15, h_y - 0.1, h_z + 0.4), color=DARK, bevel_width=0.01)
create_part("Eye_L", (0.1, 0.1, 0.1), (-0.28, h_y + 0.2, h_z + 0.1), color=DARK, bevel_width=0.005)
create_part("Eye_R", (0.1, 0.1, 0.1), (0.28, h_y + 0.2, h_z + 0.1), color=DARK, bevel_width=0.005)
create_part("Tail", (0.1, 0.1, 1.2), (0, b_y, b_z), (math.radians(-45), 0, 0), color=DARK, bevel_width=0.01)

bpy.ops.object.select_all(action='DESELECT')

Comments

Popular posts from this blog

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

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

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