Skip to content
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
3 changes: 2 additions & 1 deletion scripts/esm/camera-frame.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ const DebugType = {
BLOOM: 'bloom',
VIGNETTE: 'vignette',
DOFCOC: 'dofcoc',
DOFBLUR: 'dofblur'
DOFBLUR: 'dofblur',
DEPTH: 'depth'
};

/**
Expand Down
7 changes: 5 additions & 2 deletions src/extras/render-passes/camera-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,9 +453,12 @@ class CameraFrame {
};

/**
* Debug rendering. Set to null to disable.
* Debug rendering, which displays an intermediate value of the frame in place of the composed
* result. This never changes what the frame renders - a mode whose value this frame does not
* generate simply displays nothing: 'depth' renders black when no effect has produced the scene
* depth, and the modes of a disabled effect are ignored. Set to null to disable.
*
* @type {null|'scene'|'ssao'|'bloom'|'vignette'|'dofcoc'|'dofblur'}
* @type {null|'scene'|'ssao'|'bloom'|'vignette'|'dofcoc'|'dofblur'|'depth'}
*/
debug = null;

Expand Down
15 changes: 14 additions & 1 deletion src/extras/render-passes/frame-pass-camera-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,7 @@ class FramePassCameraFrame extends FramePass {
setupComposePass(options) {

// create a compose pass, which combines the results of the scene and other passes
this.composePass = new RenderPassCompose(this.device);
this.composePass = new RenderPassCompose(this.device, this.cameraComponent);
this.composePass.bloomTexture = this.bloomPass?.bloomTexture;
this.composePass.hdrScene = this.hdrFormat !== PIXELFORMAT_RGBA8;
this.composePass.taaEnabled = options.taaEnabled;
Expand Down Expand Up @@ -919,6 +919,19 @@ class FramePassCameraFrame extends FramePass {

super.frameUpdate();

// Whether the depth debug mode has a depth to display. Either producer publishes to the same
// uniform, and both have run by the time the composition does. The mode does not request the
// depth - a debug view never changes what is rendered - so with neither producer it shows black.
const { options, composePass } = this;
const sceneDepthAvailable = options.sceneTextureDepth || options.prepassEnabled;
composePass.sceneDepthAvailable = sceneDepthAvailable;

Debug.call(() => {
if (composePass.debug === 'depth' && !sceneDepthAvailable) {
Debug.warnOnce('CameraFrame.debug is set to \'depth\', but nothing this camera renders produces the scene depth, so the debug view is black. Enable an effect which consumes the depth (the depth of field, the volumetric fog, TAA, or SSAO in combine mode), or request it with CameraFrame.rendering.sceneDepthMap.');
}
});

if (this.sceneDepthTexture) {

// the alias of the scene color is not resized by a pass of its own, as it shares its
Expand Down
63 changes: 60 additions & 3 deletions src/extras/render-passes/render-pass-compose.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { composeChunksGLSL } from '../../scene/shader-lib/glsl/collections/compo
import { composeChunksWGSL } from '../../scene/shader-lib/wgsl/collections/compose-chunks-wgsl.js';

/**
* @import { CameraComponent } from '../../framework/components/camera/component.js';
* @import { GraphicsDevice } from '../../platform/graphics/graphics-device.js';
* @import { Texture } from '../../platform/graphics/texture.js';
*/

Expand Down Expand Up @@ -108,16 +110,25 @@ class RenderPassCompose extends RenderPassShaderQuad {

_debug = null;

_sceneDepthAvailable = false;

// track user-provided custom compose chunks
_customComposeChunks = new Map([
['composeDeclarationsPS', ''],
['composeMainStartPS', ''],
['composeMainEndPS', '']
]);

constructor(graphicsDevice) {
/**
* @param {GraphicsDevice} graphicsDevice - The graphics device.
* @param {CameraComponent} cameraComponent - The camera this composes the frame of. Only the depth
* debug mode needs it, for the depth encoding the camera renders and its clip range.
*/
constructor(graphicsDevice, cameraComponent) {
super(graphicsDevice);

this.cameraComponent = cameraComponent;

// register compose shader chunks
ShaderChunks.get(graphicsDevice, SHADERLANGUAGE_GLSL).add(composeChunksGLSL, false);
ShaderChunks.get(graphicsDevice, SHADERLANGUAGE_WGSL).add(composeChunksWGSL, false);
Expand All @@ -144,6 +155,8 @@ class RenderPassCompose extends RenderPassShaderQuad {
this.colorEnhanceParamsId = scope.resolve('colorEnhanceParams');
this.colorEnhanceMidtonesId = scope.resolve('colorEnhanceMidtones');
this.composeTargetFlipYId = scope.resolve('composeTargetFlipY');
this.cameraParams = new Float32Array(4);
this.cameraParamsId = scope.resolve('camera_params');
}

set debug(value) {
Expand All @@ -157,6 +170,37 @@ class RenderPassCompose extends RenderPassShaderQuad {
return this._debug;
}

/**
* Whether the scene depth this frame renders is available to sample, which the depth debug mode
* displays instead of producing a depth of its own - a debug mode never changes what is rendered.
*
* @type {boolean}
*/
set sceneDepthAvailable(value) {
if (this._sceneDepthAvailable !== value) {
this._sceneDepthAvailable = value;
this._shaderDirty = true;
}
}

get sceneDepthAvailable() {
return this._sceneDepthAvailable;
}

/**
* The debug mode the shader is built for. This is the requested mode, except that a request for the
* depth with no depth to sample renders black instead.
*
* @type {string|null}
* @private
*/
get _debugMode() {
if (this._debug === 'depth' && !this._sceneDepthAvailable) {
return 'depthmissing';
}
return this._debug;
}

set colorLUT(value) {
if (this._colorLUT !== value) {
this._colorLUT = value;
Expand Down Expand Up @@ -365,6 +409,12 @@ class RenderPassCompose extends RenderPassShaderQuad {
const startHash = hashCode(customChunks.get('composeMainStartPS') ?? '');
const endHash = hashCode(customChunks.get('composeMainEndPS') ?? '');

// the depth debug mode samples the scene depth, whose encoding varies with what produced it
const debugMode = this._debugMode;
const depthDefines = new Map();
const depthKey = debugMode === 'depth' ?
ShaderUtils.addScreenDepthChunkDefines(this.cameraComponent.shaderParams, depthDefines) : '';

const key =
`${this.toneMapping}` +
`-${gammaCorrectionName}` +
Expand All @@ -380,7 +430,7 @@ class RenderPassCompose extends RenderPassShaderQuad {
`-${this.fringingEnabled ? 'fringing' : 'nofringing'}` +
`-${this.taaEnabled ? 'taa' : 'notaa'}` +
`-${this.isSharpnessEnabled ? (this._hdrScene ? 'cashdr' : 'cas') : 'nocas'}` +
`-${this._debug ?? ''}` +
`-${debugMode ?? ''}${depthKey}` +
`-decl${declHash}-start${startHash}-end${endHash}`;

if (this._key !== key) {
Expand All @@ -404,7 +454,8 @@ class RenderPassCompose extends RenderPassShaderQuad {
defines.set('CAS', true);
if (this._hdrScene) defines.set('CAS_HDR', true);
}
if (this._debug) defines.set('DEBUG_COMPOSE', this._debug);
if (debugMode) defines.set('DEBUG_COMPOSE', debugMode);
depthDefines.forEach((value, name) => defines.set(name, value));

this.shader = ShaderUtils.createShader(this.device, {
uniqueName: `ComposeShader-${key}`,
Expand All @@ -419,6 +470,12 @@ class RenderPassCompose extends RenderPassShaderQuad {

execute() {

// the clip range the depth debug mode maps to its ramp, and what the depth chunk linearizes
// with. Only set for that mode, so the rest of the composition leaves the camera state alone.
if (this._debugMode === 'depth') {
this.cameraParamsId.setValue(this.cameraComponent.camera.fillShaderParams(this.cameraParams));
}

const sceneTex = this.sceneTexture;
this.sceneTextureId.setValue(sceneTex);
this.sceneTextureInvResValue[0] = 1.0 / sceneTex.width;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export default /* glsl */`
#include "composeCasPS"
#include "composeColorLutPS"

// The depth debug mode displays a depth some other pass in this frame has already produced - the
// debug modes never turn any rendering on, so the mode is switched to depthmissing when nothing
// did, see RenderPassCompose. That is also why this is included here rather than unconditionally:
// declaring the depth sampler in a frame with no depth to bind to it is an error.
#if DEBUG_COMPOSE == depth
#include "screenDepthPS"
#endif

#include "composeDeclarationsPS"

void main() {
Expand Down Expand Up @@ -94,6 +102,13 @@ export default /* glsl */`
result = vec3(dSsao);
#elif defined(VIGNETTE) && DEBUG_COMPOSE == vignette
result = vec3(dVignette);
#elif DEBUG_COMPOSE == depth
// a linear ramp over the camera clip range
float dDepth = getLinearScreenDepth(uv);
result = vec3(clamp((dDepth - camera_params.z) / (camera_params.y - camera_params.z), 0.0, 1.0));
#elif DEBUG_COMPOSE == depthmissing
// the depth was asked for while nothing in this frame produces it
result = vec3(0.0);
#endif
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export default /* wgsl */`
#include "composeCasPS"
#include "composeColorLutPS"

// The depth debug mode displays a depth some other pass in this frame has already produced - the
// debug modes never turn any rendering on, so the mode is switched to depthmissing when nothing
// did, see RenderPassCompose. That is also why this is included here rather than unconditionally:
// declaring the depth sampler in a frame with no depth to bind to it is an error.
#if DEBUG_COMPOSE == depth
#include "screenDepthPS"
#endif

#include "composeDeclarationsPS"

@fragment
Expand Down Expand Up @@ -98,6 +106,13 @@ export default /* wgsl */`
result = vec3f(dSsao);
#elif defined(VIGNETTE) && DEBUG_COMPOSE == vignette
result = vec3f(dVignette);
#elif DEBUG_COMPOSE == depth
// a linear ramp over the camera clip range
let dDepth = getLinearScreenDepth(uv);
result = vec3f(clamp((dDepth - uniform.camera_params.z) / (uniform.camera_params.y - uniform.camera_params.z), 0.0, 1.0));
#elif DEBUG_COMPOSE == depthmissing
// the depth was asked for while nothing in this frame produces it
result = vec3f(0.0);
#endif
#endif

Expand Down