Working with Iterations
In the course of this tutorial we have learned how an XPresso Expression basically works. However, the methods we have used up to now have their limits with regard to working with hierarchies. In the following example we will calculate the position of all Child objects of a given Null Object per frame using a formula. If the number of Child objects is not too high such an Expression can be created using few Object Nodes in conjunction with the corresponding Formula Nodes. However, the greater the total number of Child objects the more difficult it will be to maintain a good overview. This is where the Iterator Node comes in. This Node lets us select an element based on a list or number that are generated each time the Expression is executed (Knowing how to work with iterations is also important if you work with the Thinking Particles module).
In our example scene a Hierarchy Iterator can, depending on its settings, be used to output all of an object’s Child objects so that we can modify these objects’ parameters on a per-frame basis. This not only saves us a lot of time when designing the Expression but also from having a bunch of overlapping XPresso Nodes. Note, however, that not all objects can be output at once but will be output consecutively by the Hierarchy Node.
Sound and Iterator
In this example we will create a light show that will be controlled using an audio file. The Iterator will be used so we can see how it works. Before we begin setting up the Expression open the sample file that contains the lights we want to have blink to the beat of music. All necessary Objects and Tags are already included in the scene so all we have to do is set up the XPresso Expression:
After you have opened the file have a good look at it so you know what you’ll be working with. The lighting console (clavilux) is made up of several objects and many other objects are used for the environment. Our job will be to control the intensity of the lights themselves. Open the XPresso tag attached to the clavilux and add a Sound Node in the XPresso Editor window that opens (New Node/XPresso/General).
The Sound Node
In the Sound Node’s Attribute Manager settings, click on the button to the right of the Filename field and select the audio file "maxon_technoloop2.wav" from the "tex/tutorials" folder located in your Cinema 4D installation directory. Information regarding the file formats supported by the Sound Node can be found under Sound Formats.
The Sound Node supports wav and aiff file formats in the following sampling rates: 11kHz, 22kHz, 44kHz, 8-bit, 16-bit. In addition to the audio file we can also define the number of Bands.
In our example we will assign each light in the clavilux a specific frequency. Depending on the value assigned to the amplitude the corresponding light will emit a bright or weak light. Each time the Expression is executed all frequency bands will be iterated and pass values per beat to each light accordingly.
Our clavilux is made up of four colored lights ("LightRed", "LightGreen", "LightBlue", "LightYellow") as well as a bright flash light ("LightFlash"). We will link the flash light to the overall amplitude of the audio file and the colored lights with the individual frequencies of the audio file. After we have loaded an audio file into our Sound Node we will set the number of frequencies to 8 and click on the Node’s blue corner so we can add a frequency Band input Port. Even though we only have four colored lights we will set the number of frequency bands to 8 because we will read out only every other frequency in order to increase the variation with which the lights blink.
We now need a temporal influence on our effect because we want to iterate to every 2nd frequency at any given time. Add a Time Node with which the current scene time will be conducted. This will prevent the audio from being distorted and it will always have the correct timing even if we modify the temporal proportions of our scene. Add a Time output Port to the Sound Node and connect it with the Time Node’s ouput Port.
If you now test the animation using the Timeslider or by pressing F8 you won’t hear any sound. An additional step is required so the sound will be made audible and so the sound will also be recorded with the animation:
Open a Timeline window (Window/Timeline (Dope Sheet)) anddrag an object (e.g., Clavilux) into the object area. Right-click on the object and open the object’s context menu and select Add Special Tracks / Sound. You can now add the sound file in the Attribute Manager.
Next, create an Iterator Node so we can finally get to the core of what this tutorial is about (New Node/XPresso/Iterator). This Node has two input Ports and on output Port. The Iterator Node input Ports represent the start and end values, respectively, of the iteration. If, for example, we set the Iteration Start Port’s value to 10 and the Iteration End Port’s value to 15 the numbers 10, 11, 12, 13 and 14 will be output. Note that the Iteration End value should always be the larger of the two values. Even though Cinema 4D will automatically run a check on this it is advisable to also check this manually in order to avoid any unwanted results.
We will use two Constant Nodes to pass on the values 0 and 4, respectively, to the corresponding Iterator Nodes. We have already established that we require the numerical sequence 0, 1, 2, 3 but have assigned an upper limit for the iterator of 4. This is a convention stemming from programming languages and will not be delved into here. Since we want to iterate every second frequency band we will use a Math Node in conjunction with at Constant Node to multiply the iteration value by 2. This will supply us with the values 0, 2, 4, 6, which we will pass on to the Sound Node’s input Port.
The Sound Node will receive the Cinema 4D document’s actual time and the Iterator will pass on its values at every second frequency band to the Sound Node’s output Port. What’s still missing are the values that our Sound Node ascertains over time when the respective frequencies are played. For this we will add the Left Mag and Right Mag output Ports to the Sound Node. In order to establish a median value we will add both of these values and divide the result by 2, which we will do using a Formula Node (New Node/XPresso/Calculate).
A Formula Node can often be of use when several calculations are used for a given operation. This keeps you from having to create several Math Nodes that can only be used for a single operation each. So add a Formula Node and create two input Ports. These will later store the respective Band amplitude values. Enable the Use Port Names in the Formula Node’s Attribute Manager settings. This lets us use the Port’s name in the formula itself. Therefore, name the Ports "Left" and "Right", respectively. Now add the following formula to the Formula Node’s Formula field in the Attribute Manager: (Left+Right)/2.
Our Expresson now contains all elements and operations required for the audio file. Now we just have to transfer the values to the Light object’s Intensity. To do so, we will first create a link list (New Node/XPresso/General/Link List) and select it so we can drag all four Light objects from the Object Manager into the Link List field in the Attribute Manager.
The objects cannot be selected individually because the Light objects’ attributes will be shown in the Attribute Manager’s Link List instead of the Link List’s attributes). Multiple objects can be dragged into the Link List field in one of three ways:
The Link list is very useful when we want to output an object using an index value. The object whose index lies at the input Port will be output. Since we have four objects in out list and our Iterator outputs the values 0, 1, 2, 3 we can activate and output each object in the list. Connect the Iterator Node’s output Port that is already connected to the Math Node’s input Port to the Link Node’s input Port.
In order to pass the parameters to the corresponding object, drag one of the Light objects into the XPresso Editor window. As you already know, this will create an Object Node for that light that contains the default Ports for a Light object. Add to this Object Node the input Ports Object and Intensity. Even though this Object Port overwrites the reference Port in the Attribute Manager the name of the Node remains unchanged.
Connect the Link Node’s output Port with the Object Node’s input Port. One more step and our Expression will be functional. The Formula Node’s output Port puts out values ranging from 0.0 to 1.0. However, because the Light object’s Intensity values range from 0 to 100 percent we have to scale this range up accordingly. To do so, create a Range Mapper Node with an input range of 0.0 - 1.0 and an output range of 0.0 - 100.0. The input value will be passed on from the Formula Node’s output Port. Now connect the Range Mapper Node’s output Port with the Object Node’s Intensity Port.
After we have set up the lights we have to control the flashing of the lights. Up to now we have measured the amplitude of each frequency and passed this on to our Light object. Now we will add the output Ports Left and Right the Sound Node so we can do this with the maximum volume of all frequencies. As was already done with the frequencies we will add the value of the left and right audio channels and divide the result by a value of 2 to ascertain a median value. A Range Mapper Node will make sure the result is scaled accordingly to the value range of the light’s intensity. In order to pass on the intensity to our flashing light object, drag the "LightFlash" object from the Object Manager into the XPresso Editor window. Add an Intensity input Port to the newly created Node. Finally, connect the Range Mapper Node’s output Port with the new LightFlash Node’s input Port.
Now render the scene and you should see the following result:
Let’s briefly recap how we reached this result. The Sound Node is influenced temporally by the scene itself and an Iterator Node passes the number sequence 0, 2, 4. 6 sequentially to the Sound Node, which in turn iterates the frequency bands. For each iteration pass the amplitude value of each activated frequency is passed on to the Sound Node’s output Port. The values of both audio channels are added to ascertain a median value. These values are then converted via a Range Mapper to a maximum value of 100.0. This value is then passed on to the Object Node’s Intensity Port. The object’s Reference overwrites itself as a result of object index information being passed on from a Link list via an Iterator Node.
Finally, we will tranform the values to maximum 100 using the Range Mapper. For the flash light we will add the current sample amplitude of both audio channels and create a median value; this will also be scaled to maximum 100 using a Range Mapper