Merge branch 'ahujasid:main' into rodin-intergration

This commit is contained in:
ElgoogUdiab 2025-03-17 17:21:31 +08:00 committed by GitHub
commit 648ed244fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 74 deletions

View File

@ -5,6 +5,7 @@ BlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP
## Release notes (1.1.0)
- Added support for Poly Haven assets through their API
- Added support to prompt 3D models using Hyper3D Rodin
- For newcomers, you can go straight to Installation. For existing users, see the points below
- Download the latest addon.py file and replace the older one, then add it to Blender
- Delete the MCP server from Claude and add it back again, and you should be good to go!
@ -33,13 +34,17 @@ The system consists of two main components:
- Python 3.10 or newer
- uv package manager:
If you're on Mac, please install uv as
**If you're on Mac, please install uv as**
```bash
brew install uv
```
On Windows
**On Windows**
```bash
pip install uv
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```
and then
```bash
set Path=C:\Users\nntra\.local\bin;%Path%
```
Otherwise installation instructions are on their website: [Install uv](https://docs.astral.sh/uv/getting-started/installation/)
@ -104,22 +109,15 @@ Once the config file has been set on Claude, and the addon is running on Blender
![BlenderMCP in the sidebar](assets/hammer-icon.png)
#### Tools
#### Capabilities
- `get_scene_info` - Gets scene information
- `get_object_info` - Gets detailed information for a specific object in the scene
- `create_primitive` - Create basic primitive objects with optional color
- `set_object_property` - Set a single property of an object
- `create_object` - Create a new object with detailed parameters
- `modify_object` - Modify an existing object's properties
- `delete_object` - Remove an object from the scene
- `set_material` - Apply or create materials for objects
- `execute_blender_code` - Run any Python code in Blender
- `get_polyhaven_categories` - Get a list of categories for PolyHaven assets (HDRIs, textures, models)
- `search_polyhaven_assets` - Search for assets on PolyHaven with optional category filtering
- `download_polyhaven_asset` - Download and import a PolyHaven asset into Blender
- Get scene and object information
- Create, delete and modify shapes
- Apply or create materials for objects
- Execute any Python code in Blender
- Download the right models, assets and HDRIs through [Poly Haven](https://polyhaven.com/)
- AI generated 3D models through [Hyper3D Rodin](https://hyper3d.ai/)
To see everything in Poly Haven, [see here](https://polyhaven.com/)
### Example Commands
@ -128,6 +126,7 @@ Here are some examples of what you can ask Claude to do:
- "Create a low poly scene in a dungeon, with a dragon guarding a pot of gold" [Demo](https://www.youtube.com/watch?v=DqgKuLYUv00)
- "Create a beach vibe using HDRIs, textures, and models like rocks and vegetation from Poly Haven" [Demo](https://www.youtube.com/watch?v=I29rn92gkC4)
- Give a reference image, and create a Blender scene out of it [Demo](https://www.youtube.com/watch?v=FDRb03XPiRo)
- "Generate a 3D model of a garden gnome through Hyper3D"
- "Get information about the current scene, and make a threejs sketch from it" [Demo](https://www.youtube.com/watch?v=jxbNI5L7AH8)
- "Make this car red and metallic"
- "Create a sphere and place it above the cube"

120
addon.py
View File

@ -268,63 +268,81 @@ class BlenderMCPServer:
align="WORLD", major_segments=48, minor_segments=12, mode="MAJOR_MINOR",
major_radius=1.0, minor_radius=0.25, abso_major_rad=1.25, abso_minor_rad=0.75, generate_uvs=True):
"""Create a new object in the scene"""
# Deselect all objects
bpy.ops.object.select_all(action='DESELECT')
try:
# Deselect all objects first
bpy.ops.object.select_all(action='DESELECT')
if type == "CUBE":
bpy.ops.mesh.primitive_cube_add(location=location, rotation=rotation, scale=scale)
elif type == "SPHERE":
bpy.ops.mesh.primitive_uv_sphere_add(location=location, rotation=rotation, scale=scale)
elif type == "CYLINDER":
bpy.ops.mesh.primitive_cylinder_add(location=location, rotation=rotation, scale=scale)
elif type == "PLANE":
bpy.ops.mesh.primitive_plane_add(location=location, rotation=rotation, scale=scale)
elif type == "CONE":
bpy.ops.mesh.primitive_cone_add(location=location, rotation=rotation, scale=scale)
elif type == "TORUS":
bpy.ops.mesh.primitive_torus_add(
align=align,
location=location,
rotation=rotation,
major_segments=major_segments,
minor_segments=minor_segments,
mode=mode,
major_radius=major_radius,
minor_radius=minor_radius,
abso_major_rad=abso_major_rad,
abso_minor_rad=abso_minor_rad,
generate_uvs=generate_uvs
)
elif type == "EMPTY":
bpy.ops.object.empty_add(location=location, rotation=rotation, scale=scale)
elif type == "CAMERA":
bpy.ops.object.camera_add(location=location, rotation=rotation)
elif type == "LIGHT":
bpy.ops.object.light_add(type='POINT', location=location, rotation=rotation, scale=scale)
else:
raise ValueError(f"Unsupported object type: {type}")
# Create the object based on type
if type == "CUBE":
bpy.ops.mesh.primitive_cube_add(location=location, rotation=rotation, scale=scale)
elif type == "SPHERE":
bpy.ops.mesh.primitive_uv_sphere_add(location=location, rotation=rotation, scale=scale)
elif type == "CYLINDER":
bpy.ops.mesh.primitive_cylinder_add(location=location, rotation=rotation, scale=scale)
elif type == "PLANE":
bpy.ops.mesh.primitive_plane_add(location=location, rotation=rotation, scale=scale)
elif type == "CONE":
bpy.ops.mesh.primitive_cone_add(location=location, rotation=rotation, scale=scale)
elif type == "TORUS":
bpy.ops.mesh.primitive_torus_add(
align=align,
location=location,
rotation=rotation,
major_segments=major_segments,
minor_segments=minor_segments,
mode=mode,
major_radius=major_radius,
minor_radius=minor_radius,
abso_major_rad=abso_major_rad,
abso_minor_rad=abso_minor_rad,
generate_uvs=generate_uvs
)
elif type == "EMPTY":
bpy.ops.object.empty_add(location=location, rotation=rotation, scale=scale)
elif type == "CAMERA":
bpy.ops.object.camera_add(location=location, rotation=rotation)
elif type == "LIGHT":
bpy.ops.object.light_add(type='POINT', location=location, rotation=rotation, scale=scale)
else:
raise ValueError(f"Unsupported object type: {type}")
# Get the created object
bpy.context.view_layer.update()
obj = bpy.context.view_layer.objects.active
# Force update the view layer
bpy.context.view_layer.update()
# Rename the object if a name is provided
if name:
obj.name = name
# Get the active object (which should be our newly created object)
obj = bpy.context.view_layer.objects.active
result = {
"name": obj.name,
"type": obj.type,
"location": [obj.location.x, obj.location.y, obj.location.z],
"rotation": [obj.rotation_euler.x, obj.rotation_euler.y, obj.rotation_euler.z],
"scale": [obj.scale.x, obj.scale.y, obj.scale.z],
}
# If we don't have an active object, something went wrong
if obj is None:
raise RuntimeError("Failed to create object - no active object")
if obj.type == "MESH":
bounding_box = self._get_aabb(obj)
result["world_bounding_box"] = bounding_box
# Make sure it's selected
obj.select_set(True)
return result
# Rename if name is provided
if name:
obj.name = name
if obj.data:
obj.data.name = name
# Return the object info
result = {
"name": obj.name,
"type": obj.type,
"location": [obj.location.x, obj.location.y, obj.location.z],
"rotation": [obj.rotation_euler.x, obj.rotation_euler.y, obj.rotation_euler.z],
"scale": [obj.scale.x, obj.scale.y, obj.scale.z],
}
if obj.type == "MESH":
bounding_box = self._get_aabb(obj)
result["world_bounding_box"] = bounding_box
return result
except Exception as e:
print(f"Error in create_object: {str(e)}")
traceback.print_exc()
return {"error": str(e)}
def modify_object(self, name, location=None, rotation=None, scale=None, visible=None):
"""Modify an existing object in the scene"""