Revision Difference
Compute_Shaders#548208
<cat>Material.ShaderBasic</cat>
<title>Compute Shaders</title>
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.
## C# side
⤶
You'll first need to create a `SceneCustomObject` so that you can call `Dispatch` within the render loop:⤶
⤶
Let's wrap our compute stuff in a class so it's nice and tidy:⤶
```
// This is what we use in order to dispatch our compute shader.⤶
public class MySceneObject : SceneCustomObject⤶
{⤶
public MyTextureGenerator MyTextureGenerator { get; }⤶
⤶
public MySceneObject( SceneWorld sceneWorld ) : base( sceneWorld )⤶
{⤶
MyTextureGenerator = new();⤶
}⤶
⤶
public override void RenderSceneObject()⤶
{⤶
MyTextureGenerator.Dispatch();⤶
}⤶
}⤶
```⤶
⤶
You'll also probably want to wrap your compute stuff in a nice class so that everything's nice and tidy:⤶
⤶
```⤶
// This is what contains our compute shader instance, as well as the texture
// we're going to be rendering to.
public class MyTextureGenerator
{
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 );
}
}
```
You also want to actually use that scene object in an entity... here's how you can do that:⤶
You then want to actually use that class in an entity:⤶
```
// This is the game entity we use to draw a model with our generated texture.
public class MyModel : ModelEntity
{
private MySceneObject mySceneObject;
private MyTextureGenerator myTextureGenerator;
public override void Spawn()
{
base.Spawn();
Transmit = TransmitType.Always;
}
public override void ClientSpawn()
{
// Set up our dispatching scene object.
mySceneObject = new( Map.Scene )
{⤶
Transform = Transform,⤶
Position = Position,⤶
Bounds = CollisionBounds + Position⤶
};⤶
// Set up our dispatching class.
myTextureGenerator = new();
}
[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();⤶
⤶
// Make sure we destroy our custom scene object so that we don't leak any!⤶
mySceneObject?.Delete();⤶
// You can call this wherever you want, but we'll update it every frame for now.
myTextureGenerator.Dispatch();
⤶
// Here's where we assign our generated texture to this entity's model.
SceneObject.Attributes.Set( "Albedo", myTextureGenerator.Texture );
}
}
```
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 );
}
}
```