Blender scripting can seem intimidating at first, but once you start exploring it, the possibilities for saving time and improving results are endless. Recently, I’ve been diving into scripting while working on a 3D UI project for Decentraland’s In World Builder, and I’d like to share how it made my workflow smoother and more efficient. If you’re looking to automate tedious tasks and spend more time on the creative side of things, this one’s for you.

If you're completely new to Blender or Scripting, take a look at this post first:

The Situation: For this particular project, I was tasked with creating letters, numbers, and symbols for the In World Builder in Decentraland. Each character had different fonts and colorways, which resulted in a massive set of over 1600 files. As you can imagine, manually exporting each asset would’ve been a time-consuming nightmare.
Enter Blender Scripting: I knew there had to be a better way to handle the exporting process. So, I wrote a Blender script to export each asset individually, using the object’s name to keep things organized. On top of that, the script automatically added custom colliders for each asset to ensure they worked smoothly in Decentraland.
Once the exporting was done, I realized I needed thumbnails for each asset too. Instead of manually rendering 1600 images (no, thank you!), I wrote another script. This one created a thumbnail render for each individual asset and exported it as a PNG file with the same name.

Not only did these scripts save me an incredible amount of time, but they also ensured consistency across all the assets.

Learning as You Go: The best part about Blender scripting? You don’t have to be an expert to make it work for you. I’m far from a scripting guru, but by experimenting and problem-solving, I was able to drastically improve my workflow. The key is staying curious and being willing to learn—scripting is just another tool in your creative toolbox.
Ready to Try? If you’re interested in trying these scripts yourself, I’ve included them below. Feel free to tweak, adjust, and experiment! And if you have any questions, drop a comment or reach out—I’m always happy to chat about ways to work smarter in Blender.
Let’s keep learning together. What tasks have you automated in Blender, or what processes do you think could benefit from scripting? Share your ideas, and let’s see where this methodology can take us next.
Scripts:
Script 1: Automating asset export with custom colliders.
# Exports each selected object into its own file with an additional collider cube
import bpy
import os
# Export to blend file location
basedir = os.path.dirname(bpy.data.filepath)
if not basedir:
raise Exception("Blend file is not saved")
# Define your custom set name here if needed
# set_name = "YourSetName"
view_layer = bpy.context.view_layer
obj_active = view_layer.objects.active
selection = bpy.context.selected_objects
bpy.ops.object.select_all(action='DESELECT')
for obj in selection:
# Select the object
obj.select_set(True)
# Set the active object for some exporters
view_layer.objects.active = obj
# Get the object name and file path for export
object_name = bpy.path.clean_name(obj.name)
# If you want to add a set name prefix, uncomment the next line:
# full_name = f"{set_name}_{object_name}"
fn = os.path.join(basedir, object_name)
# Create a simple cube for the collider
bpy.ops.mesh.primitive_cube_add(size=0.25)
collider = bpy.context.object
collider.name = object_name + "_collider"
collider.display_type = 'WIRE'
# Position the collider at the object's origin
collider.location = (obj.location.x, obj.location.y, obj.location.z + 0.15)
# Parent the collider to the object
collider.parent = obj
# Select both the object and the collider for export
collider.select_set(True)
obj.select_set(True)
# Export to GLB
try:
bpy.ops.export_scene.gltf(filepath=fn + ".glb", use_selection=True)
except AttributeError:
print("Error: glTF 2.0 Export Add-on is not enabled.")
break
# Deselect the objects
collider.select_set(False)
obj.select_set(False)
# Delete the collider after export
bpy.data.objects.remove(collider)
print("Written:", fn + ".glb")
# Restore the previous active object
view_layer.objects.active = obj_active
# Reselect the original selection
for obj in selection:
obj.select_set(True)
Script 2: Thumbnail rendering for each asset in PNG format.
import bpy
import os
# Define the resolution and file format for the thumbnails
thumbnail_size = 512
output_format = 'PNG' # You can adjust this if needed
# Export to blend file location
basedir = os.path.dirname(bpy.data.filepath)
if not basedir:
raise Exception("Blend file is not saved")
# Set render settings for thumbnails
bpy.context.scene.render.image_settings.file_format = output_format
bpy.context.scene.render.image_settings.color_mode = 'RGBA' # RGBA for transparency
bpy.context.scene.render.resolution_x = thumbnail_size
bpy.context.scene.render.resolution_y = thumbnail_size
bpy.context.scene.render.film_transparent = True # Make background transparent
bpy.context.scene.render.resolution_percentage = 100
# Add a sun lamp to the scene
def add_sunlight():
bpy.ops.object.light_add(type='SUN', align='WORLD', location=(10, -10, 10))
sun = bpy.context.object
sun.data.energy = 5 # Adjust light intensity if needed
sun.rotation_euler = (0.7854, 0, 0.7854) # Rotate sun for better illumination
return sun
# Set up the camera closer to the object
def setup_camera():
bpy.ops.object.camera_add(location=(0, -0.36, 0.195)) # Closer camera
camera = bpy.context.object
camera.rotation_euler = (1.3, 0, 0) # Adjust camera angle
bpy.context.scene.camera = camera
return camera
# Hide all objects except the current one
def hide_other_objects(exclude_object):
for obj in bpy.context.scene.objects:
if obj != exclude_object:
obj.hide_render = True
# Restore visibility for all objects
def show_all_objects():
for obj in bpy.context.scene.objects:
obj.hide_render = False
# Get the view layer and selected objects
view_layer = bpy.context.view_layer
selection = bpy.context.selected_objects
for obj in selection:
# Deselect all and select the current object
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
view_layer.objects.active = obj
# Hide all other objects from render
hide_other_objects(obj)
# Set up camera to frame the object
camera = setup_camera()
# Align the camera to fit the object (tightly frame the asset)
bpy.ops.view3d.camera_to_view_selected()
# Add sunlight for better illumination
sun = add_sunlight()
# Set the filename to the object name
object_name = bpy.path.clean_name(obj.name)
output_path = os.path.join(basedir, object_name + ".png")
# Render the thumbnail and save the image
bpy.context.scene.render.filepath = output_path
bpy.ops.render.render(write_still=True)
# Clean up by removing the camera and sun after render
bpy.data.objects.remove(camera)
bpy.data.objects.remove(sun)
# Show all objects again
show_all_objects()
print("Thumbnail created:", output_path)
# Reselect the original selection
for obj in selection:
obj.select_set(True)
Comentarios