playcanvas
Version:
PlayCanvas WebGL game engine
128 lines (125 loc) • 5.06 kB
JavaScript
import { Color } from '../../core/math/color.js';
import { Texture } from '../../platform/graphics/texture.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import { RenderTarget } from '../../platform/graphics/render-target.js';
import { RenderPass } from '../../platform/graphics/render-pass.js';
import { ADDRESS_CLAMP_TO_EDGE, FILTER_LINEAR } from '../../platform/graphics/constants.js';
import { RenderPassDownsample } from './render-pass-downsample.js';
import { RenderPassUpsample } from './render-pass-upsample.js';
import { math } from '../../core/math/math.js';
/**
* @import { GraphicsDevice } from '../../platform/graphics/graphics-device.js'
*/ // based on https://learnopengl.com/Guest-Articles/2022/Phys.-Based-Bloom
/**
* Render pass implementation of HDR bloom effect.
*
* @category Graphics
* @ignore
*/ class RenderPassBloom extends RenderPass {
destroy() {
this.destroyRenderPasses();
this.destroyRenderTargets();
}
destroyRenderTargets(startIndex) {
if (startIndex === void 0) startIndex = 0;
for(var i = startIndex; i < this.renderTargets.length; i++){
var rt = this.renderTargets[i];
rt.destroyTextureBuffers();
rt.destroy();
}
this.renderTargets.length = 0;
}
destroyRenderPasses() {
for(var i = 0; i < this.beforePasses.length; i++){
this.beforePasses[i].destroy();
}
this.beforePasses.length = 0;
}
createRenderTarget(index) {
return new RenderTarget({
depth: false,
colorBuffer: new Texture(this.device, {
name: "BloomTexture" + index,
width: 1,
height: 1,
format: this.textureFormat,
mipmaps: false,
minFilter: FILTER_LINEAR,
magFilter: FILTER_LINEAR,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
})
});
}
createRenderTargets(count) {
for(var i = 0; i < count; i++){
var rt = i === 0 ? this.bloomRenderTarget : this.createRenderTarget(i);
this.renderTargets.push(rt);
}
}
// number of levels till hitting min size
calcMipLevels(width, height, minSize) {
var min = Math.min(width, height);
return Math.floor(Math.log2(min) - Math.log2(minSize));
}
createRenderPasses(numPasses) {
var device = this.device;
// progressive downscale
var passSourceTexture = this._sourceTexture;
for(var i = 0; i < numPasses; i++){
var pass = new RenderPassDownsample(device, passSourceTexture);
var rt = this.renderTargets[i];
pass.init(rt, {
resizeSource: passSourceTexture,
scaleX: 0.5,
scaleY: 0.5
});
pass.setClearColor(Color.BLACK); // clear when down-scaling
this.beforePasses.push(pass);
passSourceTexture = rt.colorBuffer;
}
// progressive upscale
passSourceTexture = this.renderTargets[numPasses - 1].colorBuffer;
for(var i1 = numPasses - 2; i1 >= 0; i1--){
var pass1 = new RenderPassUpsample(device, passSourceTexture);
var rt1 = this.renderTargets[i1];
pass1.init(rt1);
pass1.blendState = BlendState.ADDBLEND; // blend when up-scaling
this.beforePasses.push(pass1);
passSourceTexture = rt1.colorBuffer;
}
}
onDisable() {
var // resize down the persistent render target
_this_renderTargets_;
(_this_renderTargets_ = this.renderTargets[0]) == null ? void 0 : _this_renderTargets_.resize(1, 1);
// release the rest
this.destroyRenderPasses();
this.destroyRenderTargets(1);
}
frameUpdate() {
super.frameUpdate();
// create an appropriate amount of render passes
var maxNumPasses = this.calcMipLevels(this._sourceTexture.width, this._sourceTexture.height, 1);
var numPasses = math.clamp(maxNumPasses, 1, this.blurLevel);
if (this.renderTargets.length !== numPasses) {
this.destroyRenderPasses();
this.destroyRenderTargets(1);
this.createRenderTargets(numPasses);
this.createRenderPasses(numPasses);
}
}
/**
* @param {GraphicsDevice} device - The graphics device.
* @param {Texture} sourceTexture - The source texture, usually at half the resolution of the
* render target getting blurred.
* @param {number} format - The texture format.
*/ constructor(device, sourceTexture, format){
super(device), this.blurLevel = 16, this.renderTargets = [];
this._sourceTexture = sourceTexture;
this.textureFormat = format;
this.bloomRenderTarget = this.createRenderTarget(0);
this.bloomTexture = this.bloomRenderTarget.colorBuffer;
}
}
export { RenderPassBloom };