# Built-in pipeline
In addition to the built-in nodes, the mini game framework also provides built-in pipelines to meet different needs. There are two pipelines by default.
# Forward rendering pipeline
The forward rendering pipeline ForwardBaseRG
is a standard pipeline built into the small game framework, which integrates Forward Base
and Forward Add
, and at the same time incorporates UI, Gizmo, and Skybox.
As a built-in pipeline, in order to integrate with other parts, it is constructed based on the camera Camera
, and each active camera in the scene has its own sub-rendered image. So the basic process of this built-in pipeline is:
onCamerasChange
-> Traversecameras
-> Generate subgraphs for eachcamera
-> Connect these subgraphs end to end
The graph itself is cached for the subgraphs to avoid reconstructing the entire graph every time it is modified. In addition to building the graph, another important part is the creation and update of the global uniform, which directly affects the update of each rendering node. In addition, generally speaking, the registration of the default downgrade effect is also carried out here.
Since all aspects are involved, the code of the entire built-in pipeline will be directly commented out below:
export default class ForwardBaseRG extends RenderGraph {
// Has the degraded shadow Effect been registered?
protected _shadowFallbackRegistered: boolean = false;
// Global Uniform
protected _globalUniforms!: {
// Global Uniform in the ForwardBase stage
fbUniforms: engine.UniformBlock;
// Global Uniform in the ForwardAdd phase
faUniforms: engine.UniformBlock;
// Global Uniform in the UI stage
uiUniforms?: engine.UniformBlock;
// Global Uniform in the shadow phase
scUniforms?: engine.UniformBlock;
// #if defined(EDITOR)
rcUniforms?: engine.UniformBlock;
// #endif
};
protected _subGraphs: {[nodeId: number]: BaseCamera} = {};
// View used to clear the screen by default
protected _defaultClearView?: engine.View;
public onActive(context: RenderSystem) {
this._globalUniforms = {
fbUniforms: new engine.UniformBlock(forwardBaseUD),
faUniforms: new engine.UniformBlock(forwardAddUD),
uiUniforms: new engine.UniformBlock(forwardBaseUD),
scUniforms: new engine.UniformBlock(shadowCaterUD),
// #if defined(EDITOR)
rcUniforms: new engine.UniformBlock(forwardBaseUD)
// #endif
}
this._defaultClearView = new engine.View({
passAction: {
clearColor: [0, 0, 0, 1],
colorAction: engine.ELoadAction.CLEAR
},
viewport: {x: 0, y: 0, w: 1, h: 1},
scissor: {x: 0, y: 0, w: 1, h: 1}
});
this._rebuildRG(context.cameras, context.changedCameras);
}
public onCamerasChange(cameras: BaseCamera[], changeCameras: BaseCamera[]) {
this._rebuildRG(cameras, changeCameras);
}
// Create the whole picture by `cameras`, the camera list has been sorted
protected _rebuildRG(cameras: BaseCamera[], changeCameras: BaseCamera[]) {
// First clear the entire picture, but keep the sub-pictures that Camera has not changed
const cachedCameras: {[cameraId: number]: TRGNodeAny} = {};
this._clear((node: TRGNodeAny) => {
const camera = this._subGraphs[node.id];
if (camera && changeCameras.indexOf(camera) <0) {
cachedCameras[camera.id] = node;
return true;
}
delete this._subGraphs[node.id];
return false;
});
let lastNode: TRGNodeAny;
// If there is only one camera and it is a UI camera, the screen is forced to clear once, because the main UI camera is not clear by default
if (cameras[0] instanceof UICamera && (!cameras[0].renderTarget || cameras[0].renderTarget instanceof Screen)) {
const defaultCameraNode = this.createNode<RGGenViewNode>(`default-view-gen`, RGGenViewNode, {viewObject: {view: this._defaultClearView!}});
const defaultRtNode = this.createNode<RGGenRenderTargetNode>('rt-screen', RGGenRenderTargetNode, {createRenderTarget: () => this.context.screen});
const defaultClearNode = this.createNode<RGClearNode>('default-view-clear', RGClearNode, {});
this.connect(defaultCameraNode, defaultClearNode,'camera');
this.connect(defaultRtNode, defaultClearNode,'renderTarget');
lastNode = defaultClearNode;
}
// Use the cache to create all subgraph nodes
cameras.forEach(camera => {
let subGraph = cachedCameras[camera.id] as TForwardBaseSubGraphNode;
if (!subGraph) {
subGraph = this.createNode<TForwardBaseSubGraphNode>(`subGraph-${camera.entity.name}`, RGSubGraphNode, {
// class of subgraph
RGClass: ForwardBaseSubGraph,
options: {
...this._globalUniforms,
camera
}
});
this._subGraphs[subGraph.id] = camera;
}
lastNode && this.connect(lastNode, subGraph);
lastNode = subGraph;
});
}
// Before the start of each frame rendering, set the global Uniform
public onExecuteBegin(context: RenderSystem) {
const dirL = context.lights.mainDirectionalLight;
const uniforms = this._globalUniforms.fbUniforms!;
const settings = this.game.activeScene.settings;
uniforms.setUniform("u_ambientLight", settings.ambientLight._raw);
tempArr4[0] = settings.fogMode;
tempArr4[1] = settings.fogStart;
tempArr4[2] = settings.fogStart + settings.fogRange;
tempArr4[3] = settings.fogDensity;
uniforms.setUniform("u_fogInfos", tempArr4);
uniforms.setUniform("u_fogColor", settings.fogColor._raw);
uniforms.setUniform("u_lightDir", dirL? dirL.direction._raw: [0, 0, 1]);
uniforms.setUniform("u_lightColor", dirL? dirL.color.scale(dirL.intensity, tempVec3)._raw: [0, 0, 0]);
tempArr1[0] = this.game.gameTime;
uniforms.setUniform("u_gameTime", tempArr1);
tempArr3[0] = settings.subtractiveShadowColor.r / 255.0;
tempArr3[1] = settings.subtractiveShadowColor.g / 255.0;
tempArr3[2] = settings.subtractiveShadowColor.b / 255.0;
uniforms.setUniform("u_shadowColor", tempArr3);
tempArr1[0] = 1-(dirL? dirL.shadowStrength: 1);
uniforms.setUniform("u_shadowStrength", tempArr1);
unifo