Table of Contents

Root Renderer Shader

An animated ribbon background drawn by a custom RootRenderFeature, which is the deepest extension point Stride offers short of writing your own compositor. Three pieces make it work and each has a distinct job: a component holding the settings an author edits, a render object carrying just what the shader needs, and the render feature that ties them to a stage. Intensity, frequency, amplitude, speed and width are all live properties.

The Program.cs file shows how to:

  • Writing a custom RootRenderFeature
  • Splitting state across component, render object and render feature
  • Registering a render feature with the graphics compositor
  • Choosing the render stage and group a feature draws in
  • Feeding component properties through to shader parameters

Root Renderer Shader

View on GitHub.

using E09_3D_RootRendererShader.Renderers;
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Rendering.Compositing;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Rendering;

using var game = new Game();

var sceneSetup = new SceneSetup3D
{
    Camera = CameraSetup.Perspective(),
    Ground = null,
    Profiler = true,
    Resizable = true,
};

game.Run(sceneSetup, start: Start);

void Start(Scene scene)
{
    AddRenderFeature();

    // A component, because its processor is what hands the render objects to the visibility group
    scene.Entities.Add(new Entity
    {
        new RibbonBackgroundComponent
        {
            Intensity = 0.9f,
            Frequency = 0.9f,
            Amplitude = 0.9f,
            Speed = 2f,
            WidthFactor = 0.9f,
        },
    });

    game.Window.Position = new Int2(50, 50);
}

// The render feature that draws a RibbonBackgroundComponent, in the opaque stage
void AddRenderFeature()
{
    game.SceneSystem.GraphicsCompositor.TryGetRenderStage("Opaque", out var opaqueRenderStage);

    game.AddRootRenderFeature(new RibbonBackgroundRenderFeature
    {
        RenderStageSelectors =
        {
            new SimpleGroupToRenderStageSelector
            {
                EffectName = "RibbonBackground",
                RenderGroup = RenderGroupMask.All,
                RenderStage = opaqueRenderStage,
            }
        }
    });
}