From 7693f274403aa38da63b33cb4c2508d6565300fd Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Thu, 19 Sep 2024 07:44:59 -0500 Subject: [PATCH 1/2] WebGLRenderer: add reverse-z via EXT_clip_control --- src/renderers/WebGLRenderer.js | 75 +++++++++++++++++++++++- src/renderers/webgl/WebGLCapabilities.js | 9 +++ src/renderers/webgl/WebGLState.js | 21 +++++++ 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 1cf6a6a565b4e7..a51a9e77e15635 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -57,6 +57,58 @@ import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js'; import { createCanvasElement, probeAsync, warnOnce } from '../utils.js'; import { ColorManagement } from '../math/ColorManagement.js'; +function toReversedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + const isPerspectiveMatrix = m[ 11 ] === - 1; + + // Convert [-1, 1] to [0, 1] projection matrix + m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ]; + m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ]; + m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ]; + m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ]; + + // Reverse [0, 1] projection matrix + if ( isPerspectiveMatrix ) { + + m[ 10 ] = - m[ 10 ] - 1; + m[ 14 ] = - m[ 14 ]; + + } else { + + m[ 10 ] = - m[ 10 ]; + m[ 14 ] = - m[ 14 ] + 1; + + } + +} + +function toForwardProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + const isPerspectiveMatrix = m[ 11 ] === - 1; + + // Undo reversed [0, 1] projection matrix + if ( isPerspectiveMatrix ) { + + m[ 10 ] = - ( m[ 10 ] + 1 ); + m[ 14 ] = - m[ 14 ]; + + } else { + + m[ 10 ] = - m[ 10 ]; + m[ 14 ] = - ( m[ 14 ] - 1 ); + + } + + // Remap from [0, 1] back to [-1, 1] + m[ 2 ] = 2 * m[ 2 ] - m[ 3 ]; + m[ 6 ] = 2 * m[ 6 ] - m[ 7 ]; + m[ 10 ] = 2 * m[ 10 ] - m[ 11 ]; + m[ 14 ] = 2 * m[ 14 ] - m[ 15 ]; + +} + class WebGLRenderer { constructor( parameters = {} ) { @@ -291,6 +343,8 @@ class WebGLRenderer { state = new WebGLState( _gl ); + if ( capabilities.reverseDepthBuffer ) state.buffers.depth.setReversed( true ); + info = new WebGLInfo( _gl ); properties = new WebGLProperties(); textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); @@ -590,7 +644,13 @@ class WebGLRenderer { } - if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( depth ) { + + bits |= _gl.DEPTH_BUFFER_BIT; + _gl.clearDepth( this.capabilities.reverseDepthBuffer ? 0 : 1 ); + + } + if ( stencil ) { bits |= _gl.STENCIL_BUFFER_BIT; @@ -1971,7 +2031,20 @@ class WebGLRenderer { // common camera uniforms + if ( capabilities.reverseDepthBuffer ) { + + toReversedProjectionMatrix( camera.projectionMatrix ); + + } + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + + if ( capabilities.reverseDepthBuffer ) { + + toForwardProjectionMatrix( camera.projectionMatrix ); + + } + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); const uCamPos = p_uniforms.map.cameraPosition; diff --git a/src/renderers/webgl/WebGLCapabilities.js b/src/renderers/webgl/WebGLCapabilities.js index 2289d6c38f13ba..a610a9cbbe1ea7 100644 --- a/src/renderers/webgl/WebGLCapabilities.js +++ b/src/renderers/webgl/WebGLCapabilities.js @@ -92,6 +92,14 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { } const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; + const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has( 'EXT_clip_control' ); + + if ( reverseDepthBuffer === true ) { + + const ext = extensions.get( 'EXT_clip_control' ); + ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT ); + + } const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); @@ -119,6 +127,7 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) { precision: precision, logarithmicDepthBuffer: logarithmicDepthBuffer, + reverseDepthBuffer: reverseDepthBuffer, maxTextures: maxTextures, maxVertexTextures: maxVertexTextures, diff --git a/src/renderers/webgl/WebGLState.js b/src/renderers/webgl/WebGLState.js index 9f21f45001097b..3d380b1ce69f99 100644 --- a/src/renderers/webgl/WebGLState.js +++ b/src/renderers/webgl/WebGLState.js @@ -2,6 +2,18 @@ import { NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDe import { Color } from '../../math/Color.js'; import { Vector4 } from '../../math/Vector4.js'; +const reversedFuncs = { + [ NeverDepth ]: AlwaysDepth, + [ LessDepth ]: GreaterDepth, + [ EqualDepth ]: NotEqualDepth, + [ LessEqualDepth ]: GreaterEqualDepth, + + [ AlwaysDepth ]: NeverDepth, + [ GreaterDepth ]: LessDepth, + [ NotEqualDepth ]: EqualDepth, + [ GreaterEqualDepth ]: LessEqualDepth, +}; + function WebGLState( gl ) { function ColorBuffer() { @@ -66,6 +78,7 @@ function WebGLState( gl ) { function DepthBuffer() { let locked = false; + let reversed = false; let currentDepthMask = null; let currentDepthFunc = null; @@ -73,6 +86,12 @@ function WebGLState( gl ) { return { + setReversed: function ( value ) { + + reversed = value; + + }, + setTest: function ( depthTest ) { if ( depthTest ) { @@ -100,6 +119,8 @@ function WebGLState( gl ) { setFunc: function ( depthFunc ) { + if ( reversed ) depthFunc = reversedFuncs[ depthFunc ]; + if ( currentDepthFunc !== depthFunc ) { switch ( depthFunc ) { From c67c4af631cffc9bf6cf27f941f1f40385afff28 Mon Sep 17 00:00:00 2001 From: Cody Bennett Date: Thu, 19 Sep 2024 18:58:05 -0500 Subject: [PATCH 2/2] WebGLRenderer: move conversion methods to utils --- src/renderers/WebGLRenderer.js | 66 +++++----------------------------- src/utils.js | 34 +++++++++++++++++- 2 files changed, 41 insertions(+), 59 deletions(-) diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index a51a9e77e15635..ba5732f7d2576e 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -54,61 +54,9 @@ import { WebGLUtils } from './webgl/WebGLUtils.js'; import { WebXRManager } from './webxr/WebXRManager.js'; import { WebGLMaterials } from './webgl/WebGLMaterials.js'; import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js'; -import { createCanvasElement, probeAsync, warnOnce } from '../utils.js'; +import { createCanvasElement, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix, warnOnce } from '../utils.js'; import { ColorManagement } from '../math/ColorManagement.js'; -function toReversedProjectionMatrix( projectionMatrix ) { - - const m = projectionMatrix.elements; - const isPerspectiveMatrix = m[ 11 ] === - 1; - - // Convert [-1, 1] to [0, 1] projection matrix - m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ]; - m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ]; - m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ]; - m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ]; - - // Reverse [0, 1] projection matrix - if ( isPerspectiveMatrix ) { - - m[ 10 ] = - m[ 10 ] - 1; - m[ 14 ] = - m[ 14 ]; - - } else { - - m[ 10 ] = - m[ 10 ]; - m[ 14 ] = - m[ 14 ] + 1; - - } - -} - -function toForwardProjectionMatrix( projectionMatrix ) { - - const m = projectionMatrix.elements; - const isPerspectiveMatrix = m[ 11 ] === - 1; - - // Undo reversed [0, 1] projection matrix - if ( isPerspectiveMatrix ) { - - m[ 10 ] = - ( m[ 10 ] + 1 ); - m[ 14 ] = - m[ 14 ]; - - } else { - - m[ 10 ] = - m[ 10 ]; - m[ 14 ] = - ( m[ 14 ] - 1 ); - - } - - // Remap from [0, 1] back to [-1, 1] - m[ 2 ] = 2 * m[ 2 ] - m[ 3 ]; - m[ 6 ] = 2 * m[ 6 ] - m[ 7 ]; - m[ 10 ] = 2 * m[ 10 ] - m[ 11 ]; - m[ 14 ] = 2 * m[ 14 ] - m[ 15 ]; - -} - class WebGLRenderer { constructor( parameters = {} ) { @@ -248,6 +196,7 @@ class WebGLRenderer { // camera matrices cache + const _currentProjectionMatrix = new Matrix4(); const _projScreenMatrix = new Matrix4(); const _vector3 = new Vector3(); @@ -2033,15 +1982,16 @@ class WebGLRenderer { if ( capabilities.reverseDepthBuffer ) { - toReversedProjectionMatrix( camera.projectionMatrix ); + _currentProjectionMatrix.copy( camera.projectionMatrix ); - } + toNormalizedProjectionMatrix( _currentProjectionMatrix ); + toReversedProjectionMatrix( _currentProjectionMatrix ); - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix ); - if ( capabilities.reverseDepthBuffer ) { + } else { - toForwardProjectionMatrix( camera.projectionMatrix ); + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); } diff --git a/src/utils.js b/src/utils.js index 3c333e5085f402..6700462399514c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -117,4 +117,36 @@ function probeAsync( gl, sync, interval ) { } -export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, warnOnce, probeAsync }; +function toNormalizedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + + // Convert [-1, 1] to [0, 1] projection matrix + m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ]; + m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ]; + m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ]; + m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ]; + +} + +function toReversedProjectionMatrix( projectionMatrix ) { + + const m = projectionMatrix.elements; + const isPerspectiveMatrix = m[ 11 ] === - 1; + + // Reverse [0, 1] projection matrix + if ( isPerspectiveMatrix ) { + + m[ 10 ] = - m[ 10 ] - 1; + m[ 14 ] = - m[ 14 ]; + + } else { + + m[ 10 ] = - m[ 10 ]; + m[ 14 ] = - m[ 14 ] + 1; + + } + +} + +export { arrayMin, arrayMax, arrayNeedsUint32, getTypedArray, createElementNS, createCanvasElement, warnOnce, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix };