Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Blender Texture

ASecurity

Skill per materiali, texture e UV in Blender. Copre: materiali Principled BSDF procedurali (noise, bump, SSS, Fresnel), UV unwrap (Smart Project, angolo-based, manuale), baking AO/Normal/Diffuse su immagine, texture painting via vertex paint o image stamp, PBR workflow con immagini reali (albedo + roughness + normal map). Usa questa skill quando devi assegnare materiali realistici, fare baking, UV unwrap, o costruire un node tree di materiale complesso da zero.

5 stars
0 votes
0 copies
0 views
Added 9/22/2026
ai-agentspythongobashnodeapi

Works with

cliapimcp

Security Analysis

A100/100

Scanned 9/22/2026

$npx -y skills add MAX-786/claude-3d-harness --skill blender-texture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Blender Texture?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Blender Texture
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/max-786-blender-texture/badge)](https://www.skillsdirectory.com/skills/max-786-blender-texture)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
description: >
  Skill per materiali, texture e UV in Blender. Copre: materiali Principled BSDF
  procedurali (noise, bump, SSS, Fresnel), UV unwrap (Smart Project, angolo-based,
  manuale), baking AO/Normal/Diffuse su immagine, texture painting via vertex paint
  o image stamp, PBR workflow con immagini reali (albedo + roughness + normal map).
  Usa questa skill quando devi assegnare materiali realistici, fare baking, UV unwrap,
  o costruire un node tree di materiale complesso da zero.
allowed-tools:
  - Bash
  - Read
  - Write
  - Glob
  - mcp__Blender__execute_blender_code
  - mcp__Blender__get_screenshot_of_window_as_image
  - mcp__Blender__get_screenshot_of_area_as_image
  - mcp__Blender__render_viewport_to_path
  - mcp__Blender__render_thumbnail_to_path
  - mcp__Blender__get_objects_summary
  - mcp__Blender__get_object_detail_summary
---

# Skill: Blender Texture & Materials

Sei un esperto di materiali e texturing in Blender con `bpy` + node tree.
Ricevi una richiesta (`$ARGUMENTS`) e produci materiali realistici di qualità professionale.

---

## Connessione — MCP

**MCP (porta 9876 — PREFERITO):**
```python
mcp__Blender__execute_blender_code(code="import bpy\n# ...\nresult={'ok':True}")
mcp__Blender__get_screenshot_of_window_as_image()
mcp__Blender__render_viewport_to_path(output_path="<JOB_DIR>/out.png")
```

---

## Helper universali (copia nel blocco che esegui)

```python
import bpy

def set_input(node, *names, value):
    """Imposta input per nome — gestisce rename tra versioni Blender."""
    for name in names:
        if name in node.inputs:
            node.inputs[name].default_value = value
            return True
    return False

def link(links, from_node, from_sock, to_node, to_sock):
    links.new(from_node.outputs[from_sock], to_node.inputs[to_sock])

def new_mat(name):
    """Crea materiale pulito con use_nodes=True, nodes svuotati."""
    mat = bpy.data.materials.new(name)
    mat.use_nodes = True
    mat.node_tree.nodes.clear()
    return mat, mat.node_tree.nodes, mat.node_tree.links

def apply_mat(obj_name, mat):
    """Assegna mat allo slot 0 dell'oggetto."""
    ob = bpy.data.objects.get(obj_name)
    if ob:
        ob.data.materials.clear()
        ob.data.materials.append(mat)
```

---

## Sezione 1 — UV Unwrap

### 1.1 Smart UV Project (raccomandato per oggetti complessi)
```python
import bpy

def smart_uv(obj_name, angle_limit=66, margin=0.02):
    ob = bpy.data.objects[obj_name]
    bpy.context.view_layer.objects.active = ob
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.uv.smart_project(
        angle_limit   = angle_limit,
        island_margin = margin,
        scale_to_bounds = True
    )
    bpy.ops.object.mode_set(mode='OBJECT')
    uv = ob.data.uv_layers.active
    return uv.name if uv else None
```

### 1.2 Angle-Based Unwrap (superfici organiche)
```python
def unwrap_angle(obj_name, margin=0.02):
    ob = bpy.data.objects[obj_name]
    bpy.context.view_layer.objects.active = ob
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    # Mark seam automatico prima di unwrap
    bpy.ops.mesh.mark_seam(clear=True)  # rimuovi seam precedenti
    bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=margin)
    bpy.ops.object.mode_set(mode='OBJECT')
```

### 1.3 Cube Projection (muri, pavimenti, superfici piane)
```python
def cube_project(obj_name, cube_size=1.0):
    ob = bpy.data.objects[obj_name]
    bpy.context.view_layer.objects.active = ob
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.uv.cube_project(cube_size=cube_size)
    bpy.ops.object.mode_set(mode='OBJECT')
```

### 1.4 UV Layer aggiuntivo (baking separato)
```python
def add_uv_layer(obj_name, name="UVBake"):
    ob = bpy.data.objects[obj_name]
    ob.data.uv_layers.new(name=name)
    ob.data.uv_layers.active = ob.data.uv_layers[name]
    # Fai unwrap con Smart Project su questo layer
    smart_uv(obj_name)
```

---

## Sezione 2 — Materiali Procedurali

### TABELLA VALORI DI RIFERIMENTO — Materiali Comuni

> **Regola:** Metallic è sempre 0 o 1 — nessun valore intermedio (le cose sono o metallo o non-metallo).
> **Regola:** Mai Base Color = (0,0,0) puro. Anche i materiali più scuri riflettono qualcosa. Minimo: 0.02–0.03.

| Materiale | Base Color (lineare) | Roughness | Metallic | Specular IOR | Note |
|-----------|---------------------|-----------|----------|--------------|------|
| Plastica matte nera | (0.025, 0.025, 0.030) | 0.50–0.65 | 0 | 0.25 | + noise su roughness |
| Plastica semi-gloss | (0.03, 0.03, 0.04) | 0.35–0.50 | 0 | 0.30 | consumer electronics |
| Vetro screen (spento) | (0.005, 0.006, 0.012) | 0.01–0.03 | 0 | 0.50 | quasi mirror |
| Porcellana bianca | (0.955, 0.940, 0.896) | 0.08–0.12 | 0 | 0.55 | coat 0.2 |
| Legno chiaro | (0.55, 0.38, 0.22) | 0.65–0.80 | 0 | 0.10 | + grain texture |
| Legno scuro | (0.12, 0.07, 0.04) | 0.70–0.85 | 0 | 0.10 | + grain texture |
| Metallo lucido | (0.95, 0.95, 0.95) | 0.05–0.15 | 1 | — | alluminio, acciaio |
| Metallo spazzolato | (0.80, 0.80, 0.80) | 0.30–0.45 | 1 | — | + anisotropy |
| Oro | (1.00, 0.78, 0.28) | 0.10–0.25 | 1 | — | colore giallo caldo |
| Gomma | (0.02, 0.02, 0.02) | 0.90–1.00 | 0 | 0.05 | molto matte |
| Vetro trasparente | (0.92, 0.95, 0.98) | 0.00–0.05 | 0 | 0.50 | transmission=1, IOR=1.52 |
| Carta | (0.85, 0.83, 0.78) | 0.90–1.00 | 0 | 0.05 | no specular |
| Tessuto cotone | (base a scelta) | 0.85–0.95 | 0 | 0.05 | + fuzz/sheen |
| Pelle umana | (0.77, 0.52, 0.40) | 0.60–0.75 | 0 | 0.35 | SSS obbligatorio |

---

### Pattern noise-roughness — Anti "CG-Clean Look"

La roughness uniforme è il segnale più riconoscibile del "CG pulito". Aggiungere micro-variazione con Noise Texture rompe l'uniformità sintetica e rende qualsiasi superficie più reale.

```python
def add_roughness_noise(nodes, links, bsdf,
                        base_roughness=0.50,
                        variation=0.08,
                        scale=80.0,
                        detail=4.0):
    """
    Aggiunge micro-variazione di roughness tramite Noise → ColorRamp → Roughness.

    base_roughness: valore centrale (es. 0.50 per plastica matte)
    variation:      ±variazione attorno alla base (0.05–0.10 è sottile, 0.15+ è visibile)
    scale:          frequenza spaziale del noise (60–120 per micro-texture, 5–20 per macro)
    detail:         ottave del noise (2–4 per plastica, 6–8 per roccia)

    Esempi:
      Plastica matte:    base=0.50, variation=0.08, scale=80
      Plastica semi-gloss: base=0.40, variation=0.05, scale=100
      Legno:             base=0.70, variation=0.15, scale=20, detail=6
      Metallo spazzolato: base=0.35, variation=0.10, scale=60
    """
    noise = nodes.new("ShaderNodeTexNoise")
    noise.inputs["Scale"].default_value    = scale
    noise.inputs["Detail"].default_value   = detail
    noise.inputs["Roughness"].default_value = 0.6
    noise.inputs["Distortion"].default_value = 0.0
    noise.location = (-400, -200)

    ramp = nodes.new("ShaderNodeValToRGB")
    lo = max(0.0, base_roughness - variation)
    hi = min(1.0, base_roughness + variation)
    ramp.color_ramp.elements[0].position = 0.35
    ramp.color_ramp.elements[0].color    = (lo, lo, lo, 1.0)
    ramp.color_ramp.elements[1].position = 0.65
    ramp.color_ramp.elements[1].color    = (hi, hi, hi, 1.0)
    ramp.location = (-200, -200)

    links.new(noise.outputs["Fac"], ramp.inputs["Fac"])
    links.new(ramp.outputs["Color"], bsdf.inputs["Roughness"])
    return noise, ramp


# Uso rapido su un materiale esistente:
def apply_roughness_noise_to(mat, base_roughness=0.50, variation=0.08, scale=80.0):
    """Aggiunge noise-roughness a un materiale già esistente."""
    nt = mat.node_tree
    bsdf = next((n for n in nt.nodes if n.type == 'BSDF_PRINCIPLED'), None)
    if bsdf:
        add_roughness_noise(nt.nodes, nt.links, bsdf,
                            base_roughness, variation, scale)
```

---

### Pattern base: Principled BSDF
```python
mat, nodes, links = new_mat("MyMat")

out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (600, 0)
bsdf = nodes.new("ShaderNodeBsdfPrincipled"); bsdf.location = (200, 0)
links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

bsdf.inputs["Base Color"].default_value  = (0.8, 0.3, 0.1, 1.0)
bsdf.inputs["Roughness"].default_value   = 0.6
bsdf.inputs["Metallic"].default_value    = 0.0
set_input(bsdf, "Specular IOR Level", "Specular", value=0.5)

# Per plastica: aggiungi subito noise-roughness
add_roughness_noise(nodes, links, bsdf, base_roughness=0.5, variation=0.08)
```

### 2.1 mat_porcelain — Porcellana / Ceramica
```python
def mat_porcelain(name="Porcelain", color=(0.955, 0.940, 0.896)):
    mat, nodes, links = new_mat(name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (600, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (200, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    # Micro-variazione noise (2%) via ShaderNodeMix RGBA
    noise = nodes.new("ShaderNodeTexNoise"); noise.location = (-400, 100)
    noise.inputs["Scale"].default_value    = 12.0
    noise.inputs["Detail"].default_value   = 2.0
    noise.inputs["Roughness"].default_value= 0.5

    mix = nodes.new("ShaderNodeMix"); mix.data_type = "RGBA"
    mix.location = (-100, 100)
    mix.inputs[6].default_value = (*[c * 0.97 for c in color], 1.0)  # scuro
    mix.inputs[7].default_value = (*[c * 1.01 for c in color], 1.0)  # chiaro
    links.new(noise.outputs["Fac"], mix.inputs[0])
    links.new(mix.outputs[2], bsdf.inputs["Base Color"])

    bsdf.inputs["Roughness"].default_value = 0.08
    set_input(bsdf, "IOR", value=1.52)
    set_input(bsdf, "Coat Weight", "Clearcoat", value=0.2)
    set_input(bsdf, "Coat Roughness", "Clearcoat Roughness", value=0.05)
    set_input(bsdf, "Specular IOR Level", "Specular", value=0.55)
    return mat

# NOTA ShaderNodeMix RGBA:
#   inputs[0]  = Factor (Fac)
#   inputs[6]  = Color A  (NON inputs[1])
#   inputs[7]  = Color B  (NON inputs[2])
#   outputs[2] = risultato Color  (NON outputs[0])
# ShaderNodeMixRGB è DEPRECATO in Blender 4.x/5.x — non usare.
```

### 2.2 mat_organic — Materiale organico con SSS + Noise + Fresnel
```python
def mat_organic(name="Organic",
                base_color=(0.65, 0.05, 0.05),
                roughness_range=(0.50, 0.72),
                sss=0.18, sss_radius=(0.92, 0.10, 0.10),
                bump_strength=0.35, bump_dist=0.008,
                glossy_ior=1.38, glossy_rough=0.06):
    """
    Stack: Noise→ColorRamp→Principled + Noise→Bump + Glossy→Fresnel→Mix
    Usato per: muscoli, frutta, skin, radici, tessuti biologici.
    """
    mat, nodes, links = new_mat(name)

    # Coordinate
    tc  = nodes.new("ShaderNodeTexCoord"); tc.location = (-1100, 0)
    mp  = nodes.new("ShaderNodeMapping");  mp.location = (-900, 0)
    mp.inputs["Scale"].default_value = (1.2, 1.2, 1.0)
    links.new(tc.outputs["Object"], mp.inputs["Vector"])

    # Noise colore
    nc = nodes.new("ShaderNodeTexNoise"); nc.location = (-680, 250)
    nc.inputs["Scale"].default_value     = 6.0
    nc.inputs["Detail"].default_value    = 5.0
    nc.inputs["Roughness"].default_value = 0.65
    nc.inputs["Distortion"].default_value= 0.25
    links.new(mp.outputs["Vector"], nc.inputs["Vector"])

    ramp = nodes.new("ShaderNodeValToRGB"); ramp.location = (-430, 250)
    try:    ramp.color_ramp.color_space = "RGB"
    except: ramp.color_ramp.color_mode  = "RGB"   # Blender 5.x rinomina
    c = base_color
    ramp.color_ramp.elements[0].color = (c[0]*0.55, c[1]*0.55, c[2]*0.55, 1.0)
    ramp.color_ramp.elements[1].color = (*c, 1.0)
    links.new(nc.outputs["Fac"], ramp.inputs["Fac"])

    # Noise rugosità
    nr = nodes.new("ShaderNodeTexNoise"); nr.location = (-680, -50)
    nr.inputs["Scale"].default_value = 18.0
    links.new(mp.outputs["Vector"], nr.inputs["Vector"])
    rr = nodes.new("ShaderNodeValToRGB"); rr.location = (-430, -50)
    rr.color_ramp.elements[0].color = (*[roughness_range[0]]*3, 1.0)
    rr.color_ramp.elements[1].color = (*[roughness_range[1]]*3, 1.0)
    links.new(nr.outputs["Fac"], rr.inputs["Fac"])

    # Bump
    nb = nodes.new("ShaderNodeTexNoise"); nb.location = (-680, -350)
    nb.inputs["Scale"].default_value     = 22.0
    nb.inputs["Detail"].default_value    = 8.0
    nb.inputs["Roughness"].default_value = 0.55
    links.new(mp.outputs["Vector"], nb.inputs["Vector"])
    bump = nodes.new("ShaderNodeBump"); bump.location = (-180, -300)
    bump.inputs["Strength"].default_value = bump_strength
    bump.inputs["Distance"].default_value = bump_dist
    links.new(nb.outputs["Fac"], bump.inputs["Height"])

    # Principled BSDF
    bsdf = nodes.new("ShaderNodeBsdfPrincipled"); bsdf.location = (80, 120)
    links.new(ramp.outputs["Color"], bsdf.inputs["Base Color"])
    links.new(rr.outputs["Color"],   bsdf.inputs["Roughness"])
    links.new(bump.outputs["Normal"],bsdf.inputs["Normal"])
    set_input(bsdf, "Subsurface Weight", "Subsurface", value=sss)
    try:    bsdf.inputs["Subsurface Radius"].default_value = sss_radius
    except: pass
    set_input(bsdf, "Specular IOR Level", "Specular", value=0.28)

    # Glossy (strato umido)
    glossy = nodes.new("ShaderNodeBsdfGlossy"); glossy.location = (80, -200)
    glossy.inputs["Roughness"].default_value = glossy_rough
    links.new(bump.outputs["Normal"], glossy.inputs["Normal"])

    # Fresnel → Mix
    fresnel = nodes.new("ShaderNodeFresnel"); fresnel.location = (80, -380)
    fresnel.inputs["IOR"].default_value = glossy_ior
    mix = nodes.new("ShaderNodeMixShader"); mix.location = (380, 0)
    links.new(fresnel.outputs["Fac"],   mix.inputs["Fac"])
    links.new(bsdf.outputs["BSDF"],     mix.inputs[1])
    links.new(glossy.outputs["BSDF"],   mix.inputs[2])

    out = nodes.new("ShaderNodeOutputMaterial"); out.location = (620, 0)
    links.new(mix.outputs["Shader"], out.inputs["Surface"])
    return mat
```

### 2.3 mat_metal — Metallo PBR
```python
def mat_metal(name="Metal", color=(0.8, 0.8, 0.85), roughness=0.15):
    mat, nodes, links = new_mat(name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (400, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (0, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    bsdf.inputs["Base Color"].default_value  = (*color, 1.0)
    bsdf.inputs["Metallic"].default_value    = 1.0
    bsdf.inputs["Roughness"].default_value   = roughness
    set_input(bsdf, "Specular IOR Level", "Specular", value=0.5)

    # Anisotropia leggera per look brushed
    if "Anisotropic" in bsdf.inputs:
        bsdf.inputs["Anisotropic"].default_value = 0.3
    return mat
```

### 2.4 mat_glass — Vetro
```python
def mat_glass(name="Glass", color=(0.95, 0.98, 1.0), roughness=0.02, ior=1.45):
    mat, nodes, links = new_mat(name)
    mat.blend_method = "BLEND"  # Eevee transparency
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (400, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (0, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    bsdf.inputs["Base Color"].default_value  = (*color, 1.0)
    bsdf.inputs["Roughness"].default_value   = roughness
    set_input(bsdf, "IOR", value=ior)
    set_input(bsdf, "Transmission Weight", "Transmission", value=1.0)
    return mat
```

### 2.5 mat_leather — Cuoio / Pelle
```python
def mat_leather(name="Leather", color=(0.25, 0.10, 0.05), roughness=0.75):
    mat, nodes, links = new_mat(name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (600, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (200, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    # Voronoi per pori del cuoio
    vc = nodes.new("ShaderNodeTexVoronoi"); vc.location = (-500, 200)
    vc.inputs["Scale"].default_value    = 80.0
    vc.inputs["Randomness"].default_value = 0.8
    noise = nodes.new("ShaderNodeTexNoise"); noise.location = (-500, -100)
    noise.inputs["Scale"].default_value = 12.0
    noise.inputs["Detail"].default_value = 6.0

    # Mix Voronoi + Noise per bump complesso
    mix_h = nodes.new("ShaderNodeMix"); mix_h.data_type = "FLOAT"
    mix_h.location = (-200, 100); mix_h.inputs[0].default_value = 0.4
    links.new(vc.outputs["Distance"],   mix_h.inputs[4])  # A (float)
    links.new(noise.outputs["Fac"],     mix_h.inputs[5])  # B (float)

    bump = nodes.new("ShaderNodeBump"); bump.location = (-20, 0)
    bump.inputs["Strength"].default_value = 0.5
    bump.inputs["Distance"].default_value = 0.003
    links.new(mix_h.outputs[1], bump.inputs["Height"])  # output[1] = float

    # Colore con leggera variazione noise
    cr = nodes.new("ShaderNodeValToRGB"); cr.location = (-200, -200)
    cr.color_ramp.elements[0].color = (*[c*0.7 for c in color], 1.0)
    cr.color_ramp.elements[1].color = (*color, 1.0)
    links.new(noise.outputs["Fac"], cr.inputs["Fac"])

    links.new(cr.outputs["Color"],    bsdf.inputs["Base Color"])
    links.new(bump.outputs["Normal"], bsdf.inputs["Normal"])
    bsdf.inputs["Roughness"].default_value = roughness
    set_input(bsdf, "Sheen Weight", "Sheen", value=0.08)
    return mat
```

### 2.6 mat_emission — Materiale emissivo (luce, LED, neon)
```python
def mat_emission(name="Emission", color=(1.0, 0.9, 0.7), strength=5.0):
    mat, nodes, links = new_mat(name)
    out = nodes.new("ShaderNodeOutputMaterial"); out.location = (400, 0)
    em  = nodes.new("ShaderNodeEmission");       em.location  = (0, 0)
    links.new(em.outputs["Emission"], out.inputs["Surface"])
    em.inputs["Color"].default_value    = (*color, 1.0)
    em.inputs["Strength"].default_value = strength
    return mat
```

### 2.7 mat_wood — Legno procedurale
```python
def mat_wood(name="Wood", ring_color=(0.38, 0.20, 0.08), grain_color=(0.55, 0.30, 0.12)):
    mat, nodes, links = new_mat(name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (700, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (350, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    tc = nodes.new("ShaderNodeTexCoord"); tc.location = (-900, 0)
    mp = nodes.new("ShaderNodeMapping");  mp.location = (-700, 0)
    links.new(tc.outputs["Object"], mp.inputs["Vector"])

    # Wave per anelli del legno
    wave = nodes.new("ShaderNodeTexWave"); wave.location = (-500, 100)
    wave.wave_type    = "RINGS"
    wave.inputs["Scale"].default_value      = 8.0
    wave.inputs["Distortion"].default_value = 2.5
    wave.inputs["Detail"].default_value     = 6.0
    wave.inputs["Detail Roughness"].default_value = 0.65
    links.new(mp.outputs["Vector"], wave.inputs["Vector"])

    cr = nodes.new("ShaderNodeValToRGB"); cr.location = (-200, 100)
    cr.color_ramp.elements[0].color = (*ring_color,  1.0)
    cr.color_ramp.elements[1].color = (*grain_color, 1.0)
    links.new(wave.outputs["Fac"], cr.inputs["Fac"])

    # Noise per venature casuali
    noise = nodes.new("ShaderNodeTexNoise"); noise.location = (-500, -150)
    noise.inputs["Scale"].default_value = 25.0
    noise.inputs["Detail"].default_value = 8.0
    links.new(mp.outputs["Vector"], noise.inputs["Vector"])

    bump = nodes.new("ShaderNodeBump"); bump.location = (100, -200)
    bump.inputs["Strength"].default_value = 0.15
    links.new(noise.outputs["Fac"], bump.inputs["Height"])

    links.new(cr.outputs["Color"],    bsdf.inputs["Base Color"])
    links.new(bump.outputs["Normal"], bsdf.inputs["Normal"])
    bsdf.inputs["Roughness"].default_value = 0.55
    set_input(bsdf, "Specular IOR Level", "Specular", value=0.1)
    return mat
```

---

## Sezione 3 — Image Texture (PBR con immagini reali)

### 3.1 Carica immagine e assegna
```python
def mat_image_texture(name, albedo_path, normal_path=None,
                      roughness_path=None, ao_path=None):
    """
    PBR completo con immagini reali.
    Percorsi assoluti, es: "D:/textures/brick_albedo.png"
    """
    mat, nodes, links = new_mat(name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (800, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (400, 0)
    links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

    tc = nodes.new("ShaderNodeTexCoord"); tc.location = (-900, 0)
    mp = nodes.new("ShaderNodeMapping");  mp.location = (-700, 0)
    links.new(tc.outputs["UV"], mp.inputs["Vector"])

    x = -400

    # Albedo
    if albedo_path:
        img_alb = bpy.data.images.load(albedo_path, check_existing=True)
        n_alb = nodes.new("ShaderNodeTexImage"); n_alb.location = (x, 300)
        n_alb.image = img_alb
        n_alb.image.colorspace_settings.name = "sRGB"
        links.new(mp.outputs["Vector"], n_alb.inputs["Vector"])
        links.new(n_alb.outputs["Color"], bsdf.inputs["Base Color"])

    # Roughness (Linear)
    if roughness_path:
        img_r = bpy.data.images.load(roughness_path, check_existing=True)
        n_r = nodes.new("ShaderNodeTexImage"); n_r.location = (x, 0)
        n_r.image = img_r
        n_r.image.colorspace_settings.name = "Non-Color"
        links.new(mp.outputs["Vector"], n_r.inputs["Vector"])
        links.new(n_r.outputs["Color"], bsdf.inputs["Roughness"])

    # Normal Map
    if normal_path:
        img_n = bpy.data.images.load(normal_path, check_existing=True)
        n_n = nodes.new("ShaderNodeTexImage"); n_n.location = (x, -300)
        n_n.image = img_n
        n_n.image.colorspace_settings.name = "Non-Color"
        nm = nodes.new("ShaderNodeNormalMap"); nm.location = (x+300, -300)
        links.new(mp.outputs["Vector"], n_n.inputs["Vector"])
        links.new(n_n.outputs["Color"], nm.inputs["Color"])
        links.new(nm.outputs["Normal"], bsdf.inputs["Normal"])

    # AO (moltiplicato al Base Color)
    if ao_path:
        img_ao = bpy.data.images.load(ao_path, check_existing=True)
        n_ao = nodes.new("ShaderNodeTexImage"); n_ao.location = (x, 600)
        n_ao.image = img_ao
        n_ao.image.colorspace_settings.name = "Non-Color"
        mix_ao = nodes.new("ShaderNodeMix"); mix_ao.data_type = "RGBA"
        mix_ao.blend_type = "MULTIPLY"; mix_ao.location = (x+300, 400)
        mix_ao.inputs[0].default_value = 1.0
        if albedo_path:
            links.new(n_alb.outputs["Color"], mix_ao.inputs[6])
        links.new(n_ao.outputs["Color"],  mix_ao.inputs[7])
        links.new(mix_ao.outputs[2],      bsdf.inputs["Base Color"])

    return mat

# Colorspace regola:
#   Albedo, Diffuse, colori     → "sRGB"
#   Normal, Roughness, AO, Mask → "Non-Color"
```

### 3.2 Tiling / UV Scale via Mapping node
```python
def set_uv_tiling(mat_name, scale=(4.0, 4.0, 1.0)):
    """Scala le UV del materiale via nodo Mapping."""
    mat = bpy.data.materials[mat_name]
    for node in mat.node_tree.nodes:
        if node.type == "MAPPING":
            node.inputs["Scale"].default_value = scale
            break
```

---

## Sezione 4 — Baking

### 4.1 Baking setup e esecuzione
```python
def bake_texture(obj_name, bake_type="AO",
                 width=1024, height=1024,
                 img_name="BakedAO", save_path=None):
    """
    Bake di un singolo tipo su immagine.
    bake_type: "AO", "DIFFUSE", "NORMAL", "SHADOW", "EMIT", "COMBINED"

    Prerequisiti: UV layer attivo, Cycles renderer.
    """
    import bpy
    ob = bpy.data.objects[obj_name]
    bpy.context.view_layer.objects.active = ob
    bpy.context.scene.render.engine = "CYCLES"
    bpy.context.scene.cycles.samples = 64  # basso per bake rapido

    # Crea immagine target
    if img_name in bpy.data.images:
        bpy.data.images.remove(bpy.data.images[img_name])
    img = bpy.data.images.new(img_name, width, height)
    img.generated_color = (0.0, 0.0, 0.0, 1.0)

    # Aggiungi nodo Image Texture al materiale, collegato ma non usato per render
    for mat_slot in ob.material_slots:
        mat = mat_slot.material
        if mat and mat.use_nodes:
            nt = mat.node_tree
            tex_node = nt.nodes.new("ShaderNodeTexImage")
            tex_node.image = img
            tex_node.name  = "__bake_target__"
            # Selezionalo come target
            nt.nodes.active = tex_node

    # Bake
    bpy.ops.object.bake(type=bake_type, use_clear=True)

    # Salva (opzionale)
    if save_path:
        img.filepath_raw = save_path
        img.file_format  = "PNG"
        img.save()

    return img

# Note baking:
# - Cycles OBBLIGATORIO (Eevee non supporta bake)
# - UV layer corretto deve essere ATTIVO prima del bake
# - COMBINED include AO + diffuse + speculare + shadows
# - Per bake su low-poly da high-poly: seleziona prima hi, poi lo (Ctrl+Click),
#   attiva "Selected to Active" nelle impostazioni bake
```

### 4.2 Bake AO completo (pattern consigliato)
```python
def full_ao_bake(obj_name, res=2048, save_path=None):
    """AO bake con impostazioni ottimizzate, salvataggio automatico."""
    sc = bpy.context.scene
    sc.render.engine = "CYCLES"
    sc.cycles.samples = 128
    sc.cycles.bake_type = "AO"

    img = bake_texture(obj_name, "AO", res, res, f"{obj_name}_AO", save_path)
    print(f"AO baked: {save_path}")
    return img
```

### 4.3 Bake Normal Map (high-poly → low-poly)
```python
def bake_normal_hp_to_lp(high_name, low_name,
                          res=2048, extrusion=0.02, save_path=None):
    """
    Bake normal map da high-poly a low-poly.
    Estrusion: distanza di offset per il ray (default 2cm in BU).
    """
    sc = bpy.context.scene
    sc.render.engine = "CYCLES"
    sc.cycles.samples = 16  # normal map non ha bisogno di molti samples

    # Seleziona: prima hi, poi lo (lo è active)
    bpy.ops.object.select_all(action='DESELECT')
    bpy.data.objects[high_name].select_set(True)
    lo = bpy.data.objects[low_name]
    lo.select_set(True)
    bpy.context.view_layer.objects.active = lo

    img = bake_texture(low_name, "NORMAL", res, res, f"{low_name}_Normal", save_path)

    # Configura selected-to-active
    bpy.context.scene.render.bake.use_selected_to_active = True
    bpy.context.scene.render.bake.cage_extrusion = extrusion
    bpy.ops.object.bake(type="NORMAL", use_clear=True)

    if save_path:
        img.filepath_raw = save_path
        img.file_format  = "PNG"
        img.save()
    return img
```

---

## Sezione 5 — Texture Painting (Vertex + Image Stamp)

### 5.1 Vertex Paint
```python
def vertex_paint_base(obj_name, color=(0.8, 0.3, 0.1, 1.0)):
    """
    Inizializza Vertex Paint con colore di base su tutto l'oggetto.
    Usa bpy.ops.paint per fill — richiede active object.
    """
    ob = bpy.data.objects[obj_name]
    bpy.context.view_layer.objects.active = ob
    bpy.ops.object.mode_set(mode='VERTEX_PAINT')

    # Colore tool
    bpy.context.tool_settings.vertex_paint.brush.color = color[:3]

    # Fill di tutto l'oggetto
    bpy.ops.paint.vertex_color_set()  # colora tutti i vertici con il colore brush
    bpy.ops.object.mode_set(mode='OBJECT')

def use_vertex_color_in_mat(obj_name, mat_name="VColMat"):
    """Materiale che legge il vertex color tramite Attribute node."""
    mat, nodes, links = new_mat(mat_name)
    out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (400, 0)
    bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (0, 0)
    attr = nodes.new("ShaderNodeVertexColor");     attr.location = (-300, 0)
    # Blender 4.x: attr.layer_name, Blender 5.x: attr.attribute_name (usa entrambi)
    try:    attr.layer_name = "Col"
    except: attr.attribute_name = "Col"
    links.new(attr.outputs["Color"],  bsdf.inputs["Base Color"])
    links.new(bsdf.outputs["BSDF"],   out.inputs["Surface"])
    apply_mat(obj_name, mat)
```

### 5.2 Image Stamp (pennellata programmatica)
```python
def stamp_image_texture(obj_name, res=1024, base_color=(0.8, 0.5, 0.2)):
    """
    Crea immagine per texture paint con colore base piatto.
    Sostituisce la texture painting manuale: crea img, assegna al materiale.
    """
    img_name = f"{obj_name}_Paint"
    if img_name in bpy.data.images:
        bpy.data.images.remove(bpy.data.images[img_name])
    img = bpy.data.images.new(img_name, res, res)
    # Fill uniforme
    pixels = [v for _ in range(res * res) for v in (*base_color, 1.0)]
    img.pixels = pixels

    # Assegna al materiale tramite nodo Image Texture
    ob = bpy.data.objects[obj_name]
    if ob.data.materials:
        mat = ob.data.materials[0]
        nt = mat.node_tree
        for n in nt.nodes:
            if n.type == "TEX_IMAGE":
                n.image = img
                break
    return img
```

---

## Sezione 6 — Scene & Render Setup

### 6.1 Setup rapido Cycles
```python
def setup_cycles(samples=128, exposure=0.0, look="Medium High Contrast"):
    sc = bpy.context.scene
    sc.render.engine = "CYCLES"
    sc.cycles.samples = samples
    sc.view_settings.view_transform = "Filmic"
    sc.view_settings.look = look
    sc.view_settings.exposure = exposure
```

### 6.2 Setup Eevee (preview veloce)
```python
def setup_eevee(exposure=0.0):
    sc = bpy.context.scene
    try:    sc.render.engine = "BLENDER_EEVEE_NEXT"
    except: sc.render.engine = "BLENDER_EEVEE"
    sc.view_settings.view_transform = "Filmic"
    sc.view_settings.look = "Medium High Contrast"
    sc.view_settings.exposure = exposure
    # SSS e trasmission non funzionano bene in Eevee — usa Cycles per materiali organici
```

### 6.3 World (HDRI o colore piatto)
```python
def world_color(color=(0.03, 0.03, 0.04), strength=0.15):
    """Sfondo uniforme, neutro, scuro."""
    w = bpy.context.scene.world
    w.use_nodes = True
    bg = w.node_tree.nodes.get("Background") or w.node_tree.nodes.new("ShaderNodeBackground")
    bg.inputs["Color"].default_value    = (*color, 1.0)
    bg.inputs["Strength"].default_value = strength

def world_hdri(hdri_path, strength=1.0, rotation_z=0.0):
    """HDRI world — illuminazione realistica da file .hdr o .exr."""
    w = bpy.context.scene.world
    w.use_nodes = True
    nt = w.node_tree; nt.nodes.clear()
    bg  = nt.nodes.new("ShaderNodeBackground");   bg.location  = (200, 0)
    env = nt.nodes.new("ShaderNodeTexEnvironment"); env.location = (-200, 0)
    tc  = nt.nodes.new("ShaderNodeTexCoord");       tc.location  = (-600, 0)
    mp  = nt.nodes.new("ShaderNodeMapping");        mp.location  = (-400, 0)
    out = nt.nodes.new("ShaderNodeOutputWorld");    out.location = (500, 0)

    env.image = bpy.data.images.load(hdri_path, check_existing=True)
    mp.inputs["Rotation"].default_value = (0.0, 0.0, rotation_z)

    nt.links.new(tc.outputs["Generated"], mp.inputs["Vector"])
    nt.links.new(mp.outputs["Vector"],    env.inputs["Vector"])
    nt.links.new(env.outputs["Color"],    bg.inputs["Color"])
    nt.links.new(bg.outputs["Background"], out.inputs["Surface"])
    bg.inputs["Strength"].default_value = strength
```

---

## Sezione 7 — Gotcha e compatibilità Blender 4.x / 5.x

| Problema | Blender 4.x | Blender 5.x | Soluzione |
|----------|------------|------------|-----------|
| Mix RGB deprecato | `ShaderNodeMixRGB` | rimosso | usa `ShaderNodeMix` con `data_type='RGBA'` |
| Mix RGBA inputs | `inputs[1]`, `inputs[2]` | `inputs[6]`, `inputs[7]` | usa sempre `[6]`/`[7]` per RGBA |
| Mix RGBA output | `outputs[0]` | `outputs[2]` | usa sempre `outputs[2]` |
| Mix Float inputs | `inputs[1]`, `inputs[2]` | `inputs[4]`, `inputs[5]` | usa `[4]`/`[5]` per FLOAT |
| Mix Float output | `outputs[0]` | `outputs[1]` | usa `outputs[1]` per FLOAT |
| SSS input name | `"Subsurface"` | `"Subsurface Weight"` | prova entrambi con `set_input()` |
| Clearcoat | `"Clearcoat"` | `"Coat Weight"` | prova entrambi |
| Specular | `"Specular"` | `"Specular IOR Level"` | prova entrambi |
| ColorRamp space | `color_space` | `color_mode` | try/except su entrambi |
| VertexColor node | `layer_name` | `attribute_name` | try/except su entrambi |
| Shade smooth | `bpy.ops.object.shade_smooth()` | lascia stripes su bmesh | usa `ob.data.shade_smooth()` direttamente |
| Eevee name | `"BLENDER_EEVEE"` | `"BLENDER_EEVEE_NEXT"` | try/except su entrambi |

### ShaderNodeMix — socket reference completo
```
data_type = 'RGBA':
  inputs[0]  = Factor
  inputs[6]  = A (Color)
  inputs[7]  = B (Color)
  outputs[2] = Result (Color)

data_type = 'FLOAT':
  inputs[0]  = Factor
  inputs[4]  = A (Float)
  inputs[5]  = B (Float)
  outputs[1] = Result (Float)

data_type = 'VECTOR':
  inputs[0]  = Factor
  inputs[8]  = A (Vector)
  inputs[9]  = B (Vector)
  outputs[3] = Result (Vector)
```

---

## Flusso di lavoro tipico

```
1. UV Unwrap        → smart_uv(obj_name) oppure unwrap_angle(obj_name)
2. Materiale        → scegli preset (mat_porcelain, mat_organic, mat_metal...)
                      oppure costruisci da zero con new_mat() + nodi
3. Assegna          → apply_mat(obj_name, mat)
4. Bake (opzionale) → bake_texture(obj_name, "AO") per ottimizzare il look
5. Render setup     → setup_cycles() oppure setup_eevee()
6. World            → world_color() o world_hdri(path)
```

---

## Esempio completo — Vasetto ceramica con materiale procedurale

```python
import bpy

# 1. UV Unwrap
smart_uv("Vase")

# 2. Materiale ceramica azzurra
mat, nodes, links = new_mat("CeramicBlue")
out  = nodes.new("ShaderNodeOutputMaterial"); out.location = (600, 0)
bsdf = nodes.new("ShaderNodeBsdfPrincipled");  bsdf.location = (200, 0)
links.new(bsdf.outputs["BSDF"], out.inputs["Surface"])

noise = nodes.new("ShaderNodeTexNoise"); noise.location = (-400, 100)
noise.inputs["Scale"].default_value = 8.0
noise.inputs["Detail"].default_value = 3.0

mix = nodes.new("ShaderNodeMix"); mix.data_type = "RGBA"; mix.location = (-100, 100)
mix.inputs[6].default_value = (0.25, 0.45, 0.72, 1.0)  # blu scuro
mix.inputs[7].default_value = (0.35, 0.60, 0.88, 1.0)  # blu chiaro
links.new(noise.outputs["Fac"], mix.inputs[0])
links.new(mix.outputs[2], bsdf.inputs["Base Color"])

bsdf.inputs["Roughness"].default_value = 0.10
set_input(bsdf, "IOR", value=1.52)
set_input(bsdf, "Coat Weight", "Clearcoat", value=0.3)
set_input(bsdf, "Coat Roughness", "Clearcoat Roughness", value=0.04)

# 3. Assegna
apply_mat("Vase", mat)

# 4. Render Cycles
setup_cycles(samples=128, exposure=0.1)
world_color()
result = {"mat": mat.name, "applied": True}
```

Attribution

MAX-786MAX-786
View sourceSee grades on GitHubMore from MAX-786 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698431 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →