playcanvas
Version:
PlayCanvas WebGL game engine
105 lines (102 loc) • 3.78 kB
JavaScript
import { PIXELFORMAT_R32F, PIXELFORMAT_RGBA8, ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST } from '../../platform/graphics/constants.js';
import { Texture } from '../../platform/graphics/texture.js';
import { RenderPass } from '../../platform/graphics/render-pass.js';
import { RenderTarget } from '../../platform/graphics/render-target.js';
import { LAYERID_DEPTH, SHADER_PREPASS } from '../../scene/constants.js';
import { Color } from '../../core/math/color.js';
import { FloatPacking } from '../../core/math/float-packing.js';
const tempMeshInstances = [];
const DEPTH_UNIFORM_NAME = 'uSceneDepthMap';
class RenderPassPrepass extends RenderPass {
constructor(device, scene, renderer, camera, options){
super(device), this.viewBindGroups = [], this.linearDepthClearValue = new Color(0, 0, 0, 0);
this.scene = scene;
this.renderer = renderer;
this.camera = camera;
this.setupRenderTarget(options);
}
destroy() {
super.destroy();
this.renderTarget?.destroy();
this.renderTarget = null;
this.linearDepthTexture?.destroy();
this.linearDepthTexture = null;
this.viewBindGroups.forEach((bg)=>{
bg.defaultUniformBuffer.destroy();
bg.destroy();
});
this.viewBindGroups.length = 0;
}
setupRenderTarget(options) {
const { device } = this;
this.linearDepthFormat = device.textureFloatRenderable ? PIXELFORMAT_R32F : PIXELFORMAT_RGBA8;
this.linearDepthTexture = new Texture(device, {
name: 'SceneLinearDepthTexture',
width: 1,
height: 1,
format: this.linearDepthFormat,
mipmaps: false,
minFilter: FILTER_NEAREST,
magFilter: FILTER_NEAREST,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
});
const renderTarget = new RenderTarget({
name: 'PrepassRT',
colorBuffer: this.linearDepthTexture,
depth: true,
samples: 1
});
this.camera.shaderParams.sceneDepthMapLinear = true;
this.init(renderTarget, options);
}
after() {
this.device.scope.resolve(DEPTH_UNIFORM_NAME).setValue(this.linearDepthTexture);
}
execute() {
const { renderer, scene, renderTarget } = this;
const camera = this.camera.camera;
const layers = scene.layers.layerList;
const subLayerEnabled = scene.layers.subLayerEnabled;
const isTransparent = scene.layers.subLayerList;
for(let i = 0; i < layers.length; i++){
const layer = layers[i];
if (layer.id === LAYERID_DEPTH) {
break;
}
if (layer.enabled && subLayerEnabled[i]) {
if (layer.camerasSet.has(camera)) {
const culledInstances = layer.getCulledInstances(camera);
const meshInstances = isTransparent[i] ? culledInstances.transparent : culledInstances.opaque;
for(let j = 0; j < meshInstances.length; j++){
const meshInstance = meshInstances[j];
if (meshInstance.material?.depthWrite) {
tempMeshInstances.push(meshInstance);
}
}
renderer.renderForwardLayer(camera, renderTarget, null, undefined, SHADER_PREPASS, this.viewBindGroups, {
meshInstances: tempMeshInstances
});
tempMeshInstances.length = 0;
}
}
}
}
frameUpdate() {
super.frameUpdate();
const { camera } = this;
this.setClearDepth(camera.clearDepthBuffer ? 1 : undefined);
let clearValue;
if (camera.clearDepthBuffer) {
const farClip = camera.farClip - Number.MIN_VALUE;
clearValue = this.linearDepthClearValue;
if (this.linearDepthFormat === PIXELFORMAT_R32F) {
clearValue.r = farClip;
} else {
FloatPacking.float2RGBA8(farClip, clearValue);
}
}
this.setClearColor(clearValue);
}
}
export { RenderPassPrepass };