Skip to content

Commit

Permalink
Update to render passes - generate scene half sized texture (#7175)
Browse files Browse the repository at this point in the history
* Update to render passes - generate scene half sized texture

* Update src/platform/graphics/render-target.js

Co-authored-by: Will Eastcott <[email protected]>

---------

Co-authored-by: Martin Valigursky <[email protected]>
Co-authored-by: Will Eastcott <[email protected]>
  • Loading branch information
3 people authored and slimbuck committed Dec 9, 2024
1 parent cd8b89b commit 1402d24
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ assetListLoader.load(() => {
const cylinderMesh = pc.Mesh.fromGeometry(app.graphicsDevice, new pc.CylinderGeometry({ capSegments: 200 }));
const cylinder = new pc.Entity();
cylinder.addComponent('render', {
material: material,
meshInstances: [new pc.MeshInstance(cylinderMesh, material)],
castShadows: true
});
Expand Down
31 changes: 11 additions & 20 deletions src/extras/render-passes/render-pass-bloom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ 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.
Expand All @@ -27,6 +31,12 @@ class RenderPassBloom extends RenderPass {

renderTargets = [];

/**
* @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._sourceTexture = sourceTexture;
Expand Down Expand Up @@ -95,8 +105,7 @@ class RenderPassBloom extends RenderPass {
let passSourceTexture = this._sourceTexture;
for (let i = 0; i < numPasses; i++) {

const fast = i === 0; // fast box downscale for the first pass
const pass = new RenderPassDownsample(device, passSourceTexture, fast);
const pass = new RenderPassDownsample(device, passSourceTexture);
const rt = this.renderTargets[i];
pass.init(rt, {
resizeSource: passSourceTexture,
Expand Down Expand Up @@ -130,24 +139,6 @@ class RenderPassBloom extends RenderPass {
this.destroyRenderTargets(1);
}

set sourceTexture(value) {
this._sourceTexture = value;

if (this.beforePasses.length > 0) {
const firstPass = this.beforePasses[0];

// change resize source
firstPass.options.resizeSource = value;

// change downsample source
firstPass.sourceTexture = value;
}
}

get sourceTexture() {
return this._sourceTexture;
}

frameUpdate() {
super.frameUpdate();

Expand Down
98 changes: 72 additions & 26 deletions src/extras/render-passes/render-pass-camera-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { RenderPassPrepass } from './render-pass-prepass.js';
import { RenderPassSsao } from './render-pass-ssao.js';
import { SSAOTYPE_COMBINE, SSAOTYPE_LIGHTING, SSAOTYPE_NONE } from './constants.js';
import { Debug } from '../../core/debug.js';
import { RenderPassDownsample } from './render-pass-downsample.js';
import { Color } from '../../core/math/color.js';

class CameraFrameOptions {
formats;
Expand Down Expand Up @@ -71,6 +73,8 @@ class RenderPassCameraFrame extends RenderPass {

taaPass;

scenePassHalf;

_renderTargetScale = 1;

/**
Expand All @@ -96,13 +100,20 @@ class RenderPassCameraFrame extends RenderPass {
reset() {

this.sceneTexture = null;
this.sceneTextureHalf = null;

if (this.rt) {
this.rt.destroyTextureBuffers();
this.rt.destroy();
this.rt = null;
}

if (this.rtHalf) {
this.rtHalf.destroyTextureBuffers();
this.rtHalf.destroy();
this.rtHalf = null;
}

// destroy all passes we created
this.beforePasses.forEach(pass => pass.destroy());
this.beforePasses.length = 0;
Expand All @@ -116,6 +127,7 @@ class RenderPassCameraFrame extends RenderPass {
this.ssaoPass = null;
this.taaPass = null;
this.afterPass = null;
this.scenePassHalf = null;
}

sanitizeOptions(options) {
Expand Down Expand Up @@ -180,6 +192,29 @@ class RenderPassCameraFrame extends RenderPass {
}
}

createRenderTarget(name, depth, stencil, samples, flipY) {

const texture = new Texture(this.device, {
name: name,
width: 4,
height: 4,
format: this.hdrFormat,
mipmaps: false,
minFilter: FILTER_LINEAR,
magFilter: FILTER_LINEAR,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
});

return new RenderTarget({
colorBuffer: texture,
depth: depth,
stencil: stencil,
samples: samples,
flipY: flipY
});
}

setupRenderPasses(options) {

const { device } = this;
Expand All @@ -188,6 +223,12 @@ class RenderPassCameraFrame extends RenderPass {

this.hdrFormat = device.getRenderableHdrFormat(options.formats, true, options.samples) || PIXELFORMAT_RGBA8;

// HDR bloom is not supported on RGBA8 format
this._bloomEnabled = options.bloomEnabled && this.hdrFormat !== PIXELFORMAT_RGBA8;

// bloom needs half resolution scene texture
this._sceneHalfEnabled = this._bloomEnabled;

// camera renders in HDR mode (linear output, no tonemapping)
cameraComponent.gammaCorrection = GAMMA_NONE;
cameraComponent.toneMapping = TONEMAP_NONE;
Expand All @@ -196,25 +237,15 @@ class RenderPassCameraFrame extends RenderPass {
cameraComponent.shaderParams.ssaoEnabled = options.ssaoType === SSAOTYPE_LIGHTING;

// create a render target to render the scene into
this.sceneTexture = new Texture(device, {
name: 'SceneColor',
width: 4,
height: 4,
format: this.hdrFormat,
mipmaps: false,
minFilter: FILTER_LINEAR,
magFilter: FILTER_LINEAR,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
});

this.rt = new RenderTarget({
colorBuffer: this.sceneTexture,
depth: true,
stencil: options.stencil,
samples: options.samples,
flipY: !!targetRenderTarget?.flipY // flipY is inherited from the target renderTarget
});
const flipY = !!targetRenderTarget?.flipY; // flipY is inherited from the target renderTarget
this.rt = this.createRenderTarget('SceneColor', true, options.stencil, options.samples, flipY);
this.sceneTexture = this.rt.colorBuffer;

// when half size scene color buffer is used
if (this._sceneHalfEnabled) {
this.rtHalf = this.createRenderTarget('SceneColorHalf', false, false, 1, flipY);
this.sceneTextureHalf = this.rtHalf.colorBuffer;
}

this.sceneOptions = {
resizeSource: targetRenderTarget,
Expand All @@ -231,7 +262,7 @@ class RenderPassCameraFrame extends RenderPass {
collectPasses() {

// use these prepared render passes in the order they should be executed
return [this.prePass, this.ssaoPass, this.scenePass, this.colorGrabPass, this.scenePassTransparent, this.taaPass, this.bloomPass, this.composePass, this.afterPass];
return [this.prePass, this.ssaoPass, this.scenePass, this.colorGrabPass, this.scenePassTransparent, this.taaPass, this.scenePassHalf, this.bloomPass, this.composePass, this.afterPass];
}

createPasses(options) {
Expand All @@ -248,8 +279,11 @@ class RenderPassCameraFrame extends RenderPass {
// TAA
const sceneTextureWithTaa = this.setupTaaPass(options);

// downscale to half resolution
this.setupSceneHalfPass(options, sceneTextureWithTaa);

// bloom
this.setupBloomPass(options, sceneTextureWithTaa);
this.setupBloomPass(options, this.sceneTextureHalf);

// compose
this.setupComposePass(options);
Expand Down Expand Up @@ -328,9 +362,23 @@ class RenderPassCameraFrame extends RenderPass {
}
}

setupSceneHalfPass(options, sourceTexture) {

if (this._sceneHalfEnabled) {
this.scenePassHalf = new RenderPassDownsample(this.device, this.sceneTexture, true);
this.scenePassHalf.name = 'RenderPassSceneHalf';
this.scenePassHalf.init(this.rtHalf, {
resizeSource: sourceTexture,
scaleX: 0.5,
scaleY: 0.5
});
this.scenePassHalf.setClearColor(Color.BLACK);
}
}

setupBloomPass(options, inputTexture) {
// HDR bloom is not supported on RGBA8 format
if (options.bloomEnabled && this.hdrFormat !== PIXELFORMAT_RGBA8) {

if (this._bloomEnabled) {
// create a bloom pass, which generates bloom texture based on the provided texture
this.bloomPass = new RenderPassBloom(this.device, inputTexture, this.hdrFormat);
}
Expand Down Expand Up @@ -387,9 +435,7 @@ class RenderPassCameraFrame extends RenderPass {

// TAA history buffer is double buffered, assign the current one to the follow up passes.
this.composePass.sceneTexture = sceneTexture;
if (this.options.bloomEnabled && this.bloomPass) {
this.bloomPass.sourceTexture = sceneTexture;
}
this.scenePassHalf?.setSourceTexture(sceneTexture);
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/extras/render-passes/render-pass-downsample.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class RenderPassDownsample extends RenderPassShaderQuad {
this.sourceInvResolutionValue = new Float32Array(2);
}

setSourceTexture(value) {
this._sourceTexture = value;

// change resize source
this.options.resizeSource = value;
}

execute() {
this.sourceTextureId.setValue(this.sourceTexture);

Expand Down
10 changes: 5 additions & 5 deletions src/platform/graphics/render-target.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,13 +312,13 @@ class RenderTarget {
*/
resize(width, height) {

if (this.mipLevel > 0) {
Debug.warn('Only render target rendering to mipLevel 0 can be resized, ignoring.', this);
return;
}

if (this.width !== width || this.height !== height) {

if (this.mipLevel > 0) {
Debug.warn('Only a render target rendering to mipLevel 0 can be resized, ignoring.', this);
return;
}

// release existing
const device = this._device;
this.destroyFrameBuffers();
Expand Down

0 comments on commit 1402d24

Please sign in to comment.