playcanvas
Version:
PlayCanvas WebGL game engine
147 lines (144 loc) • 5.86 kB
JavaScript
import { BlendState } from '../../platform/graphics/blend-state.js';
import { RenderPass } from '../../platform/graphics/render-pass.js';
import { RenderAction } from '../composition/render-action.js';
import { EVENT_PRERENDER, EVENT_POSTRENDER, EVENT_PRERENDER_LAYER, SHADER_FORWARD, EVENT_POSTRENDER_LAYER } from '../constants.js';
class RenderPassForward extends RenderPass {
constructor(device, layerComposition, scene, renderer){
super(device), this.renderActions = [], this.noDepthClear = false;
this.layerComposition = layerComposition;
this.scene = scene;
this.renderer = renderer;
}
get rendersAnything() {
return this.renderActions.length > 0;
}
addRenderAction(renderAction) {
this.renderActions.push(renderAction);
}
addLayer(cameraComponent, layer, transparent, autoClears = true) {
const ra = new RenderAction();
ra.renderTarget = this.renderTarget;
ra.camera = cameraComponent;
ra.layer = layer;
ra.transparent = transparent;
if (autoClears) {
const firstRa = this.renderActions.length === 0;
ra.setupClears(firstRa ? cameraComponent : undefined, layer);
}
this.addRenderAction(ra);
}
addLayers(composition, cameraComponent, startIndex, firstLayerClears, lastLayerId, lastLayerIsTransparent = true) {
const { layerList, subLayerList } = composition;
let clearRenderTarget = firstLayerClears;
let index = startIndex;
while(index < layerList.length){
const layer = layerList[index];
const isTransparent = subLayerList[index];
const renderedByCamera = cameraComponent.camera.layersSet.has(layer.id);
if (renderedByCamera) {
this.addLayer(cameraComponent, layer, isTransparent, clearRenderTarget);
clearRenderTarget = false;
}
index++;
if (layer.id === lastLayerId && isTransparent === lastLayerIsTransparent) {
break;
}
}
return index;
}
updateDirectionalShadows() {
const { renderer, renderActions } = this;
for(let i = 0; i < renderActions.length; i++){
const renderAction = renderActions[i];
const cameraComp = renderAction.camera;
const camera = cameraComp.camera;
const shadowDirLights = this.renderer.cameraDirShadowLights.get(camera);
if (shadowDirLights) {
for(let l = 0; l < shadowDirLights.length; l++){
const light = shadowDirLights[l];
if (renderer.dirLightShadows.get(light) !== camera) {
renderer.dirLightShadows.set(light, camera);
const shadowPass = renderer._shadowRendererDirectional.getLightRenderPass(light, camera);
if (shadowPass) {
this.beforePasses.push(shadowPass);
}
}
}
}
}
}
updateClears() {
const renderAction = this.renderActions[0];
if (renderAction) {
const cameraComponent = renderAction.camera;
const camera = cameraComponent.camera;
const fullSizeClearRect = camera.fullSizeClearRect;
this.setClearColor(fullSizeClearRect && renderAction.clearColor ? camera.clearColor : undefined);
this.setClearDepth(fullSizeClearRect && renderAction.clearDepth && !this.noDepthClear ? camera.clearDepth : undefined);
this.setClearStencil(fullSizeClearRect && renderAction.clearStencil ? camera.clearStencil : undefined);
}
}
frameUpdate() {
super.frameUpdate();
this.updateDirectionalShadows();
this.updateClears();
}
before() {
const { renderActions } = this;
for(let i = 0; i < renderActions.length; i++){
const ra = renderActions[i];
if (ra.firstCameraUse) {
this.scene.fire(EVENT_PRERENDER, ra.camera);
}
}
}
execute() {
const { layerComposition, renderActions } = this;
for(let i = 0; i < renderActions.length; i++){
const ra = renderActions[i];
const layer = ra.layer;
if (layerComposition.isEnabled(layer, ra.transparent)) {
this.renderRenderAction(ra, i === 0);
}
}
}
after() {
for(let i = 0; i < this.renderActions.length; i++){
const ra = this.renderActions[i];
if (ra.lastCameraUse) {
this.scene.fire(EVENT_POSTRENDER, ra.camera);
}
}
this.beforePasses.length = 0;
}
renderRenderAction(renderAction, firstRenderAction) {
const { renderer, scene } = this;
const device = renderer.device;
const { layer, transparent, camera } = renderAction;
if (camera) {
const originalGammaCorrection = camera.gammaCorrection;
const originalToneMapping = camera.toneMapping;
if (this.gammaCorrection !== undefined) camera.gammaCorrection = this.gammaCorrection;
if (this.toneMapping !== undefined) camera.toneMapping = this.toneMapping;
scene.fire(EVENT_PRERENDER_LAYER, camera, layer, transparent);
const options = {
lightClusters: renderAction.lightClusters
};
const shaderPass = camera.camera.shaderPassInfo?.index ?? SHADER_FORWARD;
if (!firstRenderAction || !camera.camera.fullSizeClearRect) {
options.clearColor = renderAction.clearColor;
options.clearDepth = renderAction.clearDepth;
options.clearStencil = renderAction.clearStencil;
}
const renderTarget = renderAction.renderTarget ?? device.backBuffer;
renderer.renderForwardLayer(camera.camera, renderTarget, layer, transparent, shaderPass, renderAction.viewBindGroups, options);
device.setBlendState(BlendState.NOBLEND);
device.setStencilState(null, null);
device.setAlphaToCoverage(false);
scene.fire(EVENT_POSTRENDER_LAYER, camera, layer, transparent);
if (this.gammaCorrection !== undefined) camera.gammaCorrection = originalGammaCorrection;
if (this.toneMapping !== undefined) camera.toneMapping = originalToneMapping;
}
}
}
export { RenderPassForward };