Skip to content

Render Stages

tobspr edited this page Apr 15, 2016 · 10 revisions

Render Stages are a core mechanism of the pipeline. The pipeline collects all render stages, forms a pipe out of them, and executes them in order, to get the final result.

TODO: Add graphic

Each render stage can specify which pipes and inputs it needs, and also which pipes and inputs it produces. Render stages can also modify a pipe, by simply specifying the same pipe as input and output pipe.

Example

A simple render which takes as input SomePipe1 and SomePipe2, and produces SomePipe3 looks like this:

class MyStage(RenderStage):
    
    """ Specify all required pipes here. They will be made available as
    a shader input to all contained targets """
    required_pipes = ["SomePipe1", "SomePipe2"]

    """ Specify all required inputs here. They will be made available
    as a shader input aswell. """
    required_inputs = ["some_input", "another_input"]

    def create(self):
        """ This method gets called when the stage actually gets created.
        You should setup all RenderTargets here. """

        # Construct a single Render Target, see the RenderTarget API
        self.target = self.create_target("My Target")
        self.target.add_color_texture(bits=16)
        self.target.prepare_offscreen_buffer()

    def get_produced_pipes(self):
        """ This method tells the pipeline which pipes are produced / modified
        by this stage. The key is the name of the pipe, and the value should be
        a texture handle """
        return {"SomePipe3": self._target.color_tex}

    def set_shaders(self):
        """ This method gets called after the create method, as well as on
        manual shader reload. It should set all required shaders on the 
        render targets """
        # my_stage.frag.glsl should be located in the plugin directory at
        # shader/my_stage.frag.glsl
        self.target.shader = self.load_plugin_shader("my_stage.frag.glsl")

### Specifying the Stage order

The pipeline somehow has to know at which point of the rendering process your stage belongs to. This is configured in the `config/stages.yaml`. You should insert the class name of your stage somewhere inbetween there (where it fits, and you want it to get executed).


### Writing stage shaders

Writing shaders for your stages is pretty straightforward. Assuming you created a RenderStage like the example above, which takes SomePipe1 and SomePipe2 to produce SomePipe3 (e.g. by adding both), then your shader could look like this:

```glsl
#version 400

// Base render pipeline configuration
#pragma include "render_pipeline_base.inc.glsl"

// Input from the vertex shader, range 0 .. 1
in vec4 texcoord;

// Fragment output
out vec4 output;

// Pipe inputs
uniform sampler2D SomePipe1;
uniform sampler2D SomePipe2;

void main() {
    vec4 pipe1_value = textureLod(SomePipe1, texcoord, 0);
    vec4 pipe2_value = textureLod(SomePipe2, texcoord, 0);
    output = pipe1_value + pipe2_value;
}