Blender MCP Server

  • examples
import bpy import bmesh from mathutils import Vector def create_cube_with_uv(): # Clear existing objects bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete() # Create a cube bpy.ops.mesh.primitive_cube_add(size=2, location=(0, 0, 0)) cube = bpy.context.active_object cube.name = "UV_Cube" # Switch to edit mode to modify mesh and create UVs bpy.ops.object.mode_set(mode='EDIT') # Get the mesh data in edit mode me = cube.data bm = bmesh.from_edit_mesh(me) # Ensure UV layers exist if not bm.loops.layers.uv: bm.loops.layers.uv.new("UVMap") uv_layer = bm.loops.layers.uv.active # Create a simple UV mapping (cube unwrap) # Each face will get a portion of the UV space faces = [f for f in bm.faces] # Simple planar UV mapping based on face normal direction for i, face in enumerate(faces): # Calculate uv position (divide UV space into a 3x2 grid) row = i // 3 col = i % 3 # Define UV coordinates for this face min_u, max_u = col / 3, (col + 1) / 3 min_v, max_v = row / 2, (row + 1) / 2 # Define corner indices for different UV layouts based on face orientation if face.normal.to_tuple(1) in [(0, 0, 1), (0, 0, -1)]: # top/bottom indices = [0, 1, 2, 3] elif face.normal.to_tuple(1) in [(0, 1, 0), (0, -1, 0)]: # front/back indices = [0, 1, 2, 3] else: # sides indices = [0, 1, 2, 3] # UV coordinates for the corners of this face in the UV grid uvs = [ Vector((min_u, min_v)), Vector((max_u, min_v)), Vector((max_u, max_v)), Vector((min_u, max_v)) ] # Assign UV coordinates to the face for j, loop in enumerate(face.loops): loop[uv_layer].uv = uvs[indices[j]] # Update the mesh bmesh.update_edit_mesh(me) # Switch back to object mode bpy.ops.object.mode_set(mode='OBJECT') # Create a material with a texture create_textured_material(cube) print("Created a cube with UV mapping") return cube def create_textured_material(obj): # Create a new material mat = bpy.data.materials.new(name="Textured_Material") mat.use_nodes = True # Clear default nodes node_tree = mat.node_tree for node in node_tree.nodes: node_tree.nodes.remove(node) # Create texture coordinate node tex_coord = node_tree.nodes.new(type='ShaderNodeTexCoord') tex_coord.location = (-600, 0) # Create checker texture node checker = node_tree.nodes.new(type='ShaderNodeTexChecker') checker.location = (-400, 0) checker.inputs['Scale'].default_value = 4.0 # Larger checkers checker.inputs['Color1'].default_value = (0.8, 0.1, 0.1, 1.0) # Red checker.inputs['Color2'].default_value = (0.1, 0.1, 0.8, 1.0) # Blue # Create BSDF node bsdf = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled') bsdf.location = (-100, 0) # Create output node output = node_tree.nodes.new(type='ShaderNodeOutputMaterial') output.location = (200, 0) # Link nodes node_tree.links.new(tex_coord.outputs['UV'], checker.inputs['Vector']) node_tree.links.new(checker.outputs['Color'], bsdf.inputs['Base Color']) node_tree.links.new(bsdf.outputs['BSDF'], output.inputs['Surface']) # Assign material to object if obj.data.materials: obj.data.materials[0] = mat else: obj.data.materials.append(mat) print("Created textured material with checker pattern") def create_uv_mapped_plane(): # Create a plane bpy.ops.mesh.primitive_plane_add(size=2, location=(3, 0, 0)) plane = bpy.context.active_object plane.name = "UV_Plane" # Subdivide for more detail bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.subdivide(number_cuts=4) # Smart UV project bpy.ops.uv.smart_project(angle_limit=66, island_margin=0.02) # Switch back to object mode bpy.ops.object.mode_set(mode='OBJECT') # Create a gradient material create_gradient_material(plane) print("Created a plane with smart UV projection") return plane def create_gradient_material(obj): # Create a new material mat = bpy.data.materials.new(name="Gradient_Material") mat.use_nodes = True # Clear default nodes node_tree = mat.node_tree for node in node_tree.nodes: node_tree.nodes.remove(node) # Create texture coordinate node tex_coord = node_tree.nodes.new(type='ShaderNodeTexCoord') tex_coord.location = (-600, 0) # Create gradient texture node gradient = node_tree.nodes.new(type='ShaderNodeTexGradient') gradient.location = (-400, 0) # Create color ramp for the gradient color_ramp = node_tree.nodes.new(type='ShaderNodeValToRGB') color_ramp.location = (-200, 0) # Customize the color ramp color_ramp.color_ramp.elements[0].color = (0.0, 0.5, 0.0, 1.0) # Green color_ramp.color_ramp.elements[1].color = (1.0, 1.0, 0.0, 1.0) # Yellow # Add a middle element element = color_ramp.color_ramp.elements.new(0.5) element.color = (0.0, 0.8, 0.8, 1.0) # Cyan # Create BSDF node bsdf = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled') bsdf.location = (0, 0) # Create output node output = node_tree.nodes.new(type='ShaderNodeOutputMaterial') output.location = (200, 0) # Link nodes node_tree.links.new(tex_coord.outputs['UV'], gradient.inputs['Vector']) node_tree.links.new(gradient.outputs['Fac'], color_ramp.inputs['Fac']) node_tree.links.new(color_ramp.outputs['Color'], bsdf.inputs['Base Color']) node_tree.links.new(bsdf.outputs['BSDF'], output.inputs['Surface']) # Assign material to object if obj.data.materials: obj.data.materials[0] = mat else: obj.data.materials.append(mat) print("Created gradient material") def create_uv_sphere_with_seams(): # Create a sphere bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(-3, 0, 0), segments=32, ring_count=16) sphere = bpy.context.active_object sphere.name = "UV_Sphere" # Switch to edit mode bpy.ops.object.mode_set(mode='EDIT') # Select all edges bpy.ops.mesh.select_all(action='DESELECT') # Get the mesh data me = sphere.data bm = bmesh.from_edit_mesh(me) # Mark some edges as seams for better unwrapping # Select edges along longitude for edge in bm.edges: v1, v2 = edge.verts # Edges along longitude line (connecting top to bottom) if abs(v1.co.x) < 0.01 and abs(v2.co.x) < 0.01 and v1.co.y * v2.co.y >= 0: edge.select = True # Mark selected edges as seams bpy.ops.mesh.mark_seam(clear=False) # Select all faces bpy.ops.mesh.select_all(action='SELECT') # Unwrap using the seams bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.02) # Switch back to object mode bpy.ops.object.mode_set(mode='OBJECT') # Create a grid material create_grid_material(sphere) print("Created a sphere with seam-based UV unwrapping") return sphere def create_grid_material(obj): # Create a new material mat = bpy.data.materials.new(name="Grid_Material") mat.use_nodes = True # Clear default nodes node_tree = mat.node_tree for node in node_tree.nodes: node_tree.nodes.remove(node) # Create texture coordinate node tex_coord = node_tree.nodes.new(type='ShaderNodeTexCoord') tex_coord.location = (-600, 0) # Create mapping node for extra control mapping = node_tree.nodes.new(type='ShaderNodeMapping') mapping.location = (-400, 0) mapping.inputs['Scale'].default_value = (10, 10, 10) # More grid cells # Create grid texture node grid = node_tree.nodes.new(type='ShaderNodeTexGrid') grid.location = (-200, 0) grid.inputs['Scale'].default_value = 1.0 grid.inputs['Line Width'].default_value = 0.02 # Create BSDF node bsdf = node_tree.nodes.new(type='ShaderNodeBsdfPrincipled') bsdf.location = (0, 0) bsdf.inputs['Base Color'].default_value = (0.2, 0.5, 0.8, 1.0) # Blue # Create output node output = node_tree.nodes.new(type='ShaderNodeOutputMaterial') output.location = (200, 0) # Link nodes node_tree.links.new(tex_coord.outputs['UV'], mapping.inputs['Vector']) node_tree.links.new(mapping.outputs['Vector'], grid.inputs['Vector']) node_tree.links.new(grid.outputs['Fac'], bsdf.inputs['Emission Strength']) node_tree.links.new(bsdf.outputs['BSDF'], output.inputs['Surface']) # Assign material to object if obj.data.materials: obj.data.materials[0] = mat else: obj.data.materials.append(mat) print("Created grid material for UV visualization") def save_blend_file(filepath="/tmp/uv_mapping_example.blend"): bpy.ops.wm.save_as_mainfile(filepath=filepath) print(f"Saved blend file to: {filepath}") return filepath # Main function to create all examples def create_uv_examples(): # Create camera for better view bpy.ops.object.camera_add(location=(0, -10, 2), rotation=(1.4, 0, 0)) bpy.context.scene.camera = bpy.context.object # Create objects with UV mappings cube = create_cube_with_uv() plane = create_uv_mapped_plane() sphere = create_uv_sphere_with_seams() # Set up render settings bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.cycles.device = 'CPU' # Add a light for better visualization bpy.ops.object.light_add(type='SUN', location=(0, 0, 5)) # Save the file for later use filepath = save_blend_file() return { 'objects': [cube.name, plane.name, sphere.name], 'blend_file': filepath } # Run the examples result = create_uv_examples() print("\nCreated examples:") for obj_name in result['objects']: print(f"- {obj_name}") print(f"\nBlend file saved to: {result['blend_file']}") print("You can use this file to study the UV mappings or modify them further.")