Revision Difference
Compute_Shaders#548207
<cat>Material.ShaderBasic</cat>
<title>Compute Shaders</title>
<note>
You can use compute shaders to do lots of things, but their most common use is to generate textures at blazing fast speeds; here's an example that shows you how you can do that.
TODO - this isn't finished, it's not an exhaustive example.. there's lots more to add here.
</note>
You can use compute shaders to do stuff.
Here's how you can write a really simple compute texture to generate a texture on the GPU at runtime.
## C# side
You'll first need to create a `SceneCustomObject` so that you can call `Dispatch` within the render loop:
```
// This is what we use in order to dispatch our compute shader.
public class MySceneObject : SceneCustomObject
{
private MyTextureGenerator myTextureGenerator;
public MyTextureGenerator MyTextureGenerator { get; }
public MySceneObject( SceneWorld sceneWorld ) : base( sceneWorld )
{
myTextureGenerator = new();
MyTextureGenerator = new();
}
public override void RenderSceneObject()
{
base.RenderSceneObject();
MyTextureGenerator.Dispatch();
myTextureGenerator.Render();
}
}
```
You'll also probably want to wrap your compute stuff in a nice class so that everything's nice and tidy:
```
public MyTextureGenerator()
// This is what contains our compute shader instance, as well as the texture
// we're going to be rendering to.
public class MyTextureGenerator
{
// Create a texture that we can use
texture = Texture.Create( 512, 512 )
.WithUAVBinding() // Needs to have this if we're using it in a compute shader
.WithFormat( ImageFormat.RGBA16161616F ) // Other formats are available :-)
.Finish();
computeShader = new ComputeShader( "my_compute_shader" ); // This should be the name of your shader
private ComputeShader computeShader;
public Texture Texture { get; }
public MyTextureGenerator()
{
// Create a texture that we can use
Texture = Texture.Create( 512, 512 )
.WithUAVBinding() // Needs to have this if we're using it in a compute shader
.WithFormat( ImageFormat.RGBA16161616F ) // Other formats are available :-)
.Finish();
computeShader = new ComputeShader( "my_compute_shader" ); // This should be the name of your shader
}
public void Dispatch()
{
// Set up the shader...
computeShader.Attributes.Set( "OutputTexture", Texture );
// ...and run it!
computeShader.Dispatch( Texture.Width, Texture.Height, 1 );
}
}
public void Render()
{
computeShader.Attributes.Set( "OutputTexture", texture );
computeShader.Dispatch( texture.Width, texture.Height, 1 );
}
```
You also want to actually use that scene object in an entity... here's how you can do that:
```
// This is the game entity we use to draw a model with our generated texture.
public class MyModel : ModelEntity
{
private MySceneObject mySceneObject;
public override void Spawn()
{
base.Spawn();
Transmit = TransmitType.Always;
}
public override void ClientSpawn()
{
// Set up our dispatching scene object.
mySceneObject = new( Map.Scene )
{
Transform = this.Transform,
Position = this.Position,
Bounds = this.CollisionBounds + this.Position
Transform = Transform,
Position = Position,
Bounds = CollisionBounds + Position
};
}
[Event.PreRender]
public void OnFrame()
{
// Here's where we assign our generated texture to this entity's model.
SceneObject.Attributes.Set( "Albedo", mySceneObject.MyTextureGenerator.Texture );
}
protected override void OnDestroy()
{
base.OnDestroy();
mySceneObject?.Delete();
// Make sure we destroy our custom scene object so that we don't leak any!
mySceneObject?.Delete();
}
}
```
Spawn your entity somewhere, make sure it's visible.
## Shader
Compute shaders are similar to normal VS/FS shaders, but they're a bit shorter and you can forego a lot of the includes.
Here's a really simple one that'll generate a solid pink texture:
```
//=========================================================================================================================
// Optional
//=========================================================================================================================
HEADER
{
DevShader = true;
Description = "My Cool Compute Shader";
}
//=========================================================================================================================
// Optional
//=========================================================================================================================
FEATURES
{
}
//=========================================================================================================================
MODES
{
Default();
}
//=========================================================================================================================
COMMON
{
#include "common/shared.hlsl"
}
//=========================================================================================================================
CS
{
// Output texture
RWTexture2D<float4> g_tOutput< Attribute( "OutputTexture" ); >;
[numthreads(8, 8, 1)]
void MainCs( uint uGroupIndex : SV_GroupIndex, uint3 vThreadId : SV_DispatchThreadID )
{
g_tOutput[vThreadId.xy] = float4( 1, 0, 1, 1 );
}
}
```