TODO - this isn't finished, it's not an exhaustive example.. there's lots more to add here.
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:
public class MySceneObject : SceneCustomObject
{
private MyTextureGenerator myTextureGenerator;
public MySceneObject( SceneWorld sceneWorld ) : base( sceneWorld )
{
myTextureGenerator = new();
}
public override void RenderSceneObject()
{
base.RenderSceneObject();
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()
{
texture =
Texture.
Create(
512,
512 )
.
WithUAVBinding()
.
WithFormat(
ImageFormat.
RGBA16161616F )
.
Finish();
computeShader =
new ComputeShader(
"my_compute_shader" );
}
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:
public class MyModel : ModelEntity
{
private MySceneObject mySceneObject;
public override void Spawn()
{
base.
Spawn();
Transmit =
TransmitType.
Always;
}
public override void ClientSpawn()
{
mySceneObject =
new(
Map.
Scene )
{
Transform =
this.Transform,
Position =
this.Position,
Bounds =
this.CollisionBounds +
this.Position
};
}
protected override void OnDestroy()
{
base.
OnDestroy();
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:
HEADER
{
CompileTargets = ( IS_SM_50 && ( PC || VULKAN ) );
DevShader = true;
Description = "My Cool Compute Shader";
}
FEATURES
{
}
MODES
{
Default();
}
COMMON
{
#include "common/shared.hlsl"
}
CS
{
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 );
}
}
Tips
If you're writing a compute shader you probably want to see its contents. You can do that really easily using Render.Draw2D.Quad
.
private static void DrawTexture( Texture texture, Rect rect )
{
Render.Draw2D.Texture = texture;
Render.Draw2D.Quad( rect.BottomLeft,
rect.BottomRight,
rect.TopRight,
rect.TopLeft );
}