From 5d4cd1db6dff08e89a61261096eaa8b1ebcd10ca Mon Sep 17 00:00:00 2001 From: ahujasid Date: Sat, 15 Mar 2025 21:27:16 +0530 Subject: [PATCH 1/5] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e996fda..9d93956 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,11 @@ brew install uv ``` 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/) From ec8b61a94848b06f73ebbca3f7a035be8576a822 Mon Sep 17 00:00:00 2001 From: ahujasid Date: Sat, 15 Mar 2025 21:27:49 +0530 Subject: [PATCH 2/5] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d93956..3f3db7e 100644 --- a/README.md +++ b/README.md @@ -33,11 +33,11 @@ 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 powershell -c "irm https://astral.sh/uv/install.ps1 | iex" ``` From 5e0f87cbc1ac7a84bbc683c54d5bfa82c7832b98 Mon Sep 17 00:00:00 2001 From: ahujasid Date: Sun, 16 Mar 2025 21:35:42 +0530 Subject: [PATCH 3/5] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3f3db7e..e7d2552 100644 --- a/README.md +++ b/README.md @@ -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! From 9c299304ceabdcf5aac9e6d39d1d225fea8d6c8e Mon Sep 17 00:00:00 2001 From: ahujasid Date: Sun, 16 Mar 2025 21:42:14 +0530 Subject: [PATCH 4/5] fixed the create_object nonetype error --- addon.py | 132 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 57 deletions(-) diff --git a/addon.py b/addon.py index d84a1d9..18e5ab5 100644 --- a/addon.py +++ b/addon.py @@ -266,63 +266,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') - - 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 - - # Rename the object if a name is provided - if name: - obj.name = name - - 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 + try: + # Deselect all objects first + bpy.ops.object.select_all(action='DESELECT') + + # 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}") + + # Force update the view layer + bpy.context.view_layer.update() + + # Get the active object (which should be our newly created object) + obj = bpy.context.view_layer.objects.active + + # If we don't have an active object, something went wrong + if obj is None: + raise RuntimeError("Failed to create object - no active object") + + # Make sure it's selected + obj.select_set(True) + + # 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""" From a3b862dda59ed0590cf15d64d3b9d170834d48c3 Mon Sep 17 00:00:00 2001 From: ahujasid Date: Sun, 16 Mar 2025 22:58:03 +0530 Subject: [PATCH 5/5] Update README.md --- README.md | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index e7d2552..c8a1f4a 100644 --- a/README.md +++ b/README.md @@ -109,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 @@ -133,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"