www.xbdev.net
xbdev - software development
Wednesday July 16, 2025
Home | Contact | Support | Blender (.py) Scripts... Automating Blender ..
     
 

Blender (.py) Scripts...

Automating Blender ..

 

Jelly Soft Bodies


As well as rigid bodies, particles and other physics-based systems - Blender also supports 'soft bodies' - so you can create squish jelly like creations. What is more, they can interact with one another - bouncing off and around your scene.


A couple of jelly cubes falling on to a plane (and on top of one another).
A couple of jelly cubes falling on to a plane (and on top of one another).


The complete implementation is generated using a single script.

The code looks longer than it should - more than half the code is for clearing the scene and creating some nice looking materials (glassy jellow for the soft bodies and a simple floor).

import bpy
from mathutils import Vector

# ๐Ÿงน Deselect and delete all objects
bpy.ops.object.select_all(action='DESELECT')
for 
obj in bpy.context.scene.objects:
    
obj.select_set(True)
bpy.ops.object.delete()

# ๐Ÿงผ Clear materials
for mat in bpy.data.materials:
    
bpy.data.materials.remove(matdo_unlink=True)

# ๐Ÿ”ฅ Clear meshes
for mesh in bpy.data.meshes:
    
bpy.data.meshes.remove(meshdo_unlink=True)

# ๐Ÿ–ผ๏ธ Clear images
for image in bpy.data.images:
    if 
image.users == 0:
        
bpy.data.images.remove(image)

# ๐ŸŽจ Clear textures
for tex in bpy.data.textures:
    
bpy.data.textures.remove(tex)

# ๐Ÿ”— Optional: clean up unused node groups
for ng in bpy.data.node_groups:
    if 
ng.users == 0:
        
bpy.data.node_groups.remove(ng)

# ๐Ÿ’ฅ Bonus: remove cameras and lights too
for cam in bpy.data.cameras:
    
bpy.data.cameras.remove(cam)
for 
lamp in bpy.data.lights:
    
bpy.data.lights.remove(lamp)

# Create floor
bpy.ops.mesh.primitive_plane_add(size=10location=(000))
floor bpy.context.active_object
floor
.name "Floor"
floor.location.0

def create_glass_material
(name="GlassMaterial"):
    
# Check if it already exists
    
if name in bpy.data.materials:
        return 
bpy.data.materials[name]

    
# Create new material
    
mat bpy.data.materials.new(name=name)
    
mat.use_nodes True

    
# Clear default nodes
    
nodes mat.node_tree.nodes
    nodes
.clear()

    
# Add Glass BSDF
    
output nodes.new(type='ShaderNodeOutputMaterial')
    
glass nodes.new(type='ShaderNodeBsdfGlass')
    
glass.inputs["IOR"].default_value 1.45
    glass
.inputs["Roughness"].default_value 0.05

    
# ๐ŸŽจ Set color to blue (RGB)
    
glass.inputs["Color"].default_value = (0.01.00.31.0)  # (R, G, B, Alpha)

    # Link nodes
    
mat.node_tree.links.new(glass.outputs["BSDF"], output.inputs["Surface"])

    return 
mat

# Create or get glass material
glass_mat create_glass_material()


def create_floor_material(name="FloorMaterial"):
    
# Check if it already exists
    
if name in bpy.data.materials:
        return 
bpy.data.materials[name]

    
# Create new material
    
mat bpy.data.materials.new(name=name)
    
mat.use_nodes True

    
# Clear existing nodes
    
nodes mat.node_tree.nodes
    nodes
.clear()

    
# Add nodes
    
output nodes.new(type='ShaderNodeOutputMaterial')
    
diffuse nodes.new(type='ShaderNodeBsdfDiffuse')

    
# Set color to light gray (RGB)
    
diffuse.inputs["Color"].default_value = (0.80.80.81.0)

    
# Link nodes
    
mat.node_tree.links.new(diffuse.outputs["BSDF"], output.inputs["Surface"])

    return 
mat

floor_mat 
create_floor_material();

def addSoftCubeyy ):
    
# Create cube
    
bpy.ops.mesh.primitive_cube_add(size=1location=(00yy))
    
cube bpy.context.active_object
    cube
.name "JellyCube"
    
if cube.data.materials:
        
cube.data.materials[0] = glass_mat
    
else:
        
cube.data.materials.append(glass_mat)

    
    
# Apply subdivision for smoother deformation
    
bpy.ops.object.modifier_add(type='SUBSURF')
    
cube.modifiers["Subdivision"].levels 3
    cube
.modifiers["Subdivision"].render_levels 3
    bpy
.ops.object.modifier_apply(modifier="Subdivision")

    
bpy.context.view_layer.objects.active cube
    bpy
