Today we’ll see how to programmatically spawn an object you created at specific locations. I’ll be using the 2.90 version of Blender.
Now, suppose you created an object, like a tree, and now want to spawn it multiple times in the scene. You could use particles, but they don’t give you full control. If you want to add the tree objects at specific locations, you can use Python.
So, here’s what we are going to do. First we’ll model a simple tree. Then we’ll add a plane, select some vertices on the plane and spawn the trees at the selected vertices. And we’ll do it by means of a Python script.
So, let’s get to work. Here are the steps to follow:
Table of Contents
Step 1 – Model a Tree
First, delete the default cube and add a cylinder. Move it up (G Z 1), go to edit mode and move the origin point to its base by selecting all and hitting G Z 1. Go back to object mode and move the cylinder down (G Z -1):
Scale the cylinder down on the X and Y axes (S Shift+Z 0.2):
Go to edit mode, toggle on the Show X-Ray button and select the vertices at the top. Extrude and scale (E S 4). Extrude again (E 2):
Merge the vertices at center:
Here’s our simple tree model in edit mode:
And in object mode after shading it smooth (the Shade Smooth option can be found in the Object menu):
Step 2 – Add Materials to the Tree
Let’s add a material to the tree. Set the base color to a shade of green of your choice. Then, in edit mode, select just the faces that make up the trunk and assign a new material to them by first clicking on the plus sign button to add a new material slot and then pressing the New button to add a new material. Set the base color of this material to a shade of brown and hit the Assign button to assign the material to the trunk of the tree. Here’s what you should see in Material Preview:
We’re almost done with the tree. Go back to object mode and rename the cylinder ‘tree’ in the Outliner:
The last thing we have to do is apply the scale. To this end hit N to open the sidebar and you will see that the scale is not 1:
In order to make it 1, go to the Object menu and select Apply -> Scale:
Now the scale in the sidebar is 1:
Step 3 – Add the Plane
Now that we have a tree model, let’s add a plane that will be the ground the trees will be spawned on. So, hit Shift + A and under Mesh select Plane. Scale it by a factor of 50 (S 50) and in edit mode subdivide it. You will find the Subdivide option in the Edge menu. Set the number of cuts to 100:
Let’s add some hills. Select a couple vertices. I selected five. Enable proportional editing (A) and move them up (G Z 6). Make sure the circle is pretty big. I used a circle with the size of 25.55 (B):
Hit Enter when you’re done.
Step 5 – Add a Material to the Plane
Add a material to the plane. Set its base color to a shade of brown:
Step 6 – Create a New Collection
As we’re going to create quite a few tree objects, it’s a good idea to put them in a separate collection. This will help us keep things organized. To add a collection right-click on Scene Collection (A) and select New Collection.
Rename the collection ‘trees’ and drag the tree object to it:
Step 7 – Select the Locations to Spawn At
We’re ready to finally write the script, but before we do, let’s go to edit mode, top view, and manually select the vertices where we want to spawn the trees. Let’s start with just a couple vertices, like ten. Here are the vertices that I selected:
I want ten trees at these exact locations.
Step 8 – Write the Python Script
With the vertices selected, go to the Scripting Workspace, add a new script and type in the code below. All explanations are in the comments:
# We need the bpy module to do most stuff in Blender Python.
import bpy
# Let's assign our tree object to a variable.
tree = bpy.data.objects['tree']
# Let's access the active object, which is the plane.
obj = bpy.context.active_object
# Now we can create the list of all the vertices that we just selected.
# To do that we can use a list comprehension. We use co array of the
# MeshVertex struct to access the local certex coordinate. In order to
# get global vertex coordinates we must multiply it by the world
# transformation matrix.
selected = [(obj.matrix_world @ v.co) for v in obj.data.vertices if v.select]
# Now we can loop through all the selected vertices and add a tree at each of them.
for vertex in selected:
# We need a name for each tree. So, let's create it by concatenating the word
# 'tree' with the coordinates of the tree.
name = f'tree {vertex}'
# Now we can create a new tree, give it the name and object data from the
# original tree. We'll assign the new tree to a variable.
new_tree = bpy.data.objects.new(name=name, object_data=tree.data)
# We'll position the tree at the coordinates of the selected vertex.
new_tree.location = (vertex[0], vertex[1], vertex[2])
# Finally, let's add the tree to the trees collection.
bpy.data.collections["trees"].objects.link(new_tree)
Step 9 – Run the Script
Before you run the script, make sure the plane is selected in object mode. Then you can go to edit mode to watch the selected vertices and the trees that will appear there. Now hit the Run Script button:
You should now see the trees added at the locations that we previously selected:
Step 10 – A More Complex Example
The example works fine, but let’s add some variation to it. We can additionally randomly rotate and scale each new tree. Besides, we’ll add more trees. Before you continue, hit Ctrl + Z to undo the previous operation, which means remove all the trees you just added. Then go back to Layout workspace, top view and deselect all. Then in the Select menu (A) select Select Random and set Percent to 10 (B):
Now 10% of the vertices is selected. Go to the Scripting workspace and modify the script like so:
# We need the bpy module to do most stuff in Blender Python.
import bpy
# We'll also need some functions from the random module to randomize
# the rotation and scale of the trees.
from random import randint, uniform
# We'll rotate the trees, but the rotation_euler method that we're
# going to use accepts angles in radians. So we can use the radians
# function from the math module in order to convert degrees to radians.
from math import radians
# Let's assign our tree object to a variable.
tree = bpy.data.objects['tree']
# Let's access the active object, which is the plane.
obj = bpy.context.active_object
# Now we can create the list of all the vertices that we just selected.
# To do that we can use a list comprehension. We use co array of the
# MeshVertex struct to access the local certex coordinate. In order to
# get global vertex coordinates we must multiply it by the world
# transformation matrix.
selected = [(obj.matrix_world @ v.co) for v in obj.data.vertices if v.select]
# Now we can loop through all the selected vertices and add a tree at each of them.
for vertex in selected:
# We need a name for each tree. So, let's create it by concatenating the word
# 'tree' with the coordinates of the tree.
name = f'tree {vertex}'
# Now we can create a new tree, give it the name and object data from the
# original tree. We'll assign the new tree to a variable.
new_tree = bpy.data.objects.new(name=name, object_data=tree.data)
# We'll position the tree at the coordinates of the selected vertex.
new_tree.location = (vertex[0], vertex[1], vertex[2])
# Now we need random angles for all three axes. They should be between -10 and
# 10 degrees for the X and Y axes and between -45 and 45 for the Z axis.
angleX = randint(-10, 10)
angleY = randint(-10, 10)
angleZ = randint(-45, 45)
# Now we can use the angles to rotate the tree. We must remember to use radians,
# though, so let's use the radians function to convert from degrees.
new_tree.rotation_euler = (radians(angleX), radians(angleY), radians(angleZ))
# We also want to scale the trees randomly so that they look more natural. Let's
# pick a random scale between 0.6 and 3 for example.
scale = uniform(0.6, 3)
# Let's use the same scale for all three axes.
new_tree.scale = (scale, scale, scale)
# Finally, let's add the tree to the trees collection.
bpy.data.collections["trees"].objects.link(new_tree)
Run the script. You should see the trees:
Go to the Layout workspace to see it better:
As you can see, the trees are rotated and scaled randomly. But what’s of most interest to us in this article is that they are at the exact positions we wanted them to be.