Tuesday, April 26, 2011

Simualtion Render into Unreal Cascade as a SubUV Material

In this post I'm going to be going over how to get a simulation (in this case, a maya fire simulation) into Unreal's Cascade as a SubImage texture.

I'm assuming you have an interest with Unreal and Maya otherwise you wouldn't be reading this, so you should have a basic understanding of Unreal Cascade and material system, Photoshop and Maya's rendering pipeline. What I'm not going over is how the Maya simulation was made step by step. I could have multiple posts just for that, so I'm going straight to the render, assembly, simple additive material, and the simple cascade set up. So that said, here we go.

The Experiment: 
How do you take a simulation from Maya, and use it in Unreal's cascade as a SubUV.

Fire render Maya fluids from Fred Hooper on Vimeo.

Simulation in third party package: First you'll need to make the simulation of whatever you want the effect to do. (in this case a fire test made Maya's fluid dynamics)

Need: Second, determine how long of a simulation you need. A lot of this depends on your budget and what kind of visual fidelity you're going for. Games usually shoot for 30fps (frames per second) or above so if you want to have the simulation run for a second you should have at least 30 good frames (I'll render 36 or 64 depending on my budget). Eventually this will need to be made into a texture, so if you're using a 1024 x 1024 with 36 frames, each frame will be 179.67px x 179.67px and get me a second+ of animation. All of this comes down to your texture budget, and reuse. If I'm loading a 1024 simulation I need to be using it a lot. You'll need to experiment a lot on this, since it comes down to give and take with the look vs the need.

Render: Next render the simulation as frames into a folder. I usually use targa (.tga)s since they don't have visual degradation. Depending on how long of a simulation and how many frames you want you may want to over render the simulation frames to have a larger sample size. So for a 36 frame texture I'll render 72+ frames and use every other frame for more motion between frames.

Assembly: Now you need to assemble the texture. Take the frames and assemble it chronologically in Photoshop. Generally its better to assemble the frames then drop it down to a power of 2 size. If you have a large enough sample size, you can skip every other frame if you think it visually will make sense. The sample that we're using here is every other frame, since it didn't seem to degrade the quality of the animation. If you can make a java script or an action to make assembling the texture faster, then please do. Otherwise you're going to have to do it by hand, which is slow and makes iteration more difficult. We're lucky in this case since this sim doesn't need an alpha component otherwise you'd need to assemble it twice.

Save this as a Targa and make sure the image is set as a power of two. (in this case 1024 x 1024)

After the assembly is complete, we have something that looks like this.

Into Unreal
Now we have the texture we need. We'll need to import it into unreal and make a material for it. Load up Unreal and go to the content browser.

Import: Import the texture and make a .upk called FXPyro, with a group texture and name the texture T_FireSubUV. Remember to save your package after every step.

Add the Material: Next make a new material in the FXPyro.upk, Group Materials called M_FXAddSubUV. We're going to make this an additive material for the T_fireSuvUV

Additive Material: Next we're going to work on the additive material. The Material system in Unreal is really powerful and again this post would be huge if I went into all of the little things it can do. In this case, we're going to need for it to be additive, be usable on particles, be usable as a SubUV, and for my personal satisfaction have an edge blend so the sprite doesn't crash with the environment. In the SubUV Texture node hook the T_FireSubUV to it. Right Click in the FXPyro pkg  and select new material and save it as group 'Materials' Name M_FXAddSubUV. String up the material like this:

You can find most of these Material nodes by RCL in an empty space in the particles folder. Otherwise you'll need to find them on your own

Larger Version

Make sure the Material is set to Blend Additive with an unlit lighting model. If the usage isn't checked the Material won't be usable in Cascade.
This material will allow us to use it in Unreal, and in this case Cascade.

Add a Particle system (Cascade): Now we're at the point where we can make a particle system in Cascade. Create a new Particle system in the package FXPyro with the subgroup FXFire and name it FX_FireSubUVTest.

Cascade ed will come up and make a new particle system by RCL (right click) on the window and select new particle system. Here you will have the basics of the system, but you'll need to add a couple modules to the initial system to make it work.

Have the Particle use the Material: We need to make the particle system use the fire material (and therefore texture) we've been working on. In the FXPyro package single right click to highlight M_FXAddSubUV. Switch over to the open cascade window and go to the required module and highlight the materials field (left arrow) the material name in it. The path of M_FXAddSubUV should be in there and the sprite may vanish. Do not panic... the reason it could have vanished is we're using a vertex color in the material, and cascade doesn't have color values it can use to make a color. If its not there, add a color over life module and make sure its set to Constant 1, 1, 1 and the fire material will appear. As you can see the sprite looks a grid and won't be very usable.

Next change the following nodes so we can see what we're doing.

  • Spawn Node: from default Spawn settings to Rate >Distribution > Constant 1
  • Velocity Node: from Default Start Velocity Settings to Start Velocity/Distribution/Constant x 0, y 0, z 0.

Larger Version

SubUV Time: Now we have the material in Cascade, next we need to divide it into single frames. This takes a couple steps.
  • First add a subImageIndex to the stack. 
  • Inside that node set the SubImageIndex to ConstantCurve and have the first input be 0 (beginning lifetime of the sprite) and 0 (the first frame) the second input have it set to 1 (end lifetime of the sprite) and 35(the last frame).

This set up will smoothly ransition between the frames if the following is set up correctly in required. In Required/subuv set the horizontal to 6 and the veritcal to 6. Now the simulation should spawn with the first frame.

PSUVM_Linear_Blend will allow the animation to play smoothly between frames.

Larger Version 

To make it run through the animation change the Interpolation Method from none to PSUVIM_Linear_Blend and the simulation should start to run through the simulation, but it will snap between the beginning and end, since it hasn't been set up as a looping effect. 

From here its a matter of tweaking the simulation to do what you want it to do in Cascade. This does not loop, to make it blend well you'd need to spawn multiple sprites and blend them in and out accordingly to make sure it doesn't snap... or import the render into aftereffects and make it loop before importing it into Unreal. For purposes of this example I changed the color over life to blend with a constant curve from 0 to 1 at the middle of the simulation and back to 0, with a spawn of 2.

Fire Test Unreal from Fred Hooper on Vimeo.

There are other uses for SubUVs rather than just running animations. If you wanted you could have cascade pick a single frame and use it for simulation. Textures like an array of smaller embers, rocks, leaves, etc can be set up on a smaller scale to get what you want. Like a 4 by 4 square or a 6 by 1. Load one texture and get a number of options, as long as each frame is different.

SubUV pick one frame instead of animate: For example if you'd set up 4 rocks on a 64 x 64 and you wanted each sprite to pic one of the frames you'd set up the SubImageIndex to Uniform Min 0 and max 3, and set up the required to horizontal 2 and vertical 2 with a setting to random. This would randomly pick one 32 pixel frame and display that.

I hope this helped and wasn't too confusing. Thanks and until next time have a good one!