Skill di rigging procedurale per Blender. Armature con Bone Roll corretto, FK/IK dualità, weight painting algoritmico (distance-based), Shape Keys con Driver biomeccanici, Socket System (CHILD_OF), pelle su scheletro con Shrinkwrap+Solidify, animazione procedurale da codice. Usa questa skill quando: devi animare un oggetto articolato, creare uno scheletro, fare deformazioni biomeccaniche, o collegare oggetti a ossa.
Scanned 9/22/2026
npx -y skills add MAX-786/claude-3d-harness --skill blender-rig --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Blender Rig?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/max-786-blender-rig)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
description: >
Skill di rigging procedurale per Blender. Armature con Bone Roll corretto,
FK/IK dualità, weight painting algoritmico (distance-based), Shape Keys con
Driver biomeccanici, Socket System (CHILD_OF), pelle su scheletro con
Shrinkwrap+Solidify, animazione procedurale da codice.
Usa questa skill quando: devi animare un oggetto articolato, creare uno
scheletro, fare deformazioni biomeccaniche, o collegare oggetti a ossa.
allowed-tools:
- Bash
- Read
- Write
- mcp__Blender__execute_blender_code
- mcp__Blender__get_screenshot_of_window_as_image
- mcp__Blender__render_viewport_to_path
- mcp__Blender__get_objects_summary
- mcp__Blender__get_object_detail_summary
---
# Skill: Blender Procedural Rigging
Sei un esperto di rigging anatomico e procedurale in Blender.
Costruisci scheletri corretti, deformazioni biomeccaniche e animazioni da codice.
---
## Connessione — MCP (predefinito)
```python
mcp__Blender__execute_blender_code(code="""
import bpy, bmesh, math
from mathutils import Vector, Matrix, Quaternion
# ... codice ...
result = {"ok": True}
""")
mcp__Blender__get_screenshot_of_window_as_image()
mcp__Blender__render_viewport_to_path(output_path="<JOB_DIR>/rig_preview.png")
```
---
## IL PRINCIPIO FONDAMENTALE — Bone Roll e Frame Locali
Ogni osso in Blender ha un **frame locale** (assi X, Y, Z):
- **Y locale**: direzione testa→coda (sempre, non modificabile)
- **X locale**: determinato dal **Bone Roll**
- **Z locale**: B = Y × X
**Bone Roll = 0** significa che l'asse X locale è allineato al mondo.
Questo è **fondamentale** per catene articolate: garantisce che ruotando
sull'asse X (flessione) le falangi/vertebre si chiudano senza torsioni strane.
```
Roll sbagliato → l'osso ruota su un asse obliquo → movimenti strani
Roll = 0 → flessione sull'asse X = chiusura anatomica corretta
```
**Come verificare:**
```python
# In Edit Mode — controlla il roll di ogni osso
for bone in arm.data.edit_bones:
print(f"{bone.name}: roll = {math.degrees(bone.roll):.2f}°")
# Se non è 0° (o 90° per assi specifici), correggilo
```
---
## ARMATURE — Creazione e Convenzioni
```python
import bpy, math
from mathutils import Vector
def create_armature(name="Rig"):
"""
Crea un'armatura vuota pronta per ricevere ossa.
Ritorna (arm_obj, armature).
"""
bpy.ops.object.armature_add(enter_editmode=True,
align='WORLD', location=(0,0,0))
arm_obj = bpy.context.active_object
arm_obj.name = name
armature = arm_obj.data
armature.name = name + "_Armature"
# Rimuovi l'osso di default
armature.edit_bones.remove(armature.edit_bones[0])
return arm_obj, armature
def add_bone(armature, name, head, tail, parent=None,
connected=False, roll=0.0, layer=0):
"""
Aggiunge un osso all'armatura (deve essere in Edit Mode).
head, tail : tuple (x,y,z) in world space
parent : nome dell'osso padre (stringa) o None
connected : se True, la testa si attacca alla coda del padre
roll : rotazione dell'asse X locale in radianti (0 = allineato al mondo)
NOMENCLATURA CONSIGLIATA:
- Lato: _L (sinistra), _R (destra)
- Segmento: Palm, Proximal, Intermediate, Distal
- Root: osso radice (non deforma, ancora il rig)
- DEF_: ossa che deformano la mesh (Deform bones)
- CTRL_: ossa di controllo (non deformano)
- MCH_: ossa meccanismo (intermedie, non visibili)
"""
bone = armature.edit_bones.new(name)
bone.head = Vector(head)
bone.tail = Vector(tail)
bone.roll = roll
bone.use_deform = True
if parent:
bone.parent = armature.edit_bones[parent]
bone.use_connect = connected
return bone
# ── Esempio: dito indice ──────────────────────────────────────────────
def create_finger(armature, name, base_y, segments=None):
"""
Crea una catena di ossa per un dito.
segments: lista di (nome_suffisso, y_start, y_end)
Se None, usa proporzioni standard (Proximal 40%, Intermediate 30%, Distal 30%).
"""
if segments is None:
segments = [
("Palm", 0.0, -2.0),
("Proximal", -2.0, -4.0),
("Intermediate",-4.0, -5.5),
("Distal", -5.5, -6.5),
]
prev = None
for i, (seg, y0, y1) in enumerate(segments):
bname = f"{name}_{seg}"
bone = add_bone(armature, bname,
head=(0, y0 + base_y, 0),
tail=(0, y1 + base_y, 0),
parent=prev, connected=(i > 0),
roll=0.0) # ← ROLL = 0: asse X orizzontale
prev = bname
```
---
## FK / IK — DUALITÀ
**FK (Forward Kinematics)**: ruota ogni osso manualmente dalla radice alla punta.
Preciso, prevedibile, ma lento per animazioni complesse.
**IK (Inverse Kinematics)**: sposti la punta, Blender calcola gli angoli delle giunzioni.
Rapido per posare, ma meno preciso. Richiede un Pole Target per evitare flipping del ginocchio/gomito.
```python
def setup_ik(arm_obj, tip_bone_name, chain_count=3,
pole_target=None, pole_bone=None, pole_angle=0):
"""
Aggiunge un vincolo IK all'osso 'tip_bone_name'.
Deve essere chiamato in POSE mode.
chain_count : numero di ossa nella catena IK (2=gomito, 3=dito, 4=gamba)
pole_target : oggetto Empty usato come Pole Target (evita il flip del gomito)
pole_angle : angolo di offset del pole in gradi (tipico: 0° o 90°)
Esempio — gamba con knee target:
# 1. Crea Empty per il knee
bpy.ops.object.empty_add(location=(0, -2, 0.5))
knee = bpy.context.active_object
knee.name = "Knee_Target"
# 2. Attiva pose mode sull'armatura
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='POSE')
# 3. Applica IK
setup_ik(arm_obj, "Shin", chain_count=2,
pole_target=knee, pole_angle=0)
"""
bpy.context.view_layer.objects.active = arm_obj
if bpy.context.mode != 'POSE':
bpy.ops.object.mode_set(mode='POSE')
pbone = arm_obj.pose.bones[tip_bone_name]
ik = pbone.constraints.new('IK')
ik.chain_count = chain_count
if pole_target:
ik.pole_target = pole_target
ik.pole_subtarget = pole_bone or ""
ik.pole_angle = math.radians(pole_angle)
return ik
def setup_ik_target(arm_obj, tip_bone_name, target_obj=None, chain_count=3):
"""
Alternativa: usa un Empty come target IK (la punta segue l'Empty).
Crea automaticamente l'Empty se target_obj è None.
"""
if target_obj is None:
tip_world = arm_obj.pose.bones[tip_bone_name].tail
bpy.ops.object.empty_add(location=arm_obj.matrix_world @ tip_world)
target_obj = bpy.context.active_object
target_obj.name = f"IK_{tip_bone_name}_Target"
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='POSE')
pbone = arm_obj.pose.bones[tip_bone_name]
ik = pbone.constraints.new('IK')
ik.target = target_obj
ik.chain_count = chain_count
return ik, target_obj
def toggle_ik_fk(arm_obj, bone_names, use_ik=True):
"""
Commuta tra IK e FK per un gruppo di ossa.
IK: abilita vincolo IK, disabilita mute su FK
FK: disabilita vincolo IK (mute=True)
Utile per switch IK/FK durante l'animazione.
"""
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='POSE')
for bn in bone_names:
for c in arm_obj.pose.bones[bn].constraints:
if c.type == 'IK':
c.mute = not use_ik
```
---
## WEIGHT PAINTING ALGORITMICO
Il weight painting procedurale assegna pesi ai vertex group in base
alla distanza da punti di controllo. Più preciso del painting manuale,
100% riproducibile, zero artefatti di painting.
### Smoothstep interpolator
```python
def smoothstep(x):
"""Interpolazione cubica [0,1] → [0,1]. Derivata zero agli estremi."""
x = max(0.0, min(1.0, x))
return x * x * (3 - 2 * x)
def smootherstep(x):
"""Quintica — transizione ancora più morbida. Per blend tra giunzioni."""
x = max(0.0, min(1.0, x))
return x * x * x * (x * (x * 6 - 15) + 10)
```
### Weight painting per coordinata (catene lineari)
```python
def weight_paint_by_coord(mesh_obj, bone_ranges, coord_axis='Y',
blend_zone=0.3):
"""
Assegna pesi ai vertex group in base alla coordinata di ogni vertice.
Ideale per catene lineari (dito, colonna, arto).
bone_ranges : dict {nome_vg: (coord_min, coord_max)}
la coordinata è in LOCAL SPACE del mesh_obj
coord_axis : 'X', 'Y', o 'Z'
blend_zone : frazione del range usata per il blend tra ossa adiacenti [0-0.5]
Esempio (dito lungo Y, da 0 a -6.5):
weight_paint_by_coord(skin, {
"Palm": ( 0.0, -2.0),
"Proximal": (-2.0, -4.0),
"Intermediate":(-4.0, -5.5),
"Distal": (-5.5, -6.5),
}, coord_axis='Y', blend_zone=0.3)
"""
axis_idx = {'X': 0, 'Y': 1, 'Z': 2}[coord_axis]
# Crea vertex group se non esistono
vgs = {}
for name in bone_ranges:
vg = mesh_obj.vertex_groups.get(name)
if vg is None:
vg = mesh_obj.vertex_groups.new(name=name)
vg.add(list(range(len(mesh_obj.data.vertices))), 0.0, 'REPLACE')
vgs[name] = vg
names = list(bone_ranges.keys())
ranges = list(bone_ranges.values())
for v in mesh_obj.data.vertices:
coord = v.co[axis_idx]
for i, (name, (cmin, cmax)) in enumerate(zip(names, ranges)):
span = cmax - cmin if cmax != cmin else 1e-6
blend = abs(span) * blend_zone
if min(cmin, cmax) <= coord <= max(cmin, cmax):
# Dentro il range: peso 1 al centro, blend agli estremi
t = (coord - cmin) / span
w = 1.0
# Blend con l'osso precedente (inizio range)
if i > 0 and abs(blend) > 1e-8:
fade_in = abs((coord - cmin) / blend)
if fade_in < 1.0:
w = min(w, smoothstep(fade_in))
# Osso precedente prende il complemento
vgs[names[i-1]].add([v.index],
(1.0 - smoothstep(fade_in)), 'ADD')
# Blend con l'osso successivo (fine range)
if i < len(names)-1 and abs(blend) > 1e-8:
fade_out = abs((cmax - coord) / blend)
if fade_out < 1.0:
w = min(w, smoothstep(fade_out))
vgs[names[i+1]].add([v.index],
(1.0 - smoothstep(fade_out)), 'ADD')
if w > 0:
vgs[name].add([v.index], w, 'ADD')
### Weight painting per distanza da punto 3D
def weight_paint_by_distance(mesh_obj, vg_name, center_local,
max_dist, falloff='SMOOTH'):
"""
Assegna pesi in base alla distanza da un punto 3D in spazio locale.
Ideale per aree di influenza circolari (nocca, spalla, muscolatura).
center_local : Vector in coordinate locali del mesh
max_dist : distanza oltre cui il peso è 0
falloff : 'LINEAR', 'SMOOTH' (smoothstep), 'SHARP' (quadratica)
Esempio (palpebra — bordo dell'apertura):
eye_center = Vector((0, -0.5, 0.35))
weight_paint_by_distance(eyelid, "UpperLid", eye_center,
max_dist=0.9, falloff='SMOOTH')
"""
vg = mesh_obj.vertex_groups.get(vg_name)
if vg is None:
vg = mesh_obj.vertex_groups.new(name=vg_name)
center = Vector(center_local)
for v in mesh_obj.data.vertices:
dist = (v.co - center).length
t = max(0.0, 1.0 - dist / max_dist)
if falloff == 'SMOOTH':
w = smoothstep(t)
elif falloff == 'SHARP':
w = t * t
else: # LINEAR
w = t
if w > 0.001:
vg.add([v.index], w, 'REPLACE')
```
---
## SHAPE KEYS + DRIVER — Biomeccanica Procedurale
I Shape Key + Driver creano deformazioni reattive: la nocca si solleva
quando il dito si piega, l'occhio si gonfia quando si chiude, il muscolo
si contrae quando l'osso ruota.
```python
def add_shape_key_with_driver(mesh_obj, key_name, driver_bone,
arm_obj, transform='ROT_X',
expression="abs(rot) / 1.5",
var_name="rot"):
"""
Crea uno Shape Key con Driver collegato alla rotazione di un osso.
key_name : nome della shape key (es: "Knuckle_Bend")
driver_bone : nome dell'osso che guida la deformazione
arm_obj : l'oggetto armatura
transform : 'ROT_X' | 'ROT_Y' | 'ROT_Z' | 'LOC_X' | 'SCALE_X' ecc.
expression : espressione Python del driver (var_name è la variabile)
Ritorna: la shape key (aggiungi vertici spostati dopo questa chiamata)
Esempio completo (nocca che si solleva quando il dito si piega):
sk = add_shape_key_with_driver(skin, "Knuckle_Bend", "Proximal",
arm_obj, 'ROT_X',
"abs(rot) / 1.5")
# Poi sposta i vertici della nocca nella sk.data:
for i, v in enumerate(skin.data.vertices):
if is_near_knuckle(v.co):
influence = knuckle_weight(v.co)
sk.data[i].co.z += 0.3 * influence
"""
# Assicurati che esista la Basis key
if not mesh_obj.data.shape_keys:
mesh_obj.shape_key_add(name="Basis", from_mix=False)
sk = mesh_obj.shape_key_add(name=key_name, from_mix=False)
sk.value = 0.0
# Aggiunge il Driver
fc = sk.driver_add("value")
driver = fc.driver
driver.type = 'SCRIPTED'
var = driver.variables.new()
var.name = var_name
var.type = 'TRANSFORMS'
t = var.targets[0]
t.id = arm_obj
t.bone_target = driver_bone
t.transform_type = transform
t.transform_space = 'LOCAL_SPACE'
driver.expression = expression
return sk
def deform_knuckle(mesh_obj, joint_y, influence_radius=0.8,
lift_z=0.3, compress_z=0.4):
"""
Applica la deformazione della nocca a una shape key già creata.
Chiama questa DOPO add_shape_key_with_driver.
joint_y : coordinata Y del giunto (in local space)
influence_radius: raggio di influenza della nocca
lift_z : quanto si solleva la nocca superiore
compress_z : quanto si comprime l'interno del giunto
Il metodo identifica automaticamente:
- vertici sopra il giunto (nocca) → si sollevano (+z)
- vertici sotto il giunto (palmo) → si comprimono (verso +z)
"""
sk = mesh_obj.data.shape_keys.key_blocks[-1] # l'ultima shape key
for i, v in enumerate(mesh_obj.data.vertices):
dist = abs(v.co.y - joint_y)
if dist < influence_radius:
influence = smoothstep(1.0 - dist / influence_radius)
if v.co.z > 0: # parte superiore → nocca
sk.data[i].co.z += lift_z * influence
sk.data[i].co.y += 0.2 * influence
else: # parte inferiore → compressione
sk.data[i].co.z += compress_z * influence
```
---
## SOCKET SYSTEM — Collegare Oggetti a Ossa
Il Socket System usa il vincolo `CHILD_OF` per ancorare oggetti a ossa.
Permette di attaccare armi, attrezzi, oggetti a una mano/braccio.
```python
def socket_attach(mesh_obj, arm_obj, bone_name,
local_offset=(0,0,0), local_rotation=(0,0,0)):
"""
Attacca mesh_obj all'osso bone_name tramite vincolo CHILD_OF.
local_offset : posizione dell'oggetto in coordinate LOCALI dell'osso
local_rotation : rotazione in gradi (Euler XYZ)
MATEMATICA DEL VINCOLO:
M_world_child = M_world_bone × M_offset
Il CHILD_OF sincronizza automaticamente questa equazione.
Esempio (spada ancorata al palmo):
socket_attach(sword, hand_rig, "Palm",
local_offset=(0, -3.5, -0.6),
local_rotation=(0, 0, 0))
Esempio (scudo ancorato al braccio sinistro):
socket_attach(shield, body_rig, "Forearm_L",
local_offset=(0, -1.0, 0.1),
local_rotation=(0, 90, 0))
"""
c = mesh_obj.constraints.new('CHILD_OF')
c.target = arm_obj
c.subtarget = bone_name
# Offset locale rispetto all'osso
mesh_obj.location = Vector(local_offset)
mesh_obj.rotation_euler = tuple(math.radians(r) for r in local_rotation)
# Calcola l'inverse matrix per il vincolo
bpy.context.view_layer.objects.active = mesh_obj
bpy.ops.constraint.childof_set_inverse(
constraint=c.name, owner='OBJECT')
return c
def socket_detach(mesh_obj, bone_name=None):
"""Rimuove tutti i vincoli CHILD_OF (o solo quello verso bone_name)."""
for c in list(mesh_obj.constraints):
if c.type == 'CHILD_OF':
if bone_name is None or c.subtarget == bone_name:
mesh_obj.constraints.remove(c)
```
---
## PELLE BIOMECCANICA — Shrinkwrap + Solidify
Tecnica per creare pelle che avvolge uno scheletro curvo:
1. Crea una mesh di partenza dalla forma generale (sfera, cilindro)
2. Ritaglia le aperture (occhio a mandorla, bocca, ecc.) in Edit Mode
3. Shrinkwrap: la mesh si "avvolge" sull'oggetto sottostante
4. Solidify: aggiunge spessore
5. Armature: deformazione da scheletro
```python
def skin_with_shrinkwrap(skin_obj, target_obj, wrap_method='NEAREST_SURFACEPOINT',
offset=0.005, thickness=0.04, subsurf_levels=2):
"""
Configura i modificatori per pelle biomeccanica.
L'ordine è critico: Armature → Shrinkwrap → Solidify → SubSurf.
wrap_method:
'NEAREST_SURFACEPOINT' : proietta sul punto più vicino — stabile su mesh curve
'PROJECT' : proietta lungo una direzione — per superfici piatte
'NEAREST_VERTEX' : snapping ai vertici — meno smooth
Esempio (palpebra su sfera occhio):
create_eyeball() → eyeball
create_eyelid() → eyelid_mesh (con apertura a mandorla)
skin_with_shrinkwrap(eyelid_mesh, eyeball,
offset=0.005, thickness=0.04)
"""
# 1. Shrinkwrap
sw = skin_obj.modifiers.new("Shrinkwrap", "SHRINKWRAP")
sw.target = target_obj
sw.wrap_method = wrap_method
sw.offset = offset
# 2. Solidify (spessore verso l'esterno)
sol = skin_obj.modifiers.new("Solidify", "SOLIDIFY")
sol.thickness = thickness
sol.offset = 1.0
# 3. SubSurf (leviga il risultato)
sub = skin_obj.modifiers.new("Subdivision", "SUBSURF")
sub.levels = subsurf_levels
sub.render_levels = subsurf_levels + 1
skin_obj.data.shade_smooth()
return sw, sol, sub
def bind_armature(mesh_obj, arm_obj):
"""
Collega mesh_obj all'armatura arm_obj come modifier.
Da chiamare DOPO aver configurato i vertex group con weight_paint_*.
Il modifier Armature deve essere il PRIMO nella stack.
"""
# Aggiungi Armature come primo modificatore
arm_mod = mesh_obj.modifiers.new("Armature", "ARMATURE")
arm_mod.object = arm_obj
# Sposta in cima alla stack (prima di Shrinkwrap e Solidify)
while mesh_obj.modifiers[0].name != arm_mod.name:
bpy.ops.object.modifier_move_up(modifier=arm_mod.name)
# Parent senza vincolo di offset
mesh_obj.parent = arm_obj
mesh_obj.parent_type = 'OBJECT'
mesh_obj.matrix_parent_inverse.identity()
return arm_mod
```
---
## ANIMAZIONE PROCEDURALE — Keyframe da Codice
```python
def animate_bone(arm_obj, bone_name, frames_rots,
rotation_mode='XYZ'):
"""
Anima un osso con keyframe da codice.
frames_rots : lista di (frame, (rx_deg, ry_deg, rz_deg))
Esempio (dito che si chiude e si riapre):
animate_bone(hand_rig, "Proximal", [
(1, (0, 0, 0)), # aperto
(30, (70, 0, 0)), # chiuso
(60, (0, 0, 0)), # riaperto
])
"""
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='POSE')
pbone = arm_obj.pose.bones[bone_name]
pbone.rotation_mode = rotation_mode
for frame, rot_deg in frames_rots:
bpy.context.scene.frame_set(frame)
pbone.rotation_euler = tuple(math.radians(r) for r in rot_deg)
pbone.keyframe_insert(data_path="rotation_euler", frame=frame)
bpy.ops.object.mode_set(mode='OBJECT')
def animate_grasp(arm_obj, open_frame=1, close_frame=30, open_frame2=60,
finger_bones=None):
"""
Animazione procedurale di presa (open → close → open).
finger_bones : dict {bone_name: (open_rot, closed_rot)}
angoli in gradi sull'asse X
Default: catena indice standard (Proximal, Intermediate, Distal).
"""
if finger_bones is None:
finger_bones = {
"Proximal": (0, 70),
"Intermediate": (0, 90),
"Distal": (0, 60),
}
bpy.context.view_layer.objects.active = arm_obj
bpy.ops.object.mode_set(mode='POSE')
for bname, (open_rot, close_rot) in finger_bones.items():
pbone = arm_obj.pose.bones[bname]
pbone.rotation_mode = 'XYZ'
for frame, deg in [(open_frame, open_rot),
(close_frame, close_rot),
(open_frame2, open_rot)]:
bpy.context.scene.frame_set(frame)
pbone.rotation_euler = (math.radians(deg), 0, 0)
pbone.keyframe_insert(data_path="rotation_euler", frame=frame)
bpy.ops.object.mode_set(mode='OBJECT')
def set_interpolation(arm_obj, interp='BEZIER'):
"""
Imposta il tipo di interpolazione per tutte le f-curves dell'armatura.
'BEZIER' : morbido (default — buono per movimenti organici)
'LINEAR' : lineare (buono per turntable, meccanico)
'CONSTANT': scatto (per animazioni stop-motion o flag)
"""
if arm_obj.animation_data and arm_obj.animation_data.action:
for fc in arm_obj.animation_data.action.fcurves:
for kp in fc.keyframe_points:
kp.interpolation = interp
```
---
## WORKFLOW COMPLETO — Mano con Presa
```python
# ══ STEP 1: Armatura ══════════════════════════════════════════
arm_obj, arm = create_armature("Hand_Rig")
# Ossa in edit mode (già attivo da create_armature)
joints = [("Palm", (0,-2.0,0)), ("Proximal",(0,-4.0,0)),
("Intermediate",(0,-5.5,0)), ("Distal",(0,-6.5,0))]
prev = None
for i, (name, tail) in enumerate(joints):
head = (0, ([0,-2.0,-4.0,-5.5][i]), 0)
add_bone(arm, name, head, tail, parent=prev,
connected=(i>0), roll=0.0)
prev = name
bpy.ops.object.mode_set(mode='OBJECT')
# ══ STEP 2: Mesh cilindrica ══════════════════════════════════
bpy.ops.mesh.primitive_cylinder_add(vertices=32, radius=0.6,
depth=7.0, location=(0,-3.25,0), rotation=(math.radians(90),0,0))
skin = bpy.context.active_object
skin.name = "Finger_Skin"
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.subdivide(number_cuts=20)
bpy.ops.object.mode_set(mode='OBJECT')
# ══ STEP 3: Weight Painting ═══════════════════════════════════
weight_paint_by_coord(skin, {
"Palm": ( 0.0, -2.0),
"Proximal": (-2.0, -4.0),
"Intermediate": (-4.0, -5.5),
"Distal": (-5.5, -6.5),
}, coord_axis='Y', blend_zone=0.25)
# ══ STEP 4: Shape Key Nocca ═══════════════════════════════════
sk = add_shape_key_with_driver(skin, "Knuckle_Bend", "Proximal",
arm_obj, 'ROT_X', "abs(rot)/1.5")
deform_knuckle(skin, joint_y=-2.0)
# ══ STEP 5: Bind armatura ════════════════════════════════════
bind_armature(skin, arm_obj)
# ══ STEP 6: Socket (oggetto nella mano) ══════════════════════
bpy.ops.mesh.primitive_cylinder_add(radius=0.4, depth=4.0,
location=(0,0,0), rotation=(0,math.radians(90),0))
handle = bpy.context.active_object
handle.name = "Handle"
socket_attach(handle, arm_obj, "Palm",
local_offset=(0,-3.5,-0.6))
# ══ STEP 7: Animazione presa ══════════════════════════════════
animate_grasp(arm_obj, open_frame=1, close_frame=30, open_frame2=60)
bpy.context.scene.frame_end = 80
```
---
## WORKFLOW COMPLETO — Palpebra Biomeccanica
```python
# 1. Sfera oculare
bpy.ops.mesh.primitive_uv_sphere_add(segments=64, ring_count=32,
radius=1.0, location=(0,0,0))
eyeball = bpy.context.active_object
eyeball.name = "Eyeball"
eyeball.data.shade_smooth()
# 2. Maschera facciale (sfera leggermente più grande con apertura a mandorla)
bpy.ops.mesh.primitive_uv_sphere_add(segments=100, ring_count=50,
radius=1.02, location=(0,0,0))
eyelid = bpy.context.active_object
eyelid.name = "Eyelid"
# Ritaglia l'apertura in Edit Mode (parabola a mandorla)
bpy.ops.object.mode_set(mode='EDIT')
bm = bmesh.from_edit_mesh(eyelid.data)
width, height = 0.8, 0.35
to_del = [v for v in bm.verts if v.co.y > 0.1 or
(v.co.y < 0.2 and abs(v.co.x) < width and
abs(v.co.z) <= height * (1-(v.co.x/width)**2))]
bmesh.ops.delete(bm, geom=to_del, context='VERTS')
bmesh.update_edit_mesh(eyelid.data)
bpy.ops.object.mode_set(mode='OBJECT')
# 3. Weight paint per upper/lower lid
weight_paint_by_distance(eyelid, "EyelidControl_Upper",
Vector((0,-0.5, 0.35)), max_dist=0.9, falloff='SMOOTH')
weight_paint_by_distance(eyelid, "EyelidControl_Lower",
Vector((0,-0.5,-0.35)), max_dist=0.9, falloff='SMOOTH')
# 4. Shrinkwrap + Solidify
skin_with_shrinkwrap(eyelid, eyeball, offset=0.005, thickness=0.04)
```
---
## REGOLE QUALITÀ RIGGING
1. **Bone Roll = 0** su tutti gli assi di flessione primari (dita, gomito, ginocchio).
Eccezione: assi di abduzione/adduzione possono avere roll 90°.
2. **Ordine modificatori** è critico:
`Armature → Shrinkwrap → Solidify → SubSurf`
Invertire Armature e Shrinkwrap causa deformazioni errate.
3. **Normalizza i vertex group** dopo il weight painting:
Ogni vertice deve avere pesi che sommano a 1.0.
`bpy.ops.object.vertex_group_normalize_all()` in Edit Mode.
4. **Driver expression** deve essere limitata a [0,1]:
Usa `min(1, max(0, abs(rot)/1.5))` per sicurezza.
5. **Pole Target** obbligatorio su catene IK con 2+ ossa.
Senza pole target il gomito/ginocchio flippa a 180°.
6. **`bpy.ops.constraint.childof_set_inverse`** da chiamare dopo
ogni socket_attach — imposta la matrice inversa corretta.
7. **Test in Pose Mode** prima del render:
Muovi l'osso radice → verifica che tutto il rig si muova insieme.
Ruota l'osso foglia → verifica che i driver si attivino.
---
## ANALISI RICHIESTA
| Keyword | Tecnica |
|---------|---------|
| `mano / dito / falange` | create_finger + weight_paint_by_coord + animate_grasp |
| `occhio / palpebra` | sfera UV + maschera a mandorla + skin_with_shrinkwrap |
| `gamba / ginocchio / gomito` | IK con pole target (setup_ik) |
| `braccio / catena` | create_armature + add_bone + setup_ik_target |
| `colonna / vertebra` | catena lineare + parallel_transport (usa blender-procedural) |
| `spada / scudo / attrezzo` | socket_attach + CHILD_OF |
| `nocca / muscolo / gonfiore` | Shape Key + Driver (add_shape_key_with_driver) |
| `presa / animazione pugno` | animate_grasp |
| `FK / IK switch` | toggle_ik_fk |
| `pelle / skin / deformazione` | bind_armature + weight_paint_* |
**Se richiesta ambigua → chiedi: "L'oggetto deve deformarsi (pelle su scheletro)
o solo seguire un osso rigidamente (socket)?"**
## Output
- Codice Python completo, nessun placeholder
- Bone Roll = 0 su tutti gli assi primari
- Weight paint sempre con smoothstep (non lineare)
- Dopo esecuzione: screenshot → analisi visiva → itera
- Driver expression sempre limitata a [0,1]
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!