Custom Scene Renderer with SpriteBatch
Ta treść nie jest jeszcze dostępna w Twoim języku.
To use custom shaders and effects with sprites we need to create a Custom Scene Renderer. This renderer is an example how the whole process works.
Shader parameters
Section titled “Shader parameters”We need to create a struct that will represent the data that we want to pass to the shader. This struct will by shader’s StructuredBuffer.
public struct ShaderParameters{ public float Progress;}Shader
Section titled “Shader”An example of a very basic shader that just changes the textures color to green.
shader ExampleShader : SpriteBase{ struct ShaderParameters { float Progress; };
StructuredBuffer<ShaderParameters> Data;
stage override float4 Shading() { float progress = Data[streams.InstanceID].Progress; return float4(0.0f, progress, 0.0f, 1.0f); }};public static partial class ExampleShaderKeys{ public static readonly ObjectParameterKey<Buffer> Data = ParameterKeys.NewObject<Buffer>();}Custom Scene Renderer
Section titled “Custom Scene Renderer”We need a Custom Scene Renderer to inject our drawing logic into Stride’s render pipeline.
public class CustomSceneRenderer : SceneRendererBase{ // Sprite batch is used to draw everything in a single draw call. // You need only a single instance of this per SceneRenderer. private SpriteBatch _spriteBatch;
// The depth texture is a buffer for managing the drawing order. // Thanks to this objects behind other objects are not rendered. // You should create a blank texture in an external class and pass it to the Renderer. private Texture _depthTexture;
// The actual texture for GPU to draw on. // You should create a blank texture in an external class and pass it to the Renderer. private Texture _renderTexture;
// Your shader instance. // You need only a single instance of this per SceneRenderer. private EffectInstance _effectInstance;
// A buffer used to pass the data from the CPU to the GPU. private Buffer<ShaderParameters> _effectBuffer;
// The params that will be passed to the shader. // These params should be managed by some external script, like "ButtonAnimationScript". // You will need an instance of the params per the element you want to draw. private ShaderParameters _shaderParams;
protected override void InitializeCore() { _spriteBatch = new SpriteBatch(GraphicsDevice); _effectInstance = new EffectInstance(EffectSystem.LoadEffect("ExampleShader").WaitForResult()); _effectBuffer = Buffer.Structured.New<ShaderParameters>(GraphicsDevice, 1); // 1 - number of the elements in the buffer. _effectInstance.Parameters.Set(ExampleShaderKeys.Data, _effectBuffer);
// ------------------------- // THIS SHOULD BE PASSED FROM THE EXTERNAL CLASS // ------------------------- _depthTexture = Texture.New2D(GraphicsDevice, 64, 64, false, PixelFormat.D16_UNorm, TextureFlags.DepthStencil); _renderTexture = Texture.New2D(GraphicsDevice, 64, 64, false, PixelFormat.R8G8B8A8_UNorm, TextureFlags.ShaderResource | TextureFlags.RenderTarget); _shaderParams = new ShaderParameters { Progress = 0.5f }; }
protected override void DrawCore(RenderContext context, RenderDrawContext drawContext) { // A list of commands that will be send to the GPU. var commandList = drawContext.CommandList;
// We don't want to draw our element on the scene directly, so we need to store a reference to the original RenderTarget; var oldRenderTexture = commandList.RenderTarget;
// The same as above, we don't want to use a depth map from the scene. var oldDepthTexture = commandList.DepthStencilBuffer;
// Pass the params to the shader. // In real implementation you will have a list of params instead of a single instance. _effectBuffer.SetData(commandList, shaderParams)
// Change the render target to our texture. commandList.SetRenderTargetAndViewport(_depthTexture, _renderTexture);
// Clear the textures so we have a blank canvas to draw on. commandList.Clear(_depthTexture, DepthStencilClearOptions.DepthBuffer); commandList.Clear(_renderTexture, Color4.Black);
// Instructs the sprite buffer that we want to draw the sprites with a single draw call (Deferred). _spriteBatch.Begin(drawContext.GraphicsContext, SpriteSortMode.Deferred, _effectInstance);
// Draw your elements like text or other textures. //_spriteBatch.Draw()
// Instructs the sprite buffer to send the commands to the GPU. _spriteBatch.End();
// Sets the original textures so our scene is renderer properly. commandList.SetRenderTargetAndViewport(oldDepthTexture, oldRenderTexture);
// ------------------------- // HOW TO DRAW THE TEXTURE ON THE SCREEN // This code shows how to draw the rendered texture from the code above to the game screen. // -------------------------
_spriteBatch.Begin(drawContext.GraphicsContext, SpriteSortMode.Deffered, _effectInstance); _spriteBatch.Draw(_renderTexture, new Vector2(0, 0)); // (0, 0) -> top-left corner of the screen. _spriteBatch.End(); }}