🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples de Blender Scripting
Exemples de scripting Blender Python pour la modélisation 3D, l'animation, la création d'actifs et l'automatisation des flux de travail
💻 Blender Hello World python
🟢 simple
⭐⭐
Configuration de base du scripting Blender avec création d'objets et fondamentaux de manipulation de scène
⏱️ 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()
💻 Génération de Géométrie Procedurale python
🟡 intermediate
⭐⭐⭐⭐
Modélisation procédurale avancée avec fonctions mathématiques, objets paramétriques et géométrie complexe
⏱️ 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()
💻 Automatisation d'Animation et Rigging python
🟡 intermediate
⭐⭐⭐⭐
Système d'animation automatisé avec création de squelettes, weighting et animations complexes
⏱️ 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()
💻 Automatisation de Matériaux et Textures python
🟡 intermediate
⭐⭐⭐⭐
Création avancée de matériaux, textures procédurales et automatisation de mapping de textures
⏱️ 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()