diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 1cf6a6a565b4e7..ba5732f7d2576e 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -54,7 +54,7 @@ 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'; class WebGLRenderer { @@ -196,6 +196,7 @@ class WebGLRenderer { // camera matrices cache + const _currentProjectionMatrix = new Matrix4(); const _projScreenMatrix = new Matrix4(); const _vector3 = new Vector3(); @@ -291,6 +292,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 +593,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 +1980,21 @@ class WebGLRenderer { // common camera uniforms - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( capabilities.reverseDepthBuffer ) { + + _currentProjectionMatrix.copy( camera.projectionMatrix ); + + toNormalizedProjectionMatrix( _currentProjectionMatrix ); + toReversedProjectionMatrix( _currentProjectionMatrix ); + + p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix ); + + } else { + + p_uniforms.setValue( _gl, 'projectionMatrix', 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 ) { 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 };