2019年7月22日
How an RWU student elegantly animated thousands of cubes simultaneously in Unreal Engine
The task was purposely left open-ended, to allow us, the students, to tell a story, to create something abstract or to even potentially create 2D animations.
Having worked with Unreal Engine and having been up to date with the engine’s development since nearly the beginning, it became clear that I could use this opportunity to delve into creating a real-time film for the first time.
I've always been fascinated by how simple shapes or geometries with minimal individual functionality in sufficient quantity are able to represent detailed pictures as a whole.
Pixels can't do much more than change color or intensity. In my case, I've got virtual 3D cubes that can't do much more than move up and down. This is where the quantity of cubes can make a visual difference.
I started experimenting with simple, static cubes to create a futuristic-looking pin table and came up with a design that resembled a copper-colored circuit board.
Once I established the style I was looking for, I proceeded prototyping a system that drives the motion of those cubes.
The requirements I had for the system were:
- To drive the motion of thousands of cubes simultaneously
- To allow random/noisy and specific motion
- It had to have minimal performance impact that would run stable in the editor
- Most importantly, the system had to be easy to use and tweak.
While it would have been possible to traditionally animate or use Blueprints to drive the motion for a few dozen cubes, I knew that only a shader solution would be capable of dynamically moving up to 550,000 cubes in certain scenes without a major performance hit.
I started by generating a pin table with 25,600 cubes that I eventually would instance several times depending on the shot, to get the desired resolution. The bottom faces of the cubes were deleted as they could not be seen and would further improve performance.
Assigning different vertex colors to the four upper and lower vertices to mask out the moveable parts allowed me to keep the bottom of the cube in place while allowing only the upper face to move.
In order to use textures to drive the motion, it's important to generate a UV map that has all four top vertices mapped to a single point in the UV space and evenly spread in the 0-1 space.
This is to force all four points to move equally, otherwise, the points could sample different pixels at each point and would therefore not be flat on the top.
Using the Vertex Color output in the Alpha of a Lerp (Linear Interpolation) node in the Material Editor serves as a mask.
Multiplying the output of the Lerp with a Constant3Vector (0,0,1) node eliminates any possible movement in the X,Y direction and only allows up and down movement.
Clamping the result to a minimum of 0 makes sure that there's no movement below the base level. The Clamp output then goes into the World Position Offset and the basic framework is done.
This is where the real fun part starts. The input A of the Lerp is the most creative part of the project. There isn't a strict rule to follow and the biggest part was trying out different approaches such as:
- Scaling a texture in the U and V direction
- Rotating or Panning a texture
- Using the Time and sine node
- Switching to World Aligned Textures that allow continuous movement across different pinboards
Using a World Parameter Collection allowed me to later keyframe within Sequencer to create the actual motion.
To create a dramatic look, there's one dynamic Directional Light Source and a dynamic Skylight that are both at very low intensities (around 0.17lux and 0.1 cd/m², respectively) as the reflective surface already scatters light.
In some scenes, a spot or point light was used to create some smaller highlights when needed.
The Cinematic Camera was then used to tweak and fine-tune the look. Extensive use of depth of field enhanced the look of the size and amount of cubes.
The next steps were to set up the different shots within Sequencer and keyframe the motion. I began by importing the audio and created various placeholder shots.
Next, it was time to get the right camera angles and keyframe the material parameters that are stored in the World Parameter Collection. Unreal Engine 4's Camera Rig Rail and Crane helped a lot to create the steady yet interesting motion of the camera itself.
Altogether it has been an amazing journey for me to create this project inside Unreal Engine 4. Due to the quality real-time rendering and tools provided, it allowed for amazingly fast iteration times.
My professor’s feedback and ideas didn't require me going back and rendering the scene again, which would usually take me several days. Instead, I could immediately change several aspects in real-time that include colors, post-processing effects, or even alternative tracks for the same shot to quickly visualize different variants of the same sequence. This helped to speed up the process a lot.
It was hard to believe that I could produce the entire cinematic sequence using Unreal Engine 4, without the need of other software. Today I know that UE4 is a high-powered, dynamic video creation tool with great documentation and an incredibly helpful community.
Special Thanks
- Professor Markus Lauterbach
- Jorge S Soto
- Gregory Neale
- Division Games UG
- Sound used: "ManVsMachine" with Copyright Zelig Sound