Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to render passes - generate scene half sized texture #7175

Merged
merged 2 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading