A couple weeks back, I posted a confetti function that was wildly fun to play with, but frustrating because all the confetti was oriented in the same direction.
In the end, I started selecting the individual planes at random to rotate the manually, but well, let’s face it. There were over 200 planes. That was just stupid. Two new lines of Python. That’s all it took. I actually wasn’t even the Python that threw me in the first place—it was the rotation operator.
How Does Transform.Rotate Work?
Here’s the thing about the rotation transform operation—the first parameter (unhelpfully referred to as “value” on the Blender API page) is the amount you wish to rotate your object. In radians.
Remembering that there are approximately 6.2 of those in a circle, we can adjust the rotation value to be a random number between 1 and 6.2.
The next parameter is axis. It takes three values—all of which should be numbers between 0 and 1—for which axis you wish to rotate around. X, Y, or Z.
So, for instance, if you wanted 10 planes randomly rotated around the y-axis, that could be accomplished by plugging in a loop like this:
Cool, right? I’m sure I’ll use that later at some point when I start modelling space ships, but back to the point.
An Updated Confetti Function
So, I added two lines to the existing function. First, the line assigning a random number to the variable R. Just as a reminder, if you want to randomize a floating point number (with decimal places), use random.uniform.
r=random.uniform(0,6.2)
Second, the final line, rotating the plane by the value inside R. And presto. Randomly rotated confetti.
bpy.ops.transform.rotate(value=r, axis=(1,1,1))
Enjoy.
The Full Script
Remember, this one only works with Blender Cycles. And if you want white, you have to jack all the values (Red, Green, Blue) up to 1.
import bpy import random def confetti(MatCol,r,g,b): bpy.ops.mesh.primitive_plane_add() bpy.ops.transform.resize(value=(.25,.25,.25)) #Resize to fit the scene bpy.data.objects['Plane'].name = MatCol #Rename the planes as the 1st paramater above mat_name = MatCol mat = bpy.data.materials.new(mat_name) bpy.data.materials[mat_name].use_nodes = True bpy.data.materials[mat_name].node_tree.nodes.new(type='ShaderNodeEmission') inp = bpy.data.materials[mat_name].node_tree.nodes['Material Output'].inputs['Surface'] outp = bpy.data.materials[mat_name].node_tree.nodes['Emission'].outputs['Emission'] bpy.data.materials[mat_name].node_tree.links.new(inp,outp) bpy.data.materials[mat_name].node_tree.nodes['Emission'].inputs[0].default_value = (r,g,b,.5) bpy.data.objects[MatCol].active_material = bpy.data.materials[mat_name] #Run a loop 100 times for index in range(200): bpy.ops.object.select_all(action='DESELECT') #If you don't deslect the other objects, the results are real weird bpy.data.objects[MatCol].select = True x=random.uniform(-10,10) y=random.uniform(-10,10) z=random.uniform(-10,10) r=random.uniform(0,6.2) #Randomize some variables bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False,"mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(x,y,z)}) bpy.ops.transform.rotate(value=r, axis=(1,1,1)) confetti("WhiteMat", 1, 1, 1)