Revision Difference
Compute_Shaders#548207
<cat>Material.ShaderBasic</cat>
<title>Compute Shaders</title>
⤶
<note>⤶
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.⤶
⤶
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:
```
// 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.Render();⤶
MyTextureGenerator.Dispatch();
}
}
```
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 );
}
}
```