.ops.object.shade_smooth()

    
# Add soft body physics to the cube
    
cube.select_set(True)
    
bpy.context.view_layer.objects.active cube
    bpy
.ops.object.modifier_add(type='SOFT_BODY')
    
sb cube.modifiers["Softbody"]

    
# Configure soft body settings
    
cube.soft_body.use_goal False
    cube
.soft_body.use_edges True
    cube
.soft_body.use_self_collision False
    sb
.settings.shear 1
    sb
.settings.bend 0.9
    sb
.settings.use_stiff_quads True
    
    sb
.settings.pull 0.9     # Resistance to stretching
    
sb.settings.push 0.9     # Resistance to compression
    
sb.settings.damping 0.5  # General motion damping

    # Add collision modifier so cubes collide with each other
    
bpy.ops.object.modifier_add(type='COLLISION')
    

addSoftCube(3)
addSoftCube(2)

# Make the floor a collision object
bpy.context.view_layer.objects.active floor
bpy
.ops.object.modifier_add(type='COLLISION')
floor.data.materials.appendfloor_mat )

# Set gravity
bpy.context.scene.gravity = (00, -9.81)

# Set timeline
bpy.context.scene.frame_start 1
bpy
.context.scene.frame_end 100

# Set cube origin for better squish behavior
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS'center='BOUNDS')


# === ADD LIGHT ===
bpy.ops.object.light_add(type='AREA'location=(4, -46))
light bpy.context.active_object
light
.data.energy 1500

# === ADD CAMERA ===
bpy.ops.object.camera_add(location=(6, -64), rotation=(1.200.8))
bpy.context.scene.camera bpy.context.active_object


Stairs


To make things more interesting - we can create a spiral staircase and put a jelly-ball at the top - of course, to make sure the ball doesn't just roll off the edge - we'll put spheres on each side. These jsut push the sphere inwards - we don't show them in the final render.


See the layout for the staircase - the spheres on the edge of the staircase are to keep the soft body on the staircase (do not ...
See the layout for the staircase - the spheres on the edge of the staircase are to keep the soft body on the staircase (do not draw them in the final render).


import bpy
from math import pisincos
from mathutils import Vector

# ๐Ÿงน Clear the scene
bpy.ops.object.select_all(action='DESELECT')
for 
obj in bpy.context.scene.objects:
    
obj.select_set(True)
bpy.ops.object.delete()

# ๐Ÿงผ Clear unused data
for block in [bpy.data.materialsbpy.data.meshesbpy.data.texturesbpy.data.images]:
    for 
item in block:
        
block.remove(item)

def create_glass_material(name="GlassMaterial"):
    
# Check if it already exists
    
if name in bpy.data.materials:
        return 
bpy.data.materials[name]

    
# Create new material
    
mat bpy.data.materials.new(name=name)
    
mat.use_nodes True

    
# Clear default nodes
    
nodes mat.node_tree.nodes
    nodes
.clear()

    
# Add Glass BSDF
    
output nodes.new(type='ShaderNodeOutputMaterial')
    
glass nodes.new(type='ShaderNodeBsdfGlass')
    
glass.inputs["IOR"].default_value 1.45
    glass
.inputs["Roughness"].default_value 0.05

    
# ๐ŸŽจ Set color to blue (RGB)
    
glass.inputs["Color"].default_value = (0.01.00.31.0)  # (R, G, B, Alpha)

    # Link nodes
    
mat.node_tree.links.new(glass.outputs["BSDF"], output.inputs["Surface"])

    return 
mat


# Create materials
def create_material(namecolorroughness=0.0metallic=0.0):
    
mat bpy.data.materials.new(name=name)
    
mat.use_nodes True
    nodes 
mat.node_tree.nodes
    nodes
.clear()
    
    
output nodes.new(type='ShaderNodeOutputMaterial')
    
principled nodes.new(type='ShaderNodeBsdfPrincipled')
    
principled.inputs["Base Color"].default_value color
    principled
.inputs["Roughness"].default_value roughness
    principled
.inputs["Metallic"].default_value metallic
    
    mat
.node_tree.links.new(principled.outputs["BSDF"], output.inputs["Surface"])
    return 
mat

# Create materials
stair_mat create_material("StairMaterial", (0.80.70.61), 0.40.2)
# sphere_mat = create_material("SphereMaterial", (0.1, 0.8, 0.6, 1), 0.2)
floor_mat create_material("FloorMaterial", (0.90.90.91), 0.6)

# Create or get glass material
sphere_mat create_glass_material()


def create_circular_staircase(steps=20radius=2step_height=0.3step_width=1.5):
    
angle_step pi steps
    inner_radius 
radius 1.05  # Inner barrier radius
    
outer_radius radius 1.05  # Outer barrier radius
    
    # Create invisible spherical barriers
    
for i in range(steps):
        
angle angle_step
        z 
step_height step_height/2  # Center of step height
        
        # Inner barrier sphere
        
x_inner inner_radius cos(angle)
        
y_inner inner_radius sin(angle)
        
        
bpy.ops.mesh.primitive_uv_sphere_add(
            
radius=0.6,  # Sphere size
            
location=(x_innery_innerz),
            
segments=16,
            
ring_count=8
        
)
        
inner_barrier bpy.context.active_object
        inner_barrier
.name f"InnerBarrier_{i}"
        
bpy.ops.object.modifier_add(type='COLLISION')
        
inner_barrier.hide_render True
        inner_barrier
.collision.cloth_friction 0.0
        inner_barrier
.collision.damping 0.5  # Softer collisions
        
inner_barrier.hide_render True  
        
        
# Outer barrier sphere
        
x_outer outer_radius cos(angle)
        
y_outer outer_radius sin(angle)
        
        
bpy.ops.mesh.primitive_uv_sphere_add(
            
radius=0.6,
            
location=(x_outery_outerz),
            
segments=16,
            
ring_count=8
        
)
        
outer_barrier bpy.context.active_object
        outer_barrier
.name f"OuterBarrier_{i}"
        
bpy.ops.object.modifier_add(type='COLLISION')
        
outer_barrier.hide_render True
        outer_barrier
.collision.cloth_friction 0.0
        outer_barrier
.collision.damping 0.5
        outer_barrier
.hide_render True  
    
    
# Create visible cube steps
    
for i in range(steps):
        
angle angle_step
        x 
radius cos(angle)
        
radius sin(angle)
        
step_height
        
        
# Create step (still as cube)
        
bpy.ops.mesh.primitive_cube_add(size=1location=(xyz))
        
step bpy.context.active_object
        step
.name f"Step_{i}"
        
step.dimensions = (step_width0.3step_height)
        
step.rotation_euler.angle
        
        bpy
.ops.object.modifier_add(type='COLLISION')
        
step.data.materials.append(stair_mat)

# Create staircase with spherical barriers
create_circular_staircase(steps=40radius=2step_height=0.25step_width=1.9)


# Create soft body sphere
def create_soft_sphere(location=(008)):
    
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.5location=location)
    
