S&box Wiki

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 ); } } ```