Hunyuan3D → Blender Skill
Pipeline Order
server_health— stop if unreachable- Build Hunyuan3D prompt — geometry-focused only, no color, no style words
generate_3d_async— kick off generation- Build scene while waiting — base disc + lights + camera only
check_generation_status— poll until complete- Convert path if on Windows
- Import the GLB
- Measure bounds — derive all numbers from real values
- Scale, centre, seat on base disc
- Shade smooth
- Apply color and material in Blender with mandatory verification
- Final verification against user request
- Screenshot to confirm
Critical Rules
- One object per scene. Hunyuan3D generates exactly one mesh. The scene contains exactly one HY3D hero object.
- Hunyuan3D is the only 3D modeler. Never create any 3D geometry in Blender — not primitives, not curves, nothing. Blender's role is strictly: import, place, color, light, camera.
- Never guess scale or position. Every number must come from measuring real bounding box values after import. No hardcoded offsets.
- Never auto-clear the scene. If the scene needs clearing, ask the user first.
- Never use raw Linux paths in Blender on Windows. Convert first — see Path Conversion below.
Hunyuan3D Prompt Rules — Shape Only, No Color
Describe geometry and form only. Never describe color, material, or texture in the prompt.
- Focus on shape: structure, proportions, surface detail, physical form.
- Avoid open-ended style or setting words ("fantasy", "magical", "cute", "tropical") — these cause Hunyuan3D to hallucinate extra geometry or unwanted decorations.
- Be specific and restrictive about what should NOT appear when hallucination risk is high.
- All color, texture, and material work happens in Blender after import — never in the Hunyuan3D prompt.
Prompt structure to follow:
- What the object IS (noun + key physical traits)
- Key structural details (shape of parts, proportions)
- Explicit exclusions if needed ("no vegetation", "no extra parts", "standalone object only")
Example — Good: "a detailed wooden chair, four straight legs, flat seat, vertical back slats, standalone object, no floor, no background"
Example — Bad: "a cozy rustic chair in a warm cottage setting with cushions"
The good prompt describes geometry. The bad prompt describes a scene and style — both of which cause hallucination.
Strict Object Restriction — CRITICAL
After the HY3D mesh is imported, NO additional Blender geometry may be created under any circumstance.
- The HY3D mesh is the deliverable. Its form must not be altered or overshadowed by any Blender geometry.
- Do not add decorations, props, layers, or supporting shapes based on assumptions or inferred intent from the user's description.
- The user's description is input for the Hunyuan3D prompt — it is not a Blender modeling instruction.
The ONLY objects permitted in the final scene without explicit user instruction:
- The HY3D mesh itself
- The base display disc
- Three lights
- One camera
Nothing else. Ever.
While Waiting — Scene Setup
While Hunyuan3D is generating, build exactly three things:
Base Disc:
- Bevelled cylinder, radius
1.4, depth0.05 - Neutral matte material —
#CCCCCC, roughness0.9 - Shade smooth via
poly.use_smooth = Trueon polygons — neverbpy.ops.object.shade_smooth - Name it
"Base" - Place at
location=(0, 0, -0.025)so its top surface is exactly atz=0
Lighting — 3-Point Rig:
- Key light: area, warm
(1.0, 0.95, 0.8), energy600, front-right(4, -3, 6) - Fill light: area, cool
(0.7, 0.85, 1.0), energy250, front-left(-4, -2, 4) - Rim light: area, accent
(1.0, 0.9, 0.6), energy350, behind(0, 5, 5)
Camera:
- 85mm lens
- 3/4 hero angle, positioned to frame the full model on the base
- Set as
scene.camera
Path Conversion — Windows + WSL
HY3D runs in WSL and returns a Linux path. Blender on Windows cannot read it directly. Always convert before importing:
import sys
def linux_to_windows_wsl(p):
return "\\\\wsl.localhost\\Ubuntu" + p.replace("/", "\\")
glb_path = linux_to_windows_wsl(linux_path) if sys.platform == "win32" else linux_path
If the WSL distro is not Ubuntu, replace with the correct name (e.g. Ubuntu-22.04).
Import Rules
- Deselect all objects before importing using a loop —
obj.select_set(False)— neverbpy.ops.object.select_all. - Import the GLB using
bpy.ops.import_scene.gltf(filepath=glb_path). - Collect only
MESHtype objects frombpy.context.selected_objectsafter import. - If the result is empty — stop immediately and raise a clear error. Do not proceed silently.
- Rename the imported mesh to
"HY3D_Model".
Placement Rules — Real Numbers Only
Every placement decision must be derived from measured bounding box values. No guessing. No hardcoded offsets.
# Measure bounds from world-space vertices
verts_world = [obj.matrix_world @ v.co for v in obj.data.vertices]
xs = [v.x for v in verts_world]
ys = [v.y for v in verts_world]
zs = [v.z for v in verts_world]
min_x, max_x = min(xs), max(xs)
min_y, max_y = min(ys), max(ys)
min_z, max_z = min(zs), max(zs)
width = max_x - min_x
depth = max_y - min_y
height = max_z - min_z
Scale:
- Target height =
2.0units scale_factor = 2.0 / height- Apply uniformly:
obj.scale = (scale_factor, scale_factor, scale_factor) - Apply transform:
bpy.ops.object.transform_apply(scale=True) - Re-measure bounds after scaling
Centre on X/Y:
obj.location.x -= (min_x + max_x) / 2obj.location.y -= (min_y + max_y) / 2
Seat on base disc:
- Base disc top surface is at
z=0 obj.location.z -= min_z— this places the model bottom exactly atz=0- Apply transform:
bpy.ops.object.transform_apply(location=True)
Re-measure and print after all transforms:
print(f"Final height: {height:.4f}")
print(f"Bottom z: {min_z:.4f} (should be 0.0)")
print(f"Centre x: {(min_x+max_x)/2:.4f} (should be ~0.0)")
print(f"Centre y: {(min_y+max_y)/2:.4f} (should be ~0.0)")
print(f"Scale factor: {scale_factor:.4f}")
Check orientation:
- If the model faces away from camera, rotate on Z axis to face front.
Shade smooth:
for poly in obj.data.polygons:
poly.use_smooth = True
obj.data.update()
Material & Color Rules
- All coloring and texturing happens in Blender after import — never in the Hunyuan3D prompt.
- Clear all existing GLB baked materials before assigning anything new:
obj.data.materials.clear() - Create a fresh material with a new Principled BSDF node tree.
- Match base color and roughness exactly to the user's specified values.
- If the user did not specify a color, use a sensible neutral default and note what was chosen.
Mandatory Material Verification
After assigning every material, run all three checks:
# 1. Confirm material is assigned
assert obj.data.materials[0].name == mat.name, "Material not assigned!"
# 2. Confirm node connectivity
nodes = mat.node_tree.nodes
links = mat.node_tree.links
bsdf = nodes.get("Principled BSDF")
output = nodes.get("Material Output")
assert bsdf is not None, "Principled BSDF node missing!"
assert output is not None, "Material Output node missing!"
connected = any(l.from_node == bsdf and l.to_node == output for l in links)
assert connected, "Principled BSDF not connected to Material Output!"
# 3. Print color confirmation
color = bsdf.inputs["Base Color"].default_value
print(f"Material '{mat.name}' verified — RGB: ({color[0]:.3f}, {color[1]:.3f}, {color[2]:.3f})")
If any check fails — delete the material, create it from scratch, and re-verify. Never patch existing nodes.
Final Verification — MANDATORY Before Screenshot
Check every item below. Print PASS or FAIL for each. Fix all FAILs before proceeding.
print("=== FINAL VERIFICATION ===")
print(f"Single HY3D object only: PASS/FAIL")
print(f"No extra Blender geometry: PASS/FAIL")
print(f"Model seated on base (z=0): PASS/FAIL")
print(f"Model centred on X/Y: PASS/FAIL")
print(f"Material verified: PASS/FAIL")
print(f"Color matches user request: PASS/FAIL")
print(f"Scene objects = HY3D + Base + 3 Lights + Camera only: PASS/FAIL")
print("==========================")
Do not take the screenshot until all checks are PASS.
Expected Final Scene
Scene
├── Base ← bevelled disc, z top = 0, neutral material
├── Key_Light ← area, warm
├── Fill_Light ← area, cool
├── Rim_Light ← area, accent
├── Camera ← scene.camera, 85mm
└── HY3D_Model ← single mesh, bottom at z=0, centred, material verified
This is the complete scene. Nothing else belongs here.
Troubleshooting
| Symptom | Fix |
|---|---|
RuntimeError: Please select a file |
Missing path conversion — run linux_to_windows_wsl() |
imported = [] |
Wrong WSL distro name, or file not yet written |
poll() failed, context is incorrect |
Use obj.select_set(False) loop instead of bpy.ops.object.select_all; use poly.use_smooth instead of bpy.ops.object.shade_smooth |
| Model too large or tiny | Re-derive scale factor from actual measured Z bounds |
| Model faces wrong way | Rotate on Z axis after seating |
| Model floating above base | Re-check min_z measurement and obj.location.z -= min_z step |
| Model sunk into base | Same — re-measure after every transform apply |
| Floating mesh fragments | Edit Mode → Merge by Distance |
| Material renders white in Cycles | Clear all materials first — obj.data.materials.clear() — then assign fresh Principled BSDF |
| Material verification assertion fails | Delete material entirely, recreate from scratch, re-verify |
| Hunyuan3D hallucinated extra geometry | Prompt was too open-ended — add explicit exclusions and re-generate |