sphere bpy.context.active_object
    sphere
.name "SoftSphere"
    
    
# Add subdivision for smoother deformation
    
bpy.ops.object.modifier_add(type='SUBSURF')
    
sphere.modifiers["Subdivision"].levels 2
    sphere
.modifiers["Subdivision"].render_levels 2
    bpy
.ops.object.shade_smooth()
    
    
# Add soft body physics
    
bpy.ops.object.modifier_add(type='SOFT_BODY')
    
sb sphere.modifiers["Softbody"]
    
    
# Configure soft body
    
sphere.soft_body.mass 1.0
    sphere
.soft_body.use_goal False
    sb
.settings.pull 0.9
    sb
.settings.push 0.9
    sb
.settings.damping 0.2
    sb
.settings.bend 0.6

    
# Add collision
    
bpy.ops.object.modifier_add(type='COLLISION')
    
    
# Add material
    
sphere.data.materials.append(sphere_mat)
    
    return 
sphere

# Create sphere at top of staircase
sphere create_soft_sphere(location=(1.8, -0.510.5))

# Create floor
bpy.ops.mesh.primitive_plane_add(size=20location=(00, -0.1))
floor bpy.context.active_object
floor
.name "Floor"
bpy.ops.object.modifier_add(type='COLLISION')
floor.data.materials.append(floor_mat)

# Set up physics world
bpy.context.scene.gravity = (00, -9.81)
bpy.context.scene.frame_start 1
bpy
.context.scene.frame_end 300

# Set up lighting
bpy.ops.object.light_add(type='SUN'location=(10, -1015))
light bpy.context.active_object
light
.data.energy 5
light
.rotation_euler = (0.800.8)

# Set up camera
bpy.ops.object.camera_add(
    
location=(12, -108),  # Pulled further back and higher
    
rotation=(1.400.8)  # Same angle but sees more
)
bpy.context.scene.camera bpy.context.active_object
bpy
.context.scene.camera.data.lens 24

# Set render settings for better visualization
bpy.context.scene.render.engine 'CYCLES'
bpy.context.scene.cycles.samples 64



Things to Try


Lots of cool things you can experiement with - once you get your head around how it works!

For example:

• Try creating other soft body shapes (torus, spheres, monkey-head, ..)
• Give them different physical properties (some are stiffer and rigid than others)
• Add a scene with 'lots' of soft bodies (20+)
• Create some 3d text that is also a soft body (so it's squishy and wobbly)












 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.