Your online Softimage Educational Resource

The blog has been online for more than 4 years and there’s still not a single post even remotely related to the delicious brew called coffee… Perhaps it will someday, but in the meantime you can read the articles about Softimage. Most of the material are tutorials and Q&As I’ve written for 3D World Magazine sometime between today and 2003. If you have any questions please don’t hesitate sending me an email.


Thanks to Letterbox Animation Studios for hosting all the scene files.

Make sure you visit their Redi-Vivus.com for 100s of hours of free XSI video tutorials.

Sunday, July 31, 2011

ICE destruction

Whether it’s alien lasers, judgment day prophecies or just that really cool thingy that will self-destruct messages in five seconds, having a tool that can turn an object into dust for whatever reason can certainly become handy in the VFX demanding times of today. Anyone who has ever worked on a VFX shot knows that the second you start relaying on key framing the effect by hand the chances of the director all of a sudden changing his mind and want it to go in another direction is one hundred percent. And that is if we're being optimistic. So the goal is to design a tool that is flexible enough to change the object getting disintegrated and the factor setting of the effect without relying on you manually setting keyframes.

Prior to the introduction of ICE this would certainly be a challenging task and probably not something you would set up with your computer in the basement. But times have changed and we're now post the introduction so this is exactly what we're going to do.


While the visual nature of ICE makes it a fantastic
tool for prototyping you should at least get the basic concept on paper before going wild in the ICE Tree. There are four main components in creating the effect. The first is to initialize the disintegration. In the following walkthrough you'll be using a simple particle cloud, but this can easily be swapped with any object by replacing a single node. Once initialized, the effect should gradually spread across the surface throwing debris into the air. Rather than tessellating the object to hold an ridiculous amount of tiny polygons and disintegrate them you will use a separate particle cloud to create the debris. There are several reasons why you want to use separate entity for this but the most important is flexibility. The quantity, size, color, etc of the debris can all be changed on the fly without having to revert to the original geometry. But since you're not breaking up the actual mesh it will still be visible in rendered image, so you'll need to create a matte to mask the exact same part of the surface that's being dissolved.


The project files used in this tutorial can be found at:http://dl.dropbox.com/u/3834689/CaffeineAbuse/ICE_Vaporize.zip

STAGE ONE
Initialize the destruction
In the following walkthrough you'll be using a simple particle system, which for your convenience has already been created, to set off the disintegration of the object. This can however be replaced with any other object simply by replacing the Get Initialize_Dissolve node in the ICE Tree with your objects of choice. To set off the disintegration you'll calculate the distance between each of the particles and the surface of the object. If the distance is within the specified threshold, it's a "hit" and the object will start to disintegrate at the exact location of the respective particle. To store the data you'll use a custom attribute, which is declared in a none simulated ICE Tree and evaluated using a simulated ICE Tree. The first frame of your scene is considered to be the initial state and is used to initialize the simulation. As a result no data will be written at this frame. As you'll read data from the simulation, this may cause instability. This is fixed by forcing the simulation to start one frame prior to the scene.

01 Create the ICE Tree
Open the Road_Sign.scn scene. Select the Road_Sign object , press [Alt] + [9] to open an ICE Tree view. From the Create menu choose ICE Tree. Get a Set Data node, open the PPG and enter Self.Dissolve as the Reference. This will create a custom attribute named Dissolve. Rather than using the actual name, the "self" token refers to the object to which the ICE Tree is applied to. Get a Scalar node, set the Value to 0 and connect its Result output the Self.Dissolve input of the Set Data node. Connect the Set Data node to the Port1 of the ICE Tree.

02 Get the point position
From the Create menu choose Simulated ICE Tree. Press [8] to open an Explorer and set the scope to Environments. Click on the Simulation Time Control icon to open the PPG. Uncheck the Use start frame checkbox in the Scene Time section and in the Time Reference section, set the Offset to 0. Change the scope in the Explorer to Scene and drag and drop the Initialize_Dissolve into the ICE Tree. Get a Get Closest Location node and connect the Value output of the Initialize_Dissolve node to the Geometry input of the Get Closest Location node. Get a Get Data node, open its PPG and enter Self.PointPosition in the reference textbox.

03 Calculate the closest points
Connect the Value output of the node to the Position input of the Get Closest Location. Open the Get Closest Location PPG and check the Enable Cutoff Distance checkbox and set the value to 1. This will limit the evaluation of the node to points that are within 1 units from particles. The Get Closest Location node can be used to retrieve a variety of information, but the one you're currently interested in is the points on Road_Sign's surface that are closest to particles.

