I am Paul Scharf and Roche Fusion is my first commercial project.

Written in C#, the game renders through OpenGL using OpenTK.

Being responsible for the game's custom graphics engine and all its graphical code, I created this page as a technical summary of a number of systems and effects I created for Roche Fusion.

While the game's art assets consist entirely of 2D sprites, note that most of the effects described below are simulated in 3D or in screen space in case of the post processing effects.

Together these effects, and the game's assets make for the iconic style of Roche Fusion.

Post Processing

Black hole distortion effect

Black hole distortion effect (full image)

Screen Space Distortions

Part of Roche Fusion's rendering pipeline is the possibility to distort the original forward-rendered image at will.

Any effect that wants to apply a distortion renders to a screen-sized render target storing UV coordinates.

After all distorting effects are combined, the original image is sampled in a final pass using the distorted UV coordinates in said render target. This allows for virtually any kind of distortion.

In the game it is mostly used for shock waves, and a couple of special weapons, most strikingly the black hole.

Localised Crepuscular Rays

Next to shock waves, another detail that makes Roche Fusion's explosions feel spectacular are crepuscular or volumetric rays.

The effect is implemented very similarly to what many modern titles use as a full screen effect, with the difference that it is rendered once per explosion, using one quad with minimal size each, naturally limiting the number of fragments for which the expensive screen-space ray-marching algorithm has to be performed.

Comparison of explosion without and with crepuscular rays

Comparison of explosion without and with crepuscular rays

Screen edges pixelate on low health

Screen edges pixelate on low health (full image)

Pixelation Overlay

Roche Fusion is a fast game, and especially in later levels the player is often not able to consistently keep checking their HUD for the status of their weapons and shields.

To warn them when they get close to death after taking too much damage, as well as to increase immersion and heighten the sense of danger, the edges of the screen are continuously more pixelated and desaturated as the player approaches zero health.

This is done in the final full-screen composition pass, and it controlled by only two parameters, one for each side of the screen, to allow for separation of feedback in two player local coop.

The shader applies a strong and noticeable effect to the edges of the screen, but leaves the center of the screen, as well as the HUD mostly intact.

Effects (GPU side)

GPU accelerated particles

A major part of Roche Fusion's art style is the number of particles used for most effects, especially explosions.

Most of the particles of death explosions of both enemies and players are generated by splitting the sprites of which the ships are composited by a fine grid, each cell becoming a particle.

This creates a seamless transition between the intact and the destroyed visuals and guarantees appropriate distribution and texture of the resulting explosion.

Several enemies exploding

Several enemies exploding (full image)

A player exploding in a group of enemies

A player exploding in a group of enemies (full image)

The problem

The effect was first simulated entirely on the CPU. While not optimal, we could still easily simulate thousands of particles each frame, despite using an unoptimised system, streaming tens of thousands of vertices to the GPU every frame and heavily taxing the garbage collector.

During late-game, when the number of particles on the screen can reach tens of thousands at the same time, the game's performance became significantly CPU bound however, which is why we decided to move simulation of our most common particles to the GPU.

Implementation

This is done by creating one vertex buffer object for each explosion, and filling it with one large vertex for each created particle.

These vertex buffers are batched by uniforms (most noteworthy textures) and drawn each frame, until they are discarded when all particles have died.

The vertex shader moves and rotates the particles corresponding to their velocity and the elapsed time and passes them to the geometry shader, which expands them into a full quad. Particles that have already died are discarded at this stage by not outputting anything.

These quads are then rendered using the same fragment shader also used for drawing the ships themselves.

Results

The performance gain from this was immense and we are currently able to easily simulate many tens of thousands of particles at the same time without any drop in frame rate.

Performance comparison of a player death explosion before and after moving particles from CPU to GPU.

In fact, the biggest remaining bottleneck is fill-rate related, due to our many post-processing effects.

For a detailed analysis of our CPU particle performance, and the transition to GPU acceleration, including the relevant shader code, you can read this post I wrote on the topic: From thousands to millions of particles.

Volumetrically projected sprite and text

Volumetrically projected sprite and text

Volumetric Projections

One of the more mathematically involved graphical effects in Roche Fusion are volumetric sprite projections.

The effect can in be applied to any sprite and causes it to appear to be projected from a given point.

For each projected sprite, a geometry shader creates a pyramid of polygons surrounding the projected volume. The fragment shader then casts a ray through the volume and takes a number of samples to get an approximation for the fragment's brightness.

The effect works best for larger sprites with coarse details, but can also be applied to for example rendered text.

Effects (CPU side)

Skeleton of a mini boss

Keyframe animated skeleton of a mini boss,
also showing collision circles (yellow)

Keyframe Animations

Upgrade cycle animation of a ship

Despite both its gameplay and all of Roche Fusion's graphical assets being two dimensional, almost none of the sprites are simply rendered on the same plane.

All enemies and player ships consist of multiple sprites that are positioned and oriented in difference planes to give a subtle impression of volume.

To facilitate this, I implemented a flexible and fast keyframe animation system, using generics to allow the user to animate any kind of value they can imagine.

Besides defining the relative position of the ships' sprites, the system is also used for actual animations for a variety of effects.

Most notably these are bosses, and the player's ships themselves, which animated through several stages when progressing further into the game.

Our implementation of the generic system also supports the drawing and collision of ships, by storing collision radii and sprite ids in the animation systems' bones, and even weapons can be assigned a bone they are attached to, which is heavily used for large enemies like bosses.

The animations are stored in JSON files and can be easily read and edited by hand to make adjustments.

I also made the entire code of this system available under the MIT license as part of my graphics library here: amulware.Graphics.Animation on GitHub.

That library is also used as the backbone for all other effects explained on this page.

Various Effects

Next to the major systems above, Roche Fusion has many dozens of smaller effects, most using a variety of particles.

Below are a few short videos, featuring some of them.

Upgraded primary weapon of a ship (full size)

A player activating their ship's ultimate, causing a chain reaction to destroy all enemies (full size)

A player ship's death explosion (full size)

Directional shielding effect (full size)

If you are interested in more details on any of these effects, or anything else related to Roche Fusion or my other work, feel free to send me a mail at amul@amulware.net.