Category: Blender

Blender – Box Trim Not Supported in Dynamic Topology Mode

I hand-sculpted bases for my chess set before realizing that I wanted them to be very identical. So I wanted to “cut” the hand-sculpted base off of the figure and replace it with a programmatic one. Except I kept getting this error using box trim — Not supported in dynamic topology mode.

Switch to a drawing brush and uncheck Dynamic Topology box

Then switch back to box trim and it actually trims

And then, of course, you need to remember to turn dynamic topography back on for the drawing tools to draw.

 

Cat Chess – Kitten Queen

I copied the pawn and grew her a little. Added a crown and necklace … voila, a kitten queen! I’ve been using the smooth brush a lot to even out the surface. I’m curious how these will 3d print because the model is made up of a lot of little triangles.

421,132 to be exact. As I’ve discovered, you can configure the viewport to add data in overlays. Statistics is a nice one!

Blender – Python Script to Build Bases for Chess Pieces

Originally, I wanted to sculpt the entire thing in python, but it appears that the programmatic interface only works in defined shapes. I guess I could construct millions of tiny triangles? polygons? to create cats … but I suspect that using the actual sculpting tools is going to be the easier approach.

However, the base of each piece seems perfect for a script. This will ensure consistency in my chess pieces (and let me play around with the Python approach since I think it is really cool that Blender takes Python code!). I am making decorated cylinders onto which my figures will sit.

import bpy
import bmesh
import math

INCH = 0.0254  # meters per inch

params = {
    # Cylinder base size
    "base_diameter_in": 1.75,
    "base_height_in": 0.25,

    # Wreath hemispheres
    "hemi_count": 24,
    "hemi_radius_in": 0.05,
    "hemi_offset_in": 0.125,  # inward from base outer edge

    # Collection
    "collection_name": "Chess_Base",
}

def inch(v): 
    return v * INCH

def ensure_collection(name):
    if name in bpy.data.collections:
        return bpy.data.collections[name]
    col = bpy.data.collections.new(name)
    bpy.context.scene.collection.children.link(col)
    return col

COL = ensure_collection(params["collection_name"])

def build_base():
    base_r = inch(params["base_diameter_in"]) / 2.0
    base_h = inch(params["base_height_in"])
    # Place the base so its top is at Z = base_h (sitting on Z=0 plane)
    bpy.ops.mesh.primitive_cylinder_add(radius=base_r, depth=base_h, location=(0, 0, base_h / 2.0))
    base = bpy.context.active_object
    base.name = "Chess_Base_Cylinder"
    # Link explicitly to target collection (in case active collection differs)
    if base.name not in COL.objects:
        COL.objects.link(base)
    return base

def make_hemisphere_mesh(radius_m, segments=32, rings=16):
    bpy.ops.mesh.primitive_uv_sphere_add(radius=radius_m, segments=segments, ring_count=rings, location=(0, 0, 0))
    sph = bpy.context.active_object
    bm = bmesh.new()
    bm.from_mesh(sph.data)
    # Keep the top hemisphere: delete vertices with z < 0 (tolerance to avoid floating error)
    to_delete = [v for v in bm.verts if v.co.z < -1e-7]
    if to_delete:
        bmesh.ops.delete(bm, geom=to_delete, context='VERTS')
    bm.to_mesh(sph.data)
    bm.free()
    hemi_mesh = sph.data
    hemi_mesh.name = "Hemisphere_Mesh"
    # Remove the temporary object but keep the mesh datablock
    bpy.data.objects.remove(sph, do_unlink=True)
    return hemi_mesh

def build_wreath_hemispheres(hemi_mesh):
    base_r = inch(params["base_diameter_in"]) / 2.0
    base_h = inch(params["base_height_in"])
    ring_r = base_r - inch(params["hemi_offset_in"])
    count = params["hemi_count"]

    hemis = []
    for i in range(count):
        theta = (i / count) * 2.0 * math.pi
        cx = ring_r * math.cos(theta)
        cy = ring_r * math.sin(theta)
        obj = bpy.data.objects.new(f"Hemi_{i:02d}", hemi_mesh)
        # Flat face of hemisphere (its equator at local Z=0) sits on base top (Z=base_h)
        obj.location = (cx, cy, base_h)
        COL.objects.link(obj)
        hemis.append(obj)

    # Join hemispheres into a single object
    bpy.ops.object.select_all(action='DESELECT')
    for o in hemis:
        o.select_set(True)
    bpy.context.view_layer.objects.active = hemis[0]
    bpy.ops.object.join()
    wreath = bpy.context.active_object
    wreath.name = "Wreath_Hemispheres"
    return wreath

def build_all():
    base = build_base()
    hemi_mesh = make_hemisphere_mesh(inch(params["hemi_radius_in"]))
    wreath = build_wreath_hemispheres(hemi_mesh)
    print("Built:", base.name, wreath.name)

build_all()