04 Output the closest points
Get another Get Data node and connect the Location output of the Get Closest Location node to the Source input. Open the Get Data PPG and enter PointPosition as the reference. Note that you're not using the "self" token here. The data you want to get is not the point position of every point of you mesh , but the position of the points retrieved by the Get Closest Location node.

05 Calculate the distance
By subtracting the position of each of these points with the position of the points on the mesh you'll effectively calculate the distance between them. Get a Subtract node and connect the value output of the PointPosition to the First input and the Self.PointPosition to the Second input. The distance it currently exposed as vector values and you want the length of each of these vectors. If the length is less than a specified value that part of the surface has been hit and will start to dissolve.

06 Create a custom attribute
Get a Length node and a Less Than node. Connect the Result of the Subtract node to the Vector input of the Length node and the Result of the Length node to The First input of the Less Than node. Open the PPG of the Less Than node and enter 1 as the Second value. Get a Set Data node, open the PPG and enter Self.Dissolve as the reference. This will create a custom attribute named Dissolve and store whichever information feed into it.

07 Setting the value
Get a Scalar node, set its Value to 0.5 and connect the Result output to the Self.Dissolve input of the Set Data node. Before finalizing the branch it's important to understand how the graph is evaluated. While you could use the length directly to set the Dissolve value it wouldn't give the expected result. The ICE Tree is evaluated from left to right and from top to bottom. This means that the distance between the particles and the surface will be calculated at every frame , and since the their distance changes at every frame, so would the Dissolve value.

08 If statement
The only thing you're interested in is if the distance between the points and particles are within one unit (the value specified in the Less Than node) or not. If it is you want to set the Dissolve value and initialize the disintegration. If it's not, you're really not interested and you don't want to do anything. Get a If node. Connect the Result output of the Less Than node to the Condition input and connect the Execute output of the Set Data node to the If True input. Connect the Result output of the If node to the Port1 input of the ICE Tree.


STAGE TWO

Growing the Dissolve value over time
The Dissolve attribute just created is essentially what controls the entire effect. A value of 0 and the surface is intact, whereas a value of 1 means the surface is completely disintegrated. To gradually increasing the value from 0 to 1 you need to get the current value and add to it. However, you can't start adding the same value to all of the points as this would disintegrate the entire surface simultaneously. So you first need to determined if the disintegration has been initialize and if so, on what location on the surface. Once you have that information you can get the neighboring points of that location and making the Dissolve value spread from there.

09 Get the neighbors
Get a Get Neighbors node and a Get Data node. The Get Neighbors node will return an array, which is essentially a collection of objects or values, of the position of the connected points. In this scenario it will return a list of the position of each of the points on the geometry and their respective Dissolve value. Connect the Points output of the Get Neighbors to the Source Input of the Get Data node.

10 Calculating the array average
Open the Get Data PPG and enter Dissolve as the reference. Since you know all the points position and their individual Dissolve value you can also get the surface average Dissolve value. Get an Get Array Average node and connect the Value output of the Get Dissolve node to its Array input. By calculating the average Dissolve value of the neighbor and adding it to the current value you'll get a new Dissolve value.

11 Blending the values
Get a Get Data node and enter Self.Dissolve as the Reference. Then get a Blend node. The Blend node will output the sum of the values you feed in to it. As described earlier the ICE Tree is evaluated at each frame. By blending the current Dissolve value of each of the points with the average of their neighbors, their individual Dissolve value will increase for each frame of the animation. This will result in the Dissolve value spreading across the surface over time.

12 Increase over time
Connect the Value output of the Self.Dissolve to the Value1 input of the Blend node and the Result output of the Get Array Average node to the Blend node's Value2 input. Since you're adding the burn value of the current frame on top of the value of the previous frame, theoretically the value will eventually increase it to infinitive. While this surely could be an interesting way of passing time it's not very useful in this situation.

13 Clamping the values
You only need to know if a point is completely dissolved, not at all or somewhere in between the two. Get a Clamp node and connect the Result output of the Blend node to the Value input of the Clamp node. Open the Clamp node's PPG and set the Limit 2 to 1. Get a Set Data node and enter Self.Dissolve as the Reference. Connect the Result of the Clamp node to the Self.Dissolve input of the Set Data node and the Execute output of the Set Data node to the New(Port1)... input of the ICE Tree.


STAGE THREE

