🎯 Recommended Samples
Balanced sample collections from various categories for you to explore
Blender Scripting Samples
Blender Python scripting examples for 3D modeling, animation, asset creation, and workflow automation
💻 Blender Hello World python
🟢 simple
⭐⭐
Basic Blender scripting setup with object creation and scene manipulation fundamentals
⏱️ 15 min
🏷️ blender, python, 3d, scripting
Prerequisites:
Basic Python knowledge, Blender interface familiarity
# Blender Hello World - Basic Scripting Setup
# Run this script in Blender's Scripting workspace or from the Text Editor
import bpy
import math
def clear_scene():
"""Clear all objects from the current scene"""
# Select all objects
bpy.ops.object.select_all(action='SELECT')
# Delete selected objects
bpy.ops.object.delete()
print("Scene cleared")
def create_basic_objects():
"""Create basic geometric objects"""
# Create a cube
bpy.ops.mesh.primitive_cube_add(location=(-2, 0, 0))
cube = bpy.context.active_object
cube.name = "HelloCube"
cube.scale = (1, 1, 1)
print(f"Created cube: {cube.name}")
# Create a sphere
bpy.ops.mesh.primitive_uv_sphere_add(location=(2, 0, 0))
sphere = bpy.context.active_object
sphere.name = "HelloSphere"
sphere.scale = (1, 1, 1)
print(f"Created sphere: {sphere.name}")
# Create a plane
bpy.ops.mesh.primitive_plane_add(location=(0, -2, 0))
plane = bpy.context.active_object
plane.name = "HelloPlane"
plane.scale = (3, 3, 1)
print(f"Created plane: {plane.name}")
return cube, sphere, plane
def create_materials():
"""Create basic materials for objects"""
# Red material for cube
red_material = bpy.data.materials.new(name="RedMaterial")
red_material.diffuse_color = (0.8, 0.1, 0.1, 1.0)
# Green material for sphere
green_material = bpy.data.materials.new(name="GreenMaterial")
green_material.diffuse_color = (0.1, 0.8, 0.1, 1.0)
# Blue material for plane
blue_material = bpy.data.materials.new(name="BlueMaterial")
blue_material.diffuse_color = (0.1, 0.1, 0.8, 1.0)
return red_material, green_material, blue_material
def apply_materials(obj, material):
"""Apply material to object"""
if obj.data.materials:
obj.data.materials[0] = material
else:
obj.data.materials.append(material)
print(f"Applied material {material.name} to {obj.name}")
def setup_lighting():
"""Setup basic scene lighting"""
# Add a sun light
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
sun = bpy.context.active_object
sun.name = "SunLight"
sun.data.energy = 5.0
print(f"Created sun light: {sun.name}")
# Add an area light for fill
bpy.ops.object.light_add(type='AREA', location=(-3, -3, 5))
area = bpy.context.active_object
area.name = "FillLight"
area.data.energy = 2.0
area.data.size = 2.0
print(f"Created area light: {area.name}")
def setup_camera():
"""Setup camera for the scene"""
bpy.ops.object.camera_add(location=(7, -7, 5))
camera = bpy.context.active_object
camera.name = "MainCamera"
# Point camera at origin
direction = -camera.location
rot_quat = direction.to_track_quat('-Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
# Set as active camera
bpy.context.scene.camera = camera
print(f"Created camera: {camera.name}")
def create_text_object():
"""Create a 3D text object"""
bpy.ops.object.text_add(location=(0, 0, 2))
text_obj = bpy.context.active_object
text_obj.name = "HelloWorldText"
# Modify text properties
text_obj.data.body = "Hello Blender!"
text_obj.data.font_size = 1.0
text_obj.data.extrude = 0.1
# Center the text
text_obj.data.align_x = 'CENTER'
# Apply rotation for better visibility
text_obj.rotation_euler = (0, 0, math.radians(0))
print(f"Created text object: {text_obj.name}")
return text_obj
def animate_objects(cube, sphere, text_obj):
"""Create simple animations for objects"""
# Set timeline range
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 120
# Animate cube rotation
cube.rotation_euler = (0, 0, 0)
cube.keyframe_insert(data_path="rotation_euler", frame=1)
bpy.context.scene.frame_set(60)
cube.rotation_euler = (0, 0, math.radians(90))
cube.keyframe_insert(data_path="rotation_euler", frame=60)
bpy.context.scene.frame_set(120)
cube.rotation_euler = (0, 0, math.radians(180))
cube.keyframe_insert(data_path="rotation_euler", frame=120)
# Animate sphere location
sphere.location = (2, 0, 0)
sphere.keyframe_insert(data_path="location", frame=1)
bpy.context.scene.frame_set(60)
sphere.location = (2, 0, 2)
sphere.keyframe_insert(data_path="location", frame=60)
bpy.context.scene.frame_set(120)
sphere.location = (2, 0, 0)
sphere.keyframe_insert(data_path="location", frame=120)
# Animate text scale
text_obj.scale = (1, 1, 1)
text_obj.keyframe_insert(data_path="scale", frame=1)
bpy.context.scene.frame_set(60)
text_obj.scale = (1.2, 1.2, 1.2)
text_obj.keyframe_insert(data_path="scale", frame=60)
bpy.context.scene.frame_set(120)
text_obj.scale = (1, 1, 1)
text_obj.keyframe_insert(data_path="scale", frame=120)
# Reset to frame 1
bpy.context.scene.frame_set(1)
print("Animation keyframes created")
def setup_render_settings():
"""Configure basic render settings"""
scene = bpy.context.scene
# Set render engine to Cycles for better quality
scene.render.engine = 'CYCLES'
# Set output resolution
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.resolution_percentage = 50 # Render at 50% for faster testing
# Set output format
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGBA'
# Set samples for Cycles
scene.cycles.samples = 128
# Set file path
scene.render.filepath = "//hello_blender_render.png"
print("Render settings configured")
def main():
"""Main function to execute the Hello World script"""
print("=== Blender Hello World Script ===")
print(f"Blender Version: {bpy.app.version}")
# Clear the scene
clear_scene()
# Create objects
cube, sphere, plane = create_basic_objects()
text_obj = create_text_object()
# Create materials
red_mat, green_mat, blue_mat = create_materials()
# Apply materials
apply_materials(cube, red_mat)
apply_materials(sphere, green_mat)
apply_materials(plane, blue_mat)
# Create yellow material for text
yellow_material = bpy.data.materials.new(name="YellowMaterial")
yellow_material.diffuse_color = (0.9, 0.9, 0.1, 1.0)
apply_materials(text_obj, yellow_material)
# Setup scene
setup_lighting()
setup_camera()
animate_objects(cube, sphere, text_obj)
setup_render_settings()
print("=== Hello World scene created successfully! ===")
print("Press SPACE in the 3D Viewport to play the animation")
print("Press F12 to render the current frame")
# Run the main function
if __name__ == "__main__":
main()
💻 Procedural Geometry Generation python
🟡 intermediate
⭐⭐⭐⭐
Advanced procedural modeling with mathematical functions, parametric objects, and complex geometry
⏱️ 35 min
🏷️ blender, python, 3d, procedural, geometry
Prerequisites:
Advanced Python, Mathematics for 3D graphics, BMesh module
# Blender Procedural Geometry Generation
# Mathematical functions and parametric modeling
import bpy
import bmesh
import math
import numpy as np
from mathutils import Vector, Matrix
def clear_scene():
"""Clear all objects from the current scene"""
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
def create_parametric_surface(width=10, height=10, resolution=50):
"""Create a parametric surface using mathematical functions"""
# Create mesh data
verts = []
edges = []
faces = []
# Generate vertices using sine and cosine functions
for i in range(resolution + 1):
for j in range(resolution + 1):
u = i / resolution * width - width / 2
v = j / resolution * height - height / 2
# Mathematical function for surface
x = u
y = v
z = (math.sin(math.sqrt(u*u + v*v)) * 2 +
math.cos(u * 0.5) * math.cos(v * 0.5))
verts.append((x, y, z))
# Create edges
for i in range(resolution):
for j in range(resolution):
# Current vertex index
current = i * (resolution + 1) + j
# Edge to next vertex in row
edges.append((current, current + 1))
# Edge to vertex in next row
edges.append((current, current + resolution + 1))
# Create faces
for i in range(resolution):
for j in range(resolution):
current = i * (resolution + 1) + j
# Two triangles per grid cell
faces.append((
current,
current + 1,
current + resolution + 2,
current + resolution + 1
))
# Create mesh object
mesh = bpy.data.meshes.new("ParametricSurface")
mesh.from_pydata(verts, edges, faces)
mesh.update()
# Create object
obj = bpy.data.objects.new("ParametricSurface", mesh)
bpy.context.collection.objects.link(obj)
return obj
def create_l_system(iterations=4, angle=25, length=1):
"""Create a plant-like structure using L-system"""
# L-system rules
rules = {
'F': 'FF+[+F-F-F]-[-F+F+F]',
'X': 'F+[[X]-X]-F[-FX]+X'
}
# Start with axiom
current = 'X'
# Generate L-system string
for _ in range(iterations):
next_string = ''
for char in current:
next_string += rules.get(char, char)
current = next_string
# Convert L-system string to 3D structure
mesh = bpy.data.meshes.new("LSystem")
bm = bmesh.new()
# Create vertices and edges
position = Vector((0, 0, 0))
direction = Vector((0, 0, 1))
angle_rad = math.radians(angle)
# Stack for turtle graphics
position_stack = []
direction_stack = []
# First vertex
bm.verts.new(position)
for char in current:
if char == 'F':
# Move forward and create edge
new_pos = position + direction * length
bm.verts.new(new_pos)
bm.edges.new((bm.verts[-2], bm.verts[-1]))
position = new_pos
elif char == '+':
# Turn right
rotation_matrix = Matrix.Rotation(angle_rad, 4, 'Z')
direction = rotation_matrix @ direction
elif char == '-':
# Turn left
rotation_matrix = Matrix.Rotation(-angle_rad, 4, 'Z')
direction = rotation_matrix @ direction
elif char == '[':
# Push current state
position_stack.append(position.copy())
direction_stack.append(direction.copy())
elif char == ']':
# Pop state
position = position_stack.pop()
direction = direction_stack.pop()
bm.to_mesh(mesh)
bm.free()
# Create object
obj = bpy.data.objects.new("LSystem", mesh)
bpy.context.collection.objects.link(obj)
return obj
def create_voronoi_pattern(points_count=50, size=10):
"""Create a Voronoi pattern using random points"""
import random
# Generate random points
points = []
for _ in range(points_count):
x = random.uniform(-size/2, size/2)
y = random.uniform(-size/2, size/2)
points.append((x, y))
# Create base grid
resolution = 100
mesh = bpy.data.meshes.new("VoronoiPattern")
bm = bmesh.new()
# Create vertices and find nearest point for each
for i in range(resolution):
for j in range(resolution):
x = (i / resolution * size) - size/2
y = (j / resolution * size) - size/2
# Find nearest Voronoi point
min_dist = float('inf')
nearest_point = 0
for idx, (px, py) in enumerate(points):
dist = math.sqrt((x - px)**2 + (y - py)**2)
if dist < min_dist:
min_dist = dist
nearest_point = idx
# Create vertex with Z based on nearest point
z = nearest_point * 0.1 # Height variation based on region
bm.verts.new((x, y, z))
# Create faces (grid)
for i in range(resolution - 1):
for j in range(resolution - 1):
v1 = i * resolution + j
v2 = v1 + 1
v3 = v2 + resolution
v4 = v1 + resolution
try:
bm.faces.new((
bm.verts[v1],
bm.verts[v2],
bm.verts[v3],
bm.verts[v4]
))
except:
pass # Skip invalid faces
bm.to_mesh(mesh)
bm.free()
# Create object
obj = bpy.data.objects.new("VoronoiPattern", mesh)
bpy.context.collection.objects.link(obj)
return obj
def create_fractal_terrain(size=10, resolution=50, octaves=6, persistence=0.5):
"""Create a fractal terrain using Perlin noise"""
# Use Blender's noise module
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
# Create terrain mesh
mesh = bpy.data.meshes.new("FractalTerrain")
bm = bmesh.new()
# Generate vertices with noise
verts = {}
for i in range(resolution + 1):
for j in range(resolution + 1):
x = (i / resolution * size) - size/2
y = (j / resolution * size) - size/2
# Multi-octave Perlin noise
z = 0
amplitude = 1
frequency = 1
for octave in range(octaves):
# Simple noise function (since we can't import external noise libraries)
noise_val = (
math.sin(x * frequency * 0.3) * math.cos(y * frequency * 0.3) +
math.sin(x * frequency * 0.7) * math.sin(y * frequency * 0.7) * 0.5
)
z += noise_val * amplitude
amplitude *= persistence
frequency *= 2
verts[(i, j)] = bm.verts.new((x, y, z))
# Create faces
for i in range(resolution):
for j in range(resolution):
try:
v1 = verts[(i, j)]
v2 = verts[(i + 1, j)]
v3 = verts[(i + 1, j + 1)]
v4 = verts[(i, j + 1)]
bm.faces.new([v1, v2, v3, v4])
except:
pass
# Recalculate normals
bmesh.ops.recalc_face_normals(bm, faces=bm.faces)
bm.to_mesh(mesh)
bm.free()
# Create object
obj = bpy.data.objects.new("FractalTerrain", mesh)
bpy.context.collection.objects.link(obj)
return obj
def create_icosphere_subdivisions(subdivisions=3, radius=2):
"""Create an icosphere with custom subdivisions"""
import math
# Golden ratio
phi = (1 + math.sqrt(5)) / 2
# Initial icosahedron vertices
vertices = [
(-1, phi, 0), (1, phi, 0), (-1, -phi, 0), (1, -phi, 0),
(0, -1, phi), (0, 1, phi), (0, -1, -phi), (0, 1, -phi),
(phi, 0, -1), (phi, 0, 1), (-phi, 0, -1), (-phi, 0, 1)
]
# Normalize and scale
vertices = [Vector(v).normalized() * radius for v in vertices]
# Initial faces (20 triangles of icosahedron)
faces = [
(0, 11, 5), (0, 5, 1), (0, 1, 7), (0, 7, 10), (0, 10, 11),
(1, 5, 9), (5, 11, 4), (11, 10, 2), (10, 7, 6), (7, 1, 8),
(3, 9, 4), (3, 4, 2), (3, 2, 6), (3, 6, 8), (3, 8, 9),
(4, 9, 5), (2, 4, 11), (6, 2, 10), (8, 6, 7), (9, 8, 1)
]
# Subdivide faces
for _ in range(subdivisions):
new_faces = []
edge_midpoints = {}
for face in faces:
# Get midpoints of edges
new_vertices = []
for i in range(3):
v1, v2 = face[i], face[(i + 1) % 3]
edge = tuple(sorted([v1, v2]))
if edge not in edge_midpoints:
midpoint = (vertices[v1] + vertices[v2]) / 2
midpoint = midpoint.normalized() * radius
edge_midpoints[edge] = len(vertices)
vertices.append(midpoint)
new_vertices.append(edge_midpoints[edge])
# Create 4 new faces
v0, v1, v2 = face
m0, m1, m2 = new_vertices
new_faces.extend([
(v0, m0, m2),
(m0, v1, m1),
(m2, m1, v2),
(m0, m1, m2)
])
faces = new_faces
# Create mesh
mesh = bpy.data.meshes.new("CustomIcosphere")
mesh.from_pydata(vertices, [], faces)
mesh.update()
# Create object
obj = bpy.data.objects.new("CustomIcosphere", mesh)
bpy.context.collection.objects.link(obj)
return obj
def create_sculptural_form():
"""Create an artistic sculptural form using mathematical curves"""
# Create multiple parametric curves and loft between them
curves = []
for i in range(10):
# Create profile curve
profile_points = []
for j in range(20):
angle = j / 20 * 2 * math.pi
# Varying radius based on height
height_factor = i / 10
radius = 2 + math.sin(angle * 3) * (1 - height_factor)
x = math.cos(angle) * radius
y = math.sin(angle) * radius
z = i * 0.5
profile_points.append((x, y, z))
# Create curve object
curve_data = bpy.data.curves.new(f"Profile_{i}", type='CURVE')
curve_data.dimensions = '3D'
curve_data.fill_mode = 'FULL'
curve_data.bevel_depth = 0.05
spline = curve_data.splines.new('POLY')
spline.points.add(len(profile_points) - 1)
for point, (x, y, z) in enumerate(profile_points):
spline.points[point].co = (x, y, z, 1)
curve_obj = bpy.data.objects.new(f"Profile_{i}", curve_data)
bpy.context.collection.objects.link(curve_obj)
curves.append(curve_obj)
return curves
def main():
"""Main function to demonstrate procedural geometry generation"""
print("=== Procedural Geometry Generation ===")
# Clear scene
clear_scene()
# Create various procedural objects
surface = create_parametric_surface(width=8, height=8, resolution=30)
surface.location = (0, 0, 0)
l_system = create_l_system(iterations=4, angle=25, length=0.3)
l_system.location = (-5, 0, 0)
voronoi = create_voronoi_pattern(points_count=30, size=6)
voronoi.location = (5, 0, 0)
terrain = create_fractal_terrain(size=8, resolution=40, octaves=4)
terrain.location = (0, -8, -2)
icosphere = create_icosphere_subdivisions(subdivisions=2, radius=1.5)
icosphere.location = (0, 0, 4)
# Create sculptural forms
curves = create_sculptural_form()
for i, curve in enumerate(curves):
curve.location = (0, 8, i * 0.5)
# Add materials
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
mat = bpy.data.materials.new(name=f"Material_{obj.name}")
mat.diffuse_color = (0.7, 0.7, 0.9, 1.0)
if obj.data.materials:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
# Add lighting
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
sun = bpy.context.active_object
sun.data.energy = 3.0
bpy.ops.object.light_add(type='AREA', location=(-3, -3, 5))
area = bpy.context.active_object
area.data.energy = 1.5
# Add camera
bpy.ops.object.camera_add(location=(10, -10, 8))
camera = bpy.context.active_object
direction = -camera.location
rot_quat = direction.to_track_quat('-Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
bpy.context.scene.camera = camera
print("Procedural geometry generation complete!")
if __name__ == "__main__":
main()
💻 Animation and Rigging Automation python
🟡 intermediate
⭐⭐⭐⭐
Automated rigging, bone creation, and animation system for complex characters and objects
⏱️ 40 min
🏷️ blender, python, 3d, animation, rigging
Prerequisites:
Blender rigging knowledge, Python scripting, Animation principles
# Blender Animation and Rigging Automation
# Automated bone creation, weighting, and animation systems
import bpy
import math
from mathutils import Vector, Matrix, Quaternion
def clear_scene():
"""Clear all objects from the current scene"""
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
def create_character_mesh():
"""Create a basic humanoid character mesh"""
# Character proportions
height = 2.0
width = 0.8
# Create body parts as separate meshes
parts = {}
# Torso
bpy.ops.mesh.primitive_cube_add(size=1)
torso = bpy.context.active_object
torso.name = "Torso"
torso.scale = (width, 0.4, 0.8)
torso.location = (0, 0, height * 0.5)
parts['torso'] = torso
# Head
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.3)
head = bpy.context.active_object
head.name = "Head"
head.location = (0, 0, height * 0.9)
parts['head'] = head
# Left arm
bpy.ops.mesh.primitive_cylinder_add(radius=0.1, depth=0.6)
left_arm = bpy.context.active_object
left_arm.name = "LeftArm"
left_arm.location = (-width * 0.6, 0, height * 0.6)
left_arm.rotation_euler = (0, math.radians(90), 0)
parts['left_arm'] = left_arm
# Right arm
bpy.ops.mesh.primitive_cylinder_add(radius=0.1, depth=0.6)
right_arm = bpy.context.active_object
right_arm.name = "RightArm"
right_arm.location = (width * 0.6, 0, height * 0.6)
right_arm.rotation_euler = (0, math.radians(90), 0)
parts['right_arm'] = right_arm
# Left leg
bpy.ops.mesh.primitive_cylinder_add(radius=0.12, depth=0.8)
left_leg = bpy.context.active_object
left_leg.name = "LeftLeg"
left_leg.location = (-width * 0.3, 0, height * 0.2)
parts['left_leg'] = left_leg
# Right leg
bpy.ops.mesh.primitive_cylinder_add(radius=0.12, depth=0.8)
right_leg = bpy.context.active_object
right_leg.name = "RightLeg"
right_leg.location = (width * 0.3, 0, height * 0.2)
parts['right_leg'] = right_leg
return parts
def create_armature(parts):
"""Create an armature with bones for the character"""
# Create armature
bpy.ops.object.add(type='ARMATURE', enter_editmode=True)
armature = bpy.context.active_object
armature.name = "CharacterRig"
# Clear default bone
bpy.ops.armature.select_all(action='SELECT')
bpy.ops.armature.delete()
# Create bone hierarchy
bones = {}
# Root bone
bpy.ops.armature.bone_add()
root = bpy.context.active_bone
root.name = "Root"
root.head = (0, 0, 0)
root.tail = (0, 0, 0.2)
bones['root'] = root
# Spine
bpy.ops.armature.bone_add()
spine = bpy.context.active_bone
spine.name = "Spine"
spine.head = root.tail
spine.tail = (0, 0, parts['torso'].location.z)
spine.parent = root
bones['spine'] = spine
# Neck
bpy.ops.armature.bone_add()
neck = bpy.context.active_bone
neck.name = "Neck"
neck.head = spine.tail
neck.tail = (0, 0, parts['head'].location.z - 0.3)
neck.parent = spine
bones['neck'] = neck
# Head
bpy.ops.armature.bone_add()
head_bone = bpy.context.active_bone
head_bone.name = "Head"
head_bone.head = neck.tail
head_bone.tail = (0, 0, parts['head'].location.z + 0.3)
head_bone.parent = neck
bones['head_bone'] = head_bone
# Left arm chain
bpy.ops.armature.bone_add()
left_shoulder = bpy.context.active_bone
left_shoulder.name = "LeftShoulder"
left_shoulder.head = spine.tail
left_shoulder.tail = parts['left_arm'].location
left_shoulder.parent = spine
bones['left_shoulder'] = left_shoulder
bpy.ops.armature.bone_add()
left_elbow = bpy.context.active_bone
left_elbow.name = "LeftElbow"
left_elbow.head = left_shoulder.tail
left_elbow.tail = left_shoulder.tail + Vector((-0.6, 0, -0.3))
left_elbow.parent = left_shoulder
bones['left_elbow'] = left_elbow
# Right arm chain
bpy.ops.armature.bone_add()
right_shoulder = bpy.context.active_bone
right_shoulder.name = "RightShoulder"
right_shoulder.head = spine.tail
right_shoulder.tail = parts['right_arm'].location
right_shoulder.parent = spine
bones['right_shoulder'] = right_shoulder
bpy.ops.armature.bone_add()
right_elbow = bpy.context.active_bone
right_elbow.name = "RightElbow"
right_elbow.head = right_shoulder.tail
right_elbow.tail = right_shoulder.tail + Vector((0.6, 0, -0.3))
right_elbow.parent = right_shoulder
bones['right_elbow'] = right_elbow
# Left leg chain
bpy.ops.armature.bone_add()
left_hip = bpy.context.active_bone
left_hip.name = "LeftHip"
left_hip.head = (0, 0, parts['left_leg'].location.z + 0.4)
left_hip.tail = parts['left_leg'].location + Vector((0, 0, 0.3))
left_hip.parent = root
bones['left_hip'] = left_hip
bpy.ops.armature.bone_add()
left_knee = bpy.context.active_bone
left_knee.name = "LeftKnee"
left_knee.head = left_hip.tail
left_knee.tail = (0, 0, 0)
left_knee.parent = left_hip
bones['left_knee'] = left_knee
# Right leg chain
bpy.ops.armature.bone_add()
right_hip = bpy.context.active_bone
right_hip.name = "RightHip"
right_hip.head = (0, 0, parts['right_leg'].location.z + 0.4)
right_hip.tail = parts['right_leg'].location + Vector((0, 0, 0.3))
right_hip.parent = root
bones['right_hip'] = right_hip
bpy.ops.armature.bone_add()
right_knee = bpy.context.active_bone
right_knee.name = "RightKnee"
right_knee.head = right_hip.tail
right_knee.tail = (0, 0, 0)
right_knee.parent = right_hip
bones['right_knee'] = right_knee
# Set bones to pose mode
bpy.ops.object.mode_set(mode='OBJECT')
return armature, bones
def setup_ik_constraints(armature, bones):
"""Set up IK constraints for automatic limb positioning"""
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
# Create IK targets
ik_targets = {}
# Left hand IK
bpy.ops.object.empty_add(type='SPHERE', radius=0.1)
left_hand_target = bpy.context.active_object
left_hand_target.name = "LeftHand_IK"
left_hand_target.location = bones['left_elbow'].tail + Vector((-0.3, 0, -0.3))
ik_targets['left_hand'] = left_hand_target
# Right hand IK
bpy.ops.object.empty_add(type='SPHERE', radius=0.1)
right_hand_target = bpy.context.active_object
right_hand_target.name = "RightHand_IK"
right_hand_target.location = bones['right_elbow'].tail + Vector((0.3, 0, -0.3))
ik_targets['right_hand'] = right_hand_target
# Left foot IK
bpy.ops.object.empty_add(type='SPHERE', radius=0.1)
left_foot_target = bpy.context.active_object
left_foot_target.name = "LeftFoot_IK"
left_foot_target.location = bones['left_knee'].tail
ik_targets['left_foot'] = left_foot_target
# Right foot IK
bpy.ops.object.empty_add(type='SPHERE', radius=0.1)
right_foot_target = bpy.context.active_object
right_foot_target.name = "RightFoot_IK"
right_foot_target.location = bones['right_knee'].tail
ik_targets['right_foot'] = right_foot_target
# Add IK constraints to bones
pose_bones = armature.pose.bones
# Left elbow IK
left_elbow_constraint = pose_bones['LeftElbow'].constraints.new(type='IK')
left_elbow_constraint.target = left_hand_target
left_elbow_constraint.chain_count = 2
left_elbow_constraint.use_stretch = True
# Right elbow IK
right_elbow_constraint = pose_bones['RightElbow'].constraints.new(type='IK')
right_elbow_constraint.target = right_hand_target
right_elbow_constraint.chain_count = 2
right_elbow_constraint.use_stretch = True
# Left knee IK
left_knee_constraint = pose_bones['LeftKnee'].constraints.new(type='IK')
left_knee_constraint.target = left_foot_target
left_knee_constraint.chain_count = 2
left_knee_constraint.use_stretch = True
# Right knee IK
right_knee_constraint = pose_bones['RightKnee'].constraints.new(type='IK')
right_knee_constraint.target = right_foot_target
right_knee_constraint.chain_count = 2
right_knee_constraint.use_stretch = True
bpy.ops.object.mode_set(mode='OBJECT')
return ik_targets
def auto_weight_mesh(mesh_obj, armature):
"""Automatically weight paint a mesh to the armature"""
# Select mesh and armature
mesh_obj.select_set(True)
armature.select_set(True)
bpy.context.view_layer.objects.active = armature
# Create armature modifier
modifier = mesh_obj.modifiers.new(name="Armature", type='ARMATURE')
modifier.object = armature
modifier.use_vertex_groups = True
# Parent mesh to armature with automatic weights
bpy.ops.object.parent_set(type='ARMATURE_AUTO')
return modifier
def create_walk_cycle(armature, frames=60):
"""Create a basic walk cycle animation"""
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
# Set timeline
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = frames
pose_bones = armature.pose.bones
# Walk cycle keyframes
walk_frames = {
1: {
'LeftHip': 30, 'RightHip': -30,
'LeftKnee': 45, 'RightKnee': 0,
'LeftShoulder': -20, 'RightShoulder': 20,
'Spine': 5
},
15: {
'LeftHip': 0, 'RightHip': 0,
'LeftKnee': 20, 'RightKnee': 20,
'LeftShoulder': 0, 'RightShoulder': 0,
'Spine': 0
},
30: {
'LeftHip': -30, 'RightHip': 30,
'LeftKnee': 0, 'RightKnee': 45,
'LeftShoulder': 20, 'RightShoulder': -20,
'Spine': -5
},
45: {
'LeftHip': 0, 'RightHip': 0,
'LeftKnee': 20, 'RightKnee': 20,
'LeftShoulder': 0, 'RightShoulder': 0,
'Spine': 0
},
60: {
'LeftHip': 30, 'RightHip': -30,
'LeftKnee': 45, 'RightKnee': 0,
'LeftShoulder': -20, 'RightShoulder': 20,
'Spine': 5
}
}
# Animate the walk cycle
for frame, rotations in walk_frames.items():
bpy.context.scene.frame_set(frame)
for bone_name, rotation in rotations.items():
if bone_name in pose_bones:
bone = pose_bones[bone_name]
if 'Hip' in bone_name or 'Shoulder' in bone_name:
# Rotation around X axis
bone.rotation_euler = (math.radians(rotation), 0, 0)
elif 'Knee' in bone_name:
# Bend knee forward
bone.rotation_euler = (math.radians(rotation), 0, 0)
elif bone_name == 'Spine':
# Spine rotation
bone.rotation_euler = (0, 0, math.radians(rotation))
bone.keyframe_insert(data_path="rotation_euler", frame=frame)
# Animate root movement (forward motion)
for frame in range(1, frames + 1, 5):
bpy.context.scene.frame_set(frame)
root_bone = pose_bones['Root']
# Move forward 0.1 units per 5 frames
root_bone.location.y = (frame - 1) / 5 * 0.1
root_bone.keyframe_insert(data_path="location", frame=frame)
bpy.ops.object.mode_set(mode='OBJECT')
def create_facial_expressions(armature, mesh_obj):
"""Create facial expression controls using shape keys"""
# Add shape keys to head mesh
head_obj = None
for obj in bpy.context.scene.objects:
if obj.name == "Head":
head_obj = obj
break
if not head_obj:
return None
# Go to object mode
bpy.context.view_layer.objects.active = head_obj
bpy.ops.object.mode_set(mode='OBJECT')
# Add shape keys
head_obj.shape_key_add(name='Basis')
# Smile shape key
smile_key = head_obj.shape_key_add(name='Smile')
# Modify vertices for smile (simplified)
if hasattr(smile_key.data, 'foreach_set'):
# This would normally involve complex vertex manipulation
pass
# Frown shape key
frown_key = head_obj.shape_key_add(name='Frown')
# Create driver setup for facial expressions
# This would normally link bone rotations to shape key values
return head_obj.shape_keys
def create_animation_system():
"""Create a complete animation system with controls"""
print("Creating character animation system...")
# Create character mesh
parts = create_character_mesh()
# Create armature
armature, bones = create_armature(parts)
# Setup IK constraints
ik_targets = setup_ik_constraints(armature, bones)
# Apply automatic weights to all parts
for part_name, part_obj in parts.items():
auto_weight_mesh(part_obj, armature)
# Create walk cycle
create_walk_cycle(armature, frames=60)
# Create facial expressions
shape_keys = create_facial_expressions(armature, parts['head'])
# Add materials
for part_obj in parts.values():
mat = bpy.data.materials.new(name=f"Material_{part_obj.name}")
mat.diffuse_color = (0.8, 0.6, 0.4, 1.0) # Skin color
part_obj.data.materials.append(mat)
return {
'armature': armature,
'parts': parts,
'ik_targets': ik_targets,
'shape_keys': shape_keys
}
def main():
"""Main function to demonstrate animation and rigging automation"""
print("=== Animation and Rigging Automation ===")
# Clear scene
clear_scene()
# Create animation system
animation_data = create_animation_system()
# Add lighting
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
sun = bpy.context.active_object
sun.data.energy = 3.0
bpy.ops.object.light_add(type='AREA', location=(-3, -3, 5))
area = bpy.context.active_object
area.data.energy = 1.5
# Add camera
bpy.ops.object.camera_add(location=(8, -8, 4))
camera = bpy.context.active_object
direction = -camera.location
rot_quat = direction.to_track_quat('-Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
bpy.context.scene.camera = camera
print("Animation system created successfully!")
print("- Play animation to see walk cycle")
print("- Move IK targets (empty objects) to control limbs")
print("- Use shape keys for facial expressions")
if __name__ == "__main__":
main()
💻 Material and Texturing Automation python
🟡 intermediate
⭐⭐⭐⭐
Advanced material creation, procedural textures, and texture mapping automation
⏱️ 30 min
🏷️ blender, python, 3d, materials, texturing
Prerequisites:
Blender materials, Node editor, Texture mapping
# Blender Material and Texturing Automation
# Procedural materials, texture generation, and material management
import bpy
import math
import random
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
def clear_scene():
"""Clear all objects from the current scene"""
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
def create_test_objects():
"""Create test objects to apply materials to"""
objects = {}
# Cube
bpy.ops.mesh.primitive_cube_add(size=2, location=(-4, 0, 0))
objects['cube'] = bpy.context.active_object
objects['cube'].name = "TestCube"
# Sphere
bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 0))
objects['sphere'] = bpy.context.active_object
objects['sphere'].name = "TestSphere"
# Cylinder
bpy.ops.mesh.primitive_cylinder_add(radius=1, height=3, location=(4, 0, 0))
objects['cylinder'] = bpy.context.active_object
objects['cylinder'].name = "TestCylinder"
# Plane
bpy.ops.mesh.primitive_plane_add(size=6, location=(0, -4, 0))
objects['plane'] = bpy.context.active_object
objects['plane'].name = "TestPlane"
return objects
def create_procedural_metal_material(name="ProceduralMetal"):
"""Create a procedural metal material with nodes"""
# Create material
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
# Get default nodes
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# Clear default nodes
nodes.clear()
# Create output node
output = nodes.new(type='ShaderNodeOutputMaterial')
output.location = (400, 0)
# Create principled BSDF
principled = nodes.new(type='ShaderNodeBsdfPrincipled')
principled.location = (200, 0)
# Create noise texture for scratches
noise = nodes.new(type='ShaderNodeTexNoise')
noise.location = (-200, 100)
noise.inputs['Scale'].default_value = 50.0
noise.inputs['Detail'].default_value = 8.0
noise.inputs['Roughness'].default_value = 0.8
# Create color ramp for scratch variation
color_ramp = nodes.new(type='ShaderNodeValToRGB')
color_ramp.location = (0, 100)
# Create metallic gradient
metallic_gradient = nodes.new(type='ShaderNodeTexGradient')
metallic_gradient.location = (-200, -100)
metallic_gradient.gradient_type = 'LINEAR'
# Create roughness variation
roughness_noise = nodes.new(type='ShaderNodeTexNoise')
roughness_noise.location = (-200, -300)
roughness_noise.inputs['Scale'].default_value = 10.0
roughness_noise.inputs['Detail'].default_value = 4.0
# Create math nodes for combining
roughness_math = nodes.new(type='ShaderNodeMath')
roughness_math.location = (0, -300)
roughness_math.operation = 'MULTIPLY'
roughness_math.inputs[1].default_value = 0.3
# Create bump for surface detail
bump = nodes.new(type='ShaderNodeBump')
bump.location = (0, -500)
bump.inputs['Strength'].default_value = 0.05
# Connect nodes
links.new(noise.outputs['Fac'], color_ramp.inputs['Fac'])
links.new(color_ramp.outputs['Color'], principled.inputs['Base Color'])
links.new(metallic_gradient.outputs['Color'], principled.inputs['Metallic'])
links.new(roughness_noise.outputs['Fac'], roughness_math.inputs[0])
links.new(roughness_math.outputs['Value'], principled.inputs['Roughness'])
links.new(noise.outputs['Fac'], bump.inputs['Height'])
links.new(bump.outputs['Normal'], principled.inputs['Normal'])
links.new(principled.outputs['BSDF'], output.inputs['Surface'])
return mat
def create_wood_material(name="ProceduralWood"):
"""Create a procedural wood material with grain patterns"""
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
nodes.clear()
# Output node
output = nodes.new(type='ShaderNodeOutputMaterial')
output.location = (600, 0)
# Principled BSDF
principled = nodes.new(type='ShaderNodeBsdfPrincipled')
principled.location = (400, 0)
# Wood ring texture
rings = nodes.new(type='ShaderNodeTexVoronoi')
rings.location = (-200, 100)
rings.voronoi_dimensions = '1D'
rings.feature = 'DISTANCE_TO_EDGE'
rings.scale = 0.2
# Color ramp for wood color
wood_colors = nodes.new(type='ShaderNodeValToRGB')
wood_colors.location = (0, 100)
# Light brown to dark brown
wood_colors.color_ramp.elements[0].color = (0.6, 0.4, 0.2, 1.0)
wood_colors.color_ramp.elements[1].color = (0.3, 0.2, 0.1, 1.0)
# Wood grain texture
grain = nodes.new(type='ShaderNodeTexNoise')
grain.location = (-200, -100)
grain.scale = 50.0
grain.detail = 2.0
grain.distortion = 0.1
# Combine wood patterns
grain_strength = nodes.new(type='ShaderNodeMath')
grain_strength.location = (0, -100)
grain_strength.operation = 'MULTIPLY'
grain_strength.inputs[1].default_value = 0.2
# Combine rings and grain
wood_mix = nodes.new(type='ShaderNodeMixRGB')
wood_mix.location = (200, 0)
wood_mix.blend_type = 'OVERLAY'
# Roughness variation
roughness = nodes.new(type='ShaderNodeMath')
roughness.location = (200, -200)
roughness.operation = 'ADD'
roughness.inputs[1].default_value = 0.8
# Bump for grain texture
wood_bump = nodes.new(type='ShaderNodeBump')
wood_bump.location = (200, -400)
wood_bump.inputs['Strength'].default_value = 0.02
# Connect nodes
links.new(rings.outputs['Distance'], wood_colors.inputs['Fac'])
links.new(grain.outputs['Fac'], grain_strength.inputs[0])
links.new(wood_colors.outputs['Color'], wood_mix.inputs['Color1'])
links.new(grain_strength.outputs['Value'], wood_mix.inputs['Color2'])
links.new(wood_mix.outputs['Color'], principled.inputs['Base Color'])
links.new(grain.outputs['Fac'], roughness.inputs[0])
links.new(roughness.outputs['Value'], principled.inputs['Roughness'])
links.new(grain.outputs['Fac'], wood_bump.inputs['Height'])
links.new(wood_bump.outputs['Normal'], principled.inputs['Normal'])
links.new(principled.outputs['BSDF'], output.inputs['Surface'])
return mat
def create_fabric_material(name="ProceduralFabric"):
"""Create a procedural fabric material with weave patterns"""
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
nodes.clear()
# Output node
output = nodes.new(type='ShaderNodeOutputMaterial')
output.location = (600, 0)
# Principled BSDF
principled = nodes.new(type='ShaderNodeBsdfPrincipled')
principled.location = (400, 0)
# Fabric weave pattern using wave texture
weave_x = nodes.new(type='ShaderNodeTexWave')
weave_x.location = (-400, 100)
weave_x.wave_type = 'SAW'
weave_x.scale = 20.0
weave_x.direction = 'X'
weave_y = nodes.new(type='ShaderNodeTexWave')
weave_y.location = (-400, 0)
weave_y.wave_type = 'SAW'
weave_y.scale = 20.0
weave_y.direction = 'Y'
# Combine weave patterns
weave_combine = nodes.new(type='ShaderNodeMath')
weave_combine.location = (-200, 50)
weave_combine.operation = 'MULTIPLY'
# Add noise for fabric texture
fabric_noise = nodes.new(type='ShaderNodeTexNoise')
fabric_noise.location = (-200, -100)
fabric_noise.scale = 100.0
fabric_noise.detail = 1.0
# Color ramp for fabric color
fabric_colors = nodes.new(type='ShaderNodeValToRGB')
fabric_colors.location = (0, 0)
fabric_colors.color_ramp.elements[0].color = (0.4, 0.3, 0.6, 1.0) # Purple
fabric_colors.color_ramp.elements[1].color = (0.6, 0.5, 0.8, 1.0) # Light purple
# Subsurface scattering for fabric look
sss = nodes.new(type='ShaderNodeSubsurfaceScattering')
sss.location = (200, -200)
# Combine for final material
fabric_mix = nodes.new(type='ShaderNodeMixShader')
fabric_mix.location = (400, 0)
# Connect nodes
links.new(weave_x.outputs['Fac'], weave_combine.inputs[0])
links.new(weave_y.outputs['Fac'], weave_combine.inputs[1])
links.new(weave_combine.outputs['Value'], fabric_colors.inputs['Fac'])
links.new(fabric_colors.outputs['Color'], principled.inputs['Base Color'])
links.new(fabric_noise.outputs['Fac'], principled.inputs['Roughness'])
links.new(principled.outputs['BSDF'], fabric_mix.inputs[1])
links.new(sss.outputs['BSSRDF'], fabric_mix.inputs[2])
links.new(fabric_mix.outputs['Shader'], output.inputs['Surface'])
return mat
def create_marble_material(name="ProceduralMarble"):
"""Create a procedural marble material with veins"""
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
nodes.clear()
# Output node
output = nodes.new(type='ShaderNodeOutputMaterial')
output.location = (600, 0)
# Principled BSDF
principled = nodes.new(type='ShaderNodeBsdfPrincipled')
principled.location = (400, 0)
# Marble veins using musgrave texture
marble = nodes.new(type='ShaderNodeTexMusgrave')
marble.location = (-200, 0)
marble.musgrave_type = 'RIDGED_MULTIFRACTAL'
marble.scale = 2.0
marble.detail = 8.0
marble.dimension = 1.5
# Wave texture for additional variation
marble_wave = nodes.new(type='ShaderNodeTexWave')
marble_wave.location = (-400, 100)
marble_wave.scale = 1.0
marble_wave.detail = 0.0
marble_wave.distortion = 0.5
# Combine marble patterns
marble_mix = nodes.new(type='ShaderNodeMath')
marble_mix.location = (0, 0)
marble_mix.operation = 'ADD'
# Color ramp for marble colors
marble_colors = nodes.new(type='ShaderNodeValToRGB')
marble_colors.location = (200, 0)
marble_colors.color_ramp.elements[0].color = (0.95, 0.95, 0.95, 1.0) # White
marble_colors.color_ramp.elements[1].color = (0.1, 0.1, 0.1, 1.0) # Black
# Glass shader for transparency
glass = nodes.new(type='ShaderNodeBsdfGlass')
glass.location = (200, -200)
glass.inputs['IOR'].default_value = 1.5
glass.inputs['Roughness'].default_value = 0.1
# Mix shaders
shader_mix = nodes.new(type='ShaderNodeMixShader')
shader_mix.location = (400, 0)
# Connect nodes
links.new(marble_wave.outputs['Color'], marble.inputs['Vector'])
links.new(marble.outputs['Fac'], marble_mix.inputs[0])
links.new(marble_mix.outputs['Value'], marble_colors.inputs['Fac'])
links.new(marble_colors.outputs['Color'], principled.inputs['Base Color'])
links.new(principled.outputs['BSDF'], shader_mix.inputs[1])
links.new(glass.outputs['BSDF'], shader_mix.inputs[2])
links.new(marble.outputs['Fac'], shader_mix.inputs['Fac'])
links.new(shader_mix.outputs['Shader'], output.inputs['Surface'])
return mat
def create_pbr_texture_material(image_path, name="PBRMaterial"):
"""Create a PBR material from texture images"""
# This would normally load from actual image files
# For demonstration, we'll create placeholder nodes
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# Get existing principled BSDF
principled = nodes.get('Principled BSDF')
# Create texture nodes (these would normally load actual images)
base_color_tex = nodes.new(type='ShaderNodeTexImage')
base_color_tex.name = "BaseColorTexture"
base_color_tex.location = (-300, 100)
# base_color_tex.image = bpy.data.images.load(f"{image_path}_base_color.png")
normal_tex = nodes.new(type='ShaderNodeTexImage')
normal_tex.name = "NormalTexture"
normal_tex.location = (-300, 0)
# normal_tex.image = bpy.data.images.load(f"{image_path}_normal.png")
roughness_tex = nodes.new(type='ShaderNodeTexImage')
roughness_tex.name = "RoughnessTexture"
roughness_tex.location = (-300, -100)
# roughness_tex.image = bpy.data.images.load(f"{image_path}_roughness.png")
metallic_tex = nodes.new(type='ShaderNodeTexImage')
metallic_tex.name = "MetallicTexture"
metallic_tex.location = (-300, -200)
# metallic_tex.image = bpy.data.images.load(f"{image_path}_metallic.png")
# Normal map node
normal_map = nodes.new(type='ShaderNodeNormalMap')
normal_map.location = (-100, 0)
# Separate color channels
separate_roughness = nodes.new(type='ShaderNodeSeparateColor')
separate_roughness.location = (-100, -100)
separate_roughness.mode = 'RGB'
separate_metallic = nodes.new(type='ShaderNodeSeparateColor')
separate_metallic.location = (-100, -200)
separate_metallic.mode = 'RGB'
# Connect nodes
links.new(base_color_tex.outputs['Color'], principled.inputs['Base Color'])
links.new(normal_tex.outputs['Color'], normal_map.inputs['Color'])
links.new(normal_map.outputs['Normal'], principled.inputs['Normal'])
links.new(roughness_tex.outputs['Color'], separate_roughness.inputs['Color'])
links.new(separate_roughness.outputs['Blue'], principled.inputs['Roughness'])
links.new(metallic_tex.outputs['Color'], separate_metallic.inputs['Color'])
links.new(separate_metallic.outputs['Blue'], principled.inputs['Metallic'])
return mat
def apply_uv_mapping(obj, projection_type='CUBE'):
"""Apply UV mapping to an object"""
bpy.context.view_layer.objects.active = obj
bpy.ops.object.mode_set(mode='EDIT')
# Select all faces
bpy.ops.mesh.select_all(action='SELECT')
# Apply UV mapping
if projection_type == 'CUBE':
bpy.ops.uv.cube_project()
elif projection_type == 'SPHERE':
bpy.ops.uv.sphere_project()
elif projection_type == 'CYLINDER':
bpy.ops.uv.cylinder_project()
else: # SMART
bpy.ops.uv.smart_project(angle_limit=66.0, island_margin=0.0)
bpy.ops.object.mode_set(mode='OBJECT')
return obj.data.uv_layers.active
def create_material_library():
"""Create a library of procedural materials"""
materials = {}
# Create different material types
materials['metal'] = create_procedural_metal_material("SteelMetal")
materials['wood'] = create_wood_material("OakWood")
materials['fabric'] = create_fabric_material("VelvetFabric")
materials['marble'] = create_marble_material("WhiteMarble")
# Add variations
materials['gold_metal'] = create_procedural_metal_material("GoldMetal")
materials['dark_wood'] = create_wood_material("DarkWood")
materials['denim'] = create_fabric_material("DenimFabric")
return materials
def apply_materials_to_objects(objects, materials):
"""Apply materials to objects with appropriate UV mapping"""
# Apply UV mapping
apply_uv_mapping(objects['cube'], 'CUBE')
apply_uv_mapping(objects['sphere'], 'SPHERE')
apply_uv_mapping(objects['cylinder'], 'CYLINDER')
apply_uv_mapping(objects['plane'], 'SMART')
# Apply materials
objects['cube'].data.materials.append(materials['metal'])
objects['sphere'].data.materials.append(materials['marble'])
objects['cylinder'].data.materials.append(materials['wood'])
objects['plane'].data.materials.append(materials['fabric'])
print("Materials applied to objects with UV mapping")
def create_material_preview():
"""Create a material preview scene with proper lighting"""
# Create HDRI lighting setup
bpy.ops.object.light_add(type='SUN', location=(5, 5, 10))
sun = bpy.context.active_object
sun.data.energy = 5.0
bpy.ops.object.light_add(type='AREA', location=(-3, -3, 5))
area = bpy.context.active_object
area.data.energy = 2.0
area.data.size = 3.0
bpy.ops.object.light_add(type='AREA', location=(0, 3, 3))
fill = bpy.context.active_object
fill.data.energy = 1.0
fill.data.size = 2.0
# Setup camera
bpy.ops.object.camera_add(location=(8, -8, 4))
camera = bpy.context.active_object
direction = -camera.location
rot_quat = direction.to_track_quat('-Z', 'Y')
camera.rotation_euler = rot_quat.to_euler()
bpy.context.scene.camera = camera
# Setup render settings
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.samples = 128
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
def main():
"""Main function to demonstrate material and texturing automation"""
print("=== Material and Texturing Automation ===")
# Clear scene
clear_scene()
# Create test objects
objects = create_test_objects()
# Create material library
materials = create_material_library()
print(f"Created {len(materials)} procedural materials")
# Apply materials to objects
apply_materials_to_objects(objects, materials)
# Create preview setup
create_material_preview()
print("Material system setup complete!")
print("- Materials: Metal, Wood, Fabric, Marble")
print("- Each material uses procedural nodes")
print("- Objects have UV mapping applied")
print("- Render with F12 to preview materials")
if __name__ == "__main__":
main()