# Rendering

The Render Graph is a system used by the small game framework to manage the entire rendering process, and it can also be considered as an abstraction of the rendering pipeline.

The basis of the rendering graph is the rendering node. These rendering nodes are organized to form a graph. In actual operation, these nodes will be topologically sorted and then executed in order.

Note that the current rendering is not the final version, only a mode of code construction is provided, and it will become an important resource in the future.

# Node

The node is the basis of the rendering graph. Its base class is engine.RGNode. An RGNode is mainly composed of input, processing, and output. Let's take a look at the implementation of a typical node:

interface IRGCullNodeOptions {
  lightMode: string;
  initSize?: number;
}

class RGCullNode extends RGNode<{camera:'Camera'},'MeshList', IRGCullNodeOptions> {
  public inputTypes = {camera:'Camera' as'Camera'};
  public outputType:'MeshList' ='MeshList';

  public onActive(context: RenderSystem, options: IRGCullNodeOptions) {
    this._output = new Kanata.ScalableList(options.initSize || 2048);
  }

  public onExecute(context: RenderSystem, options: IRGCullNodeOptions) {
    this.getInput('camera').cull(this._output!, options.lightMode);
  }

  public onDisable(context: RenderSystem, options: IRGCullNodeOptions) {
    this._output = undefined;
  }
}

This is a culling node, and its composition is divided into three parts: input and output, initialization and life cycle.

# input Output

The type of input and output affects its connection with other nodes. In the above culling node, these parts are embodied as:

The first is the input type, which needs to be specified in the first type parameter and member variable at the same time, here is {camera:'Camera'} and public inputTypes = {camera:'Camera' as'Camera'};, The reason why it seems to be written twice is because TS's type system cannot guarantee runtime checking, and this check can be bypassed if it is not strictly required. In this definition, we can see that we have specified the input type Camera for the input of camera.

The second is the output type, which is the second type parameter and member variable, here MeshList and public outputType:'MeshList' ='MeshList';.

The input and output types are defined in engine.IRGData, and developers can extend them by themselves. Currently, the built-in types are:

Type Key Corresponding Type Description
None void Empty type
Camera BaseCamera Camera
RenderTarget RenderTexture/Screen Render Target
MeshList ScalableList Cull List or Draw List
LightList BaseLight[] Light Source List

# Initialization

In addition to input and output, there are initialization type parameters. Each node can have its own initialization parameters to customize this node to achieve different functions.

The initialization type parameter is the third type parameter of RGNode. In this example, it is IRGCullNodeOptions, that is, {lightMode: string, initSize?: number}, indicating that this type of object can be passed in when creating this node Initialize this node.

And this initialization parameter will also be passed into each life cycle for developers to use.

# The life cycle

The type parameter determines the external interface and initialization of the node, and the life cycle determines the internal operation of the node. It can be seen from this culling node that there are a total of three life cycles, and they all have the same parameters.

  1. onInit: Triggered when a node is just created.
  2. onActive: when the node is in a rendering graph, and it is triggered when the graph start.
  3. onExecute: Triggered when every frame of rendering is executed.
  4. onDisable: Triggered when a node is in a rendering graph and is disabled or removed out of the graph.

For example, in the culling node, the output _output is created when the graph is started, and the cull method of the input camera is used when the graph is executed, and the _output is destroyed when the graph is deactivated to prevent memory leaks. .

In the preparation of the life cycle, you can also see the role of its parameters:

  1. Context: It is actually the renderSystem mentioned in the previous chapter, which can be used to obtain some information about the rendering system.
  2. options: is the initialization parameter of the node.

# picture

With nodes, you can connect these nodes into a graph. The rendering graph is engine.RenderGraph in the small game framework, which provides some methods to manage and drive all the rendering nodes.

In order to customize a rendering, the developer must first define his own class:

export default class CustomRG extends RenderGraph {
  public onActive(context: RenderSystem) {}

  public onCamerasChange(cameras: BaseCamera[]) {}

  public onExecuteBegin(context: RenderSystem) {}

  public onExecuteDone(context: RenderSystem) {}

  public onDisable(context: RenderSystem) {
}

It can be seen that RenderGraph also has a life cycle mechanism. But before we understand the life cycle, we first need to understand the relationship between graphs and nodes.

# Create and destroy nodes

Careful developers should have noticed that when we introduced nodes, we did not discuss how to create and destroy nodes. This is because the creation and destruction of nodes depends on RenderGraph and cannot be performed independently. This is to ensure that the graph can manage the entire life of the node. cycle. In order to create and destroy nodes, RenderGraph provides two methods:

// Create
const rgNode = rg.createNode(name, clz, options);

// destroy
rg.destroyNode(rgNode);

To create a node, you must provide a name name, which is to facilitate debugging, then the node class clz, such as the above-mentioned RGCullNode, and finally the initialization parameter options corresponding to this class.

# Connect nodes and compile

After the nodes are created, they need to be connected to form a graph:

// connect two nodes
rg.connect(from, to, inputKey);

// Disconnect the two nodes
rg.disconnect(from, node);

The connection and disconnection methods both need to provide two nodes from and to, as the name suggests is to connect from the from node to the to node, and for the connection, you may also need to provide the inputKey, which is due to one The node may have multiple inputs, so a key is needed to determine which input of the to node this from node needs to connect to.

Of course, it is not necessary to provide inputKey, which means that there is no need to use the output of the from node as the input of the to node. In this case, the order of execution of the two nodes is actually guaranteed. But once inputKey is provided, you must ensure that the output type of from is the same as the input type of this key of to, otherwise an error will be reported during compilation.

After the node connection is completed, when the graph is run for the first time, the compilation process will be executed. The essence of the compilation process is to topologically sort all the nodes of the entire graph, verify the connection relationship of each node, and execute the onActive life cycle at the same time.

# The life cycle

After understanding how nodes are created and connected, you can further clarify the life cycle of RenderGraph:

  1. onActive: Triggered when the graph is used, see the next section for use.
  2. onCamerasChange: Triggered when the camera list in the scene changes. Developers can use this method to build the RenderGraph with the camera dimension, which will be in the subsequent builtin pipeline ) Said.
  3. onExecuteBegin: Triggered before the start of each frame rendering, developers can set some global uniforms here.
  4. onExecuteDone: Triggered after the rendering of each frame.
  5. onDisable: Triggered when the rendered image is not in use.

# Use and debug

To use RenderGraph, you only need to create it and use it:

const rg = new CustomRG();

game.renderSystem.useRenderGraph(rg);

If you need to know the running status, developers can use rg.showDebugInfo() to see the order of nodes after topological sorting.

点击咨询小助手