Creating the debris cloud
The sole purpose of the cloud is make it appear as if it's the actual surface that is disintegrating and getting the initial state is the key to success. One of the problem you're facing is how to emit the particles. If you open the Emit from Surface PPG you'll see that the Particle Emission Rate Type is set to Number of Particles Per Second. While this is precisely what you want, there is a slight problem with it - it will emit particles from the entire surface for the entire duration of the animation. But what you want is to emit particles only from the specific area and at the exact time it's being dissolved. Once that part of the surface is dissolved the emission must stop.

14 Apply a texture map
Make sure you have the Road_Sign object selected, and from the Get > Property > Texture Map menu choose Texture Map. The texture map enables you to control parameters in the scene, such as the particles color, using an image file. In the clip section of the PPG, click the New button and choose the RoadSign_TextureMap image on the disk. You also need to specify a projection to use, so in the UV Property section, select the UV_Texture_Projection.

15 Create the debris cloud
From the Get > Primitive > Point Cloud menu choose Empty and name it Debris. With the pointcloud selected, click the Refresh button in the ICE Tree View to update it and from the Create menu choose Simulated ICE Tree. Get a Emit from Surface node and connect its Emit output to the Port1 of the ICE Tree node. Press [8] to open an Explorer and drag and drop the Road_Sign object into the ICE Tree. Connect the Value output of the Road_Sign node to the Emitter1 input of the Emit from Surface node.

16 Emit particles
Open the Emit from Surface PPG Change the Shape to Disk. These will essentially act as points but allows you to set a size. Set the Rate to 50 000 or so and the Size to 0.05. For the final render you'll need to increase the Emission Rate to a couple of millions and decrees the Size even further. Note that the rate is the number of particles emitted per second and not the actual count of particles. For the purpose of interaction it's recommended that you keep it rather low while you're trying out the different settings.

17 Propagate the Dissolve value
Get a Get Data node and enter Self.EmitLocation as the reference. As the name might imply, the node enables you to retrieve data from the exact location where each particle is emitted. Get another Get Data node and enter Dissolve as the Reference. The Get Data node remains red cause the attribute Dissolve is associated to the Road_Sign and doesn't mean anything to the particle cloud just yet. Connect the value output of the Self.EmitLocation node to the source input of the Get Dissolve node.

18 Filter the emission
With the Dissolve value being propagated to the particles, you can use the value to filter the emission. If the Dissolve value is 0, the location is still intact and therefore shouldn't emit any particles. The same goes if the Dissolve value is 1, but for the reason that the location is completely dissolved so there's no surface left to disintegrate. Get a In Range node and connect the Value output of the Get Dissolve node to its Value input.

19 Setting the in range
Open the In Range PPG and set the Min to 0.1 and the Max to 0.9 to maximize the emission span. Get a Not node and a Delete Point node. Connect the Result output of the In Range node to the Value input of the Not node and Result output of the Not node to the Deleted input of the Delete Point node. Any particles that are not within the range specified in the In Range node will get deleted.

20 Delete unwanted points
Connect the Delete output of the Delete Point node to the Execute on Emit1 input of the Emit from Surface node. As the branch is executed at the time of emission, it will only affect the particles being emitted at that exact point in time. Any particle being emitted prior or after that will not be affected. This will drastically reduced the number of actual particles even if the Emission Rate is high, which is why you need to really crank it up for the final render.

21 Getting the point normals
If you were just emitting points the rotation of the particles wouldn't matter since they're, well, just points. But if you're emitting any other shape or object, it's vital that they are correctly align with the surface they're emitted from. Get a Get Data node, enter PointNormal as the Reference and connect the Value output of the Self.EmitLocation to the Source input of the Get PointNormal node. If you know the point normal you can convert it to a rotation value which can then be used to set the particles orientation.

22 Set Particle Orientation
Get a Direction to Rotation node and a Set Particle Orientation node. Connect the Value output of the Get PointNormal node to the Point At input of the Direction to Rotation node and then the Rotation output of the Direction to Rotation node to the Orientation input of the Set Particle Orientation node. And finally, the Execute output of Set Particle Orientation node to the New(Execute on Emit1)... input of the Emit from Surface node.

23 Set the particle color
The final piece of information you want to retrieve from the EmitLocation is the color value. Get a Get Texture Map Color node and a Set Particle Color node. Connect the Value output of the Get Self.EmitLocation to the InputLocation of the Get Texture Map Color node. Then connect its Color output to the Color input of the Set Particle Color node. Connect the Execute output of the Set Particle Color node to the New(Execute on emit1) input of the Emit from Surface node.

