- Create a 2D Unity Project
- Create Compute Shader
- Create Screen GameObject
- Create ImageFlipper
- Test it Out
In this post, we’ll cover how to use a compute shader to flip an image across the x-axis, y-axis, and diagonal axis. We will also demonstrate how these operations can be combined to rotate an image.
Create a 2D Unity Project
Open the Unity Hub and create a new 2D project. I’m using
Unity 2019.4.20f1, but you should be fine using other versions.
Create Compute Shader
In Unity, right-click an empty space in the Assets folder and open the
Create submenu. Select
ComputeShader from the
Shader submenu and name it
Open the new compute shader in your code editor. By default, compute shaders contain the following code.
We’ll delete the
CSMain function and create a new one for each of our three flip operations.
Before we create our functions, we need to define some extra variables.
Texture2D<float4> InputImage: stores the original image
int height: the height of the input image
int width: the width of the input image
int2 coords: stores the new
(x,y)coordinates for individual pixel values
Define Flip Functions
The individual flip operations quite simple. They determine the coordinates of the pixel that will replace the values for a given pixel in the image. The RGB pixel values at the calculated coordinates will be stored at the current coordinates in the
Flip x-axis: subtract the y value for the current pixel’s
(x,y)coordinates from the height of the image
Flip y-axis: subtract the x value for the current pixel’s
(x,y)coordinates from the width of the image
Flip diagonal: swap the x and y values for the current pixel’s
These operations are performed on each pixel in parallel on the GPU. We’ll use the default
numthreads(8, 8, 1) for each function.
Back in Unity, right-click an empty space in the Assets folder and select
C# Script in the
Create submenu. Name the new script,
Flip and open it in your code editor.
We’ll define the following variables at the top of the script.
public ComputeShader computeShader: The compute shader that contains the flip operations
public GameObject screen: The screen to which the test image is attached
public bool flipXAxis: Toggle whether to flip the image across the x-axis
public bool flipYAxis: Toggle whether to flip the image across the y-axis
public bool flipDiag: Toggle whether to flip the image across the diagonal axis
private GameObject mainCamera: Stores a reference to the Main Camera object
private RenderTexture image: A copy of the original test image
Start() method, we’ll store a copy the original test image in the
RenderTexture. We can do so by getting a reference to the
Texture attached to the
screen and using the
Graphics.Blit() method. We’ll also get a reference to the camera so that we can adjust the view to fit the current image.
Next, we’ll define a new method called
FlipImage to handle executing the compute shader. This method will take in the image to be flipped, an empty
RenderTexture to store the flipped image, and the name of the function to execute on the compute shader.
To execute the compute shader, we need to first get the kernel index for the specified function and initialize the variables we defined in the compute shader. Once we execute the compute shader using the
computeShader.Dispatch() method, we can copy the result to the empty
RenderTexture we passed in. We could copy the result directly to the
RenderTexture containing the original image. However, this would cause an error when flipping non-square images across the diagonal axis. This is because a
RenderTexture can not dynamically change dimensions.
First, we need to make another copy of the original image so that we can edit it. We’ll store this copy in a temporary
rTex that will get released at the end of the method.
The steps are basically the same for performing each of the three flip operations. We first allocate a temporary
tempTex to store the flipped image. We then call the
FlipImage method with the appropriate function name. Next, we copy the flipped image to
rTex. Finally, we release the resources allocated for
tempTex. The steps for flipping the image across the diagonal axis is slightly different as we can’t directly copy a flipped image with different dimensions back to
rTex. Instead, we have to directly assign the currently active
After we copy
tempTex back to
rTex we’ll update the
Texture for the
screen with the flipped image and adjust the shape of the screen to fit the new dimensions.
Create Screen GameObject
Back in Unity, right-click an empty space in the
Hierarchy tab and select
Quad from the
3D Object submenu. Name the new object
Screen. The size will be updated automatically by the
Right-click an empty space in the
Hierarchy tab and select
Create Empty from the pop-up menu. Name the empty object
ImageFlipper selected, drag and drop the
Flip.cs script into the
Drag and drop the
Screen object from the
Hierarchy tab as well as the
FlipShader from the
Assets folder onto their respective spots in the
Test it Out
We’ll need a test image to try out the
ImageFlipper. You can use your own or download the one I used for this tutorial.
Drag and drop the test image into the
Assets folder. Then drag it onto the
Screen in the
Next, we need to set our Screen to use an
Unlit shader. Otherwise it will be a bit dim. With the Screen object selected, open the
Shader drop-down menu in the
Inspector tab and select
Texture from the
Now we can click the Play button and toggle the different flip checkboxes to confirm our script is working properly. If you check the performance stats, you should see that there is a negligible performance hit from flipping the image even when performing all three operations at once.
Flip Diagonal Axis
Flip X-Axis and Y-Axis
Flip X-Axis and Diagonal Axis
Flip Y-Axis and Diagonal Axis
Flip X-Axis, Y-Axis and Diagonal Axis
That is one approach to efficiently flip images on the GPU in Unity. As demonstrated above, the operations can be combined in different ways to rotate the image as well.
Project Resources: GitHub Repository