I want to make some lights changing colors randomly each frame. They need to be either red, green, blue, or orange. That for about 1000 objects that need to be changing differently. I think it would be some combination with ColorRamp node and a randomly changing factor each frame between 0 and 1. Is this possible? If yes, how? I am using cycles.
Setup a material similar to the following :
The 'Animate' Value should be keyframed to start at 0 and increase to change the colours - the faster this changes, the faster they will animate. The Color Ramp can be adjusted to change the sequence of colors or you could use a different interpolation if you want gradual changes rather than 'Constant'. The Power node uses the 'Random' value to add some variation to the flashing - so that some of the objects change at a different rate. Set the Power to 0 and they should all change at the same rate - or experiment with other Maths nodes to get the desired spread (eg, an 'Add 1.0' node in place of Power would allow you to set the rate to range from 1.0 to 2.0 so you'd never get really slow changing ones).
Results as shown :
The "natural way" to do it is to use drivers. But it seems that frame driven values in a material node does not update properly or leads to an error.
So I found this previous answer which mainly links to an external tutorial but leads to a solution.
- Get access to a random value
To do that, we use a script (see below) that allows to use a random function in the driver's expression (see comments).
import bpy import random #Import the random module #Define a random function based on the random module def randf( min, max ): return random.uniform( min, max ) #Link the function to the driver namespace so that we can use it as an expression bpy.app.driver_namespace['randf'] = randf
- Define a material with a value node
We'll come back later in the material setting. Here we just want to have a 'value' node so that we can get the previous Python function in the material's nodes.
- Setting the driver
We can add a driver directly in the node's output slot. He will appear in purple and setting driver's expression is possible. But for some reason it won't work properly and/or refresh at each frame.
So, as indicated in the video accessible from there, we can add it from the outliner.
The noticeable difference is adding the driver directly is a material node based driver but this workaround is an object base driver.
To set it, open the outliner. Set it to 'datablocks' view. Navigate to the following:
- Your object (ie "objects then Cube")
- "Material slots" then the wanted material
- "Node tree", "shader node tree" and "nodes"
- "Value" (as our node is a value node), "outputs" and for this node "default value"
Finally, that drives to this:
Select this last "default value", then press D or use the menu "edit/add driver to selected".
- The driver
- Open a view with graph editor (1)
- Set it to 'drivers' (2)
- Select your object's driver (3)
- In the driver tab, set the expression corresponding to our script (4)
In case of error in the expression:
- Be sure to run the script (AltP or "run script" button is the text block
- "update dependencies" in the drivers tab
- Enable scripts in the user preferences, "file" tab, then "auto run Python scripts"
Now for the material
The material setting has a mix from the driver value (frame based) and "object info" node (object based) as inputs.
The aim is to combine these two random values to influence a color ramp (for instance). A modulo is used to avoid average effect (which may lead to values around 0.5).
To make it work, if needed:
- Reload trusted (on top menu bar)
- Run the script (on script/textblock part)
- Update dependencies (driver part) for one cube
Note: you'll see that this is not perfect as some objects have the same color, always... I think this is due to the "object info" node, but I don't know why...
Please comment for any enhancement.