24 Set particle age limit
As the Road_Sign dissolves into tiny debris you'll eventually want them to disappear into thin air. This is done by giving each particle a unique age limit and then altering their size as a percentage of their lifespan. Get a Set Particle Age Limit and connect the Execute output to the New(Execute on emit1) of the Emit from Surface node. Get a Turbulize Value by Range node and connect the Value output to the Age Limit input of the Set Particle Age Limit node. Open the Turbulize node and set the Min Value to 3, the Max to 5 and increase the Turbulence Scale to 0.5.

25 Change the size by age
Get a Get Data node and a Set Data node. Enter Self.Size as the reference for both of them. Get a Modulate Value by Age Percentage node and connect the Value output of the Get Self.Size to its Base Value input. The default shape of the f-curve will keep the particles at their initial size when they're born and gradually scale them to zero as they reach the end of their life. Connect the Value output of the Modulate node to the Self.Size of the Set Data node and the Execute output of the Set Data node to the New(Port1)... input of the ICE Tree node.

26 Adding forces
Get an Add Forces node and connect its Execute output to the New (Port2)... input of the ICETree node. Get a Turbulize Value by Range node and connect it to the Force1 input of the Add Forces node. Open the PPG and change the Min Value for all three axis's to -3, the Max Value to 3 and increase the Turbulence Scale to 5. Check the Animated checkbox and set the Animation Speed to 0.5 and the Complexity to 10. The turbulence will scatter the particles randomly in all direction but you also want to push them away from the Road_Sign.

27 Simulate the particles
Get a Wind force and Connect it to the New (Force1)... input of the Add Forces node. Open the Wind Force PPG and set the Wind Direction to 0 on the X axis and to 1 on the Y. For the forces to work you need the ICE Tree to be simulated, so get a Simulate Particles node and connect it to New (Port3)... of the ICETree. As the particles reach the end of their life they won't be visible anymore , so you might as well delete them. Get a Delete Particle at Age Limit node and connect the Execute output to New (Port4)... of the ICETree.

STAGE FOUR

Preparing the scene for rendering

Whether to render the individual elements in different pass to composite and revel them with mattes in post production comes down to the complexity of the scene and what want do with it. In most everyday situation (if there is such a thing in VFX shot) you can save yourself the extra steps by incorporating the matte inside the material. The dissolve value created in the ICE Tree can easily be passed on to the Render Tree as well. By using an additional gradient you can then fine-tune the falloff to sharpen the edges of the transparency.

28 Shading the particles
With the Debris cloud selected, from the Get > Material menu choose Blinn and Press [7] to open the Render Tree. The particles have already been assign their individual colors in the ICE Tree, so you just need to retrieve that information and plug it into the shader. Get a Color Attribute node, open the PPG and set the Attribute to color and connect it to the Ambient and Diffuse input of the Blinn.

29 Add a weight map
Select the Road_Sign and from the Get > Property menu choose Weight Map. Open the ICE Tree for the Road_Sign. Get a Get Data node and enter Self.Dissolve as the reference. Get a Set Data node. Open the PPG and enter self as the reference before clicking the Explore button. In the tree, expand the Polygon Mesh > Clusters > WeightMapCls > Weight_Map and select the Weights node. Connect the Get Self.Dissolve value to the Weights input of the Set Data and the Set Data to New (Port2)... of the ICETree.

30 Create a matte
With the Road_Sign still selected, press [7] to open the Render Tree and get a Scalar Map Lookup node. Open the PPG and select the Weight_Map(WeightMap) as the Map. Rather than animating the transparency of the surface (which would require raytracing) you can make use of the Sprite shader. Get a Sprite shader and connect it to the Surface and Shadow input of the Material node. Open the PPG and change the Stencil Mode to Intensity and check the Enable Matte checkbox. Then connect the Blinn to the Input of the Sprite node. From the Mixers category (important), get a Gradient node and connect the Scalar Map Lookup to the input of the Gradient node and the gradient to the matte input of the Sprite node. Open the Gradient PPG and click the White/Black preset button. This will get the values from the weight map and use these as a matte for the Road_Sign surface.

2 comments:

NOva said...

How would you achieve this effect, with the sun shining through the flower etc. link: http://death-pony7.deviantart.com/art/Turk-Cap-255752382

Jason said...

Wow this is all really thourough useful and informative !

Thank you and congats!