Caffeine Abuse - The Blog

Build your own Shockwave deformer using ICE

The wave function
The shockwave will be constructed by two sets of waves – a somewhat smaller, condensed part followed by the larger more intense pulse. Even though a shockwave is an ideal candidate for simulation, it has a slight drawback – namely that it is simulated. Whenever you want to change a value or reposition the shockwave, you have to rewind and run the simulation again. An alternative approach is to do a bit of high school math. Don’t worry; it’s not as frightening as it sounds. The waveform is essentially nothing more than a sine wave; altered over time and its distance from the origin (technically, the equation actually uses the outer edge as the base for the calculation rather than the centre)  

ShockwaveDeformer_image01

The math
The animated sine wave consist of 3 building blocks. The first set of nodes uses the time attribute to change the values for each point over time and the distance from the deformation centre. The next set of nodes handles the frequency and the last set controls the amplitude or strength of the wave.
 
Open the Shockwave_start.scn scene from this issues CD. Select the Deform_Me geometry and press Alt + [9] to open an ICE Tree and from the Create menu choose ICE Tree. To make the following steps a bit easier to follow you’ll define all the parameters at the top of the tree and then simply getting those values as you need them as the Tree evolves. Get a Set Data node and connect it to Port1 of the ICETree. Get a Scalar node and connect it and then disconnect it to the New (Value) input of Set Data node 10 times to create 10 separate attributes. Open the Set Data PPG and enter the following attributes as the Reference. Use the number inside the parentheses as a starting point.  
self.Amplitude  (1)
self.SmallWaveRadius (11)
self.SmallWaveAmp (1)
self.SmallWaveLenght (4)
self.LargeWaveRadius (12)
self.LargeWaveAmp (2)
self.LargeWaveLenght (8)
self.Speed (0)
self.Distance (0)
self.Duration (40)
ShockwaveDeformer_image02
To set the speed of the wave you can get the current time in your scene and multiply it to increase or decrease the speed. So get a Current Time (which will return the time in seconds rather than frames) and a Multiply by Scalar node. Connect the Current Time to the Value input, set the factor to 10 and connect the Result output to the self.Speed input of the Set Data node. 

Rather than using the object’s actual centre point, you’ll use a separate null object and calculate the distance between each point of the geometry and the null. This enables you to reposition the null wherever you want the shockwave to start and the ICE tree will automatically take care of the rest. Get a Get Data node and enter Self.PointPosition as the Reference. Get another Get Data node and enter Impact_Center.kine.global.pos as the Reference. Get a Get Distance Between node and connect the self.PointPosition to its First input and the Impact_Center to the Second. Connect the Result output to the self.Distance input of the Set Data node.
While the Sin node will indeed give you a sine wave, it will be a static wave. In order to create an animated wave you need to change the value you feed into it over time, which is why you created the Speed attribute. Get a Get Data node and enter self.Speed as the Reference. Get another Get Data node and enter self.Distance as the Reference. Get a Subtract node and subtract the self.Distance from the self.Speed. The result of the subtraction will assign an incrementing value to each point over time and based on its distance from the centre. The value will however continue to increase to infinity, which will result in a continuous sine wave. An easy way to fix this is by clamping the output to 0. Get a Clamp node and connect the Result of the Subtraction to the Value input. Open the Clamp PPG and set the Limit 1 to 0 and the Limit 2 to a really high negative number, such as -1000000. 
The next step is to add control for the frequency (the number of waves). Get a Get Data node and enter self.SmallWaveLenght as the Reference. Get a Divide by Scalar node and connect the WaveLenght to the Value input. Open the PPG and set the Divide By to 360 and convert the output to Softimage units instead of degrees. Get another Divide by Scalar and connect the Clamp node to the Value input and Divide by Scalar to its Divided By input. Get a Sin node and connect the result of the division to its Value input. 

In addition to the frequency you also want to control the amplitude of the wave. Or the amplitude based on the waves distance to the center to be more precise. Get 3 Get Data nodes and enter self.Distance, self.Speed and self.SmallWaveRadius as their references. Get a Subtract node and subtract the self.Speed from the self.Distance. Get a Divide by Scalar and divide the result of the subtraction by the value output of the self.SmallWaveRadius. Get a Calmp node, set the Limit 1 to 0, Limit 2 to 1 and connect the result of the division to the Value input. The output of the Clamp node will output a decreasing value rather than increasing. To fix this, get a Subtract node, open the PPG and enter 1 as the First value. Connect the result of the Clamp node to the Second input. Since you’re gradually subtracting less from 1 for every frame, the output from the subtraction will obviously get closer to 1 over time. Get a Get Data node and enter self.SmallWaveAmp as the Reference. Get a Multiply by Scalar node and connect the WaveAmp to the Value input and the result from the Subtract node to the Factor. To bring the first wave together you just need to multiply the sine wave with the amplitude, so get another Multiply by Scalar node. Connect the Result of Sin node to the Value input and Result from the previous Multiply by Scalar node to its Factor input. 
 
The second wave
The math behind the large wave is identical to the first. The only thing you need to change is negating the sine wave and reversing the subtraction of self.Distance and self.Speed. Once this is done you can combine the 2 waves with a simple add node.
 
ShockwaveDeformer_image03

With a few exceptions, the large wave uses the same math as the small wave. Select all the nodes constructing the small wave and press Ctrl + [C] and Ctrl [V] to copy and paste them. Replace all the ‘small’ with ‘large’ in the Get Data nodes (for example, self.SmallWaveLenght to self.LargeWaveLenght). Get a Negate node and intersect the connection from the Sin to the Multiply by Scalar node. You also need to reverse the subtraction of the self.Speed and the self.Distance, both for the frequency and for the amplitude. For the frequency the self.Speed should be subtracted from (Second input) the self.Distance (First input) and in for the amplitude the self.Distance should be subtracted from the self.Speed.

To add the two sets of waves together, get an Add node and connect the Result from the Multiply by Scalar from the small wave to Value1 and the Result from the large wave to Value2. Get 2 Get Data nodes and enter self.Speed and self.Duration as their References. Get a Divide by Scalar and connect the self.Speed to the Value input and the self.Duration to the Divide By. Get an FCurve and connect the Result of the Division to its input. Open the FCurve PPG and add a keyframe with a value of 1 approximately at frame 0.2. Change the value of the keyframe at frame 1 to 0. This will scale the effect of the wave from 0 to 1 and back to 0 over its lifespan (which is defined by the duration attribute). Get a Multiply by Scalar and connect the Result of the Add node to the Value and the FCurve the Factor. 

The last step is to add a multiplication to scale the overall amplitude of the wave. Get a Get Data node and enter self.Amplitude as the Reference. Get a Multiply by Scalar and connect the Result from the previous multiplication to the Value and the self.Amplitude to the Factor.

The final step is to actually deform the geometry. Get a Get Data node and enter self.PointPosition as the Reference. This will return the X, Y and Z position for each of the points of the geometry. However, you’re only interested in changing the Y position (since the disc lies flat on the ground) so you need to separate the vectors. Get a 3D Vector to Scalar node and connect the self.PointPosition to its input. Get a Scalar to 3D Vector node and connect the X and Z output of the 3D Vector to Scalar to its corresponding inputs. Connect the Result output from the Multiply by Scalar node to the Y input of the Scalar to 3D Vector. Get a Set Data node and enter self.PointPosition as the Reference and connect the Scalar to 3D Vector to its input. Complete the ICE Tree by connect the Set Data node to the New (Port1)… input of the ICE Tree node.  

ShockwaveDeformer_Complete_ICETree
The complete ICE Tree