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
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@
"webgl_multiple_rendertargets",
"webgl_multisampled_renderbuffers",
"webgl_rendertarget_texture2darray",
"webgl_reverse_depth_buffer",
"webgl_shadowmap_csm",
"webgl_shadowmap_pcss",
"webgl_shadowmap_progressive",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
279 changes: 279 additions & 0 deletions examples/webgl_reverse_depth_buffer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - reverse depth buffer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
margin: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}

a {
color: #ff0;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

#info {
position: absolute;
top: 0px;
width: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
z-index: 1; /* TODO Solve this in HTML */
}

#container {
display: flex;
}

#container_normal,
#container_logarithmic,
#container_reverse {
width: 33%;
display: inline-block;
position: relative;
}

.container_label {
position: absolute;
bottom: 1em;
width: 100%;
color: white;
z-index: 10;
display: block;
text-align: center;
}

#depth-warning {
position: absolute;
top: 40px;
width: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
color: #ff5555;
font-weight: bold;
z-index: 2;
display: none;
}
</style>
</head>
<body>
<div id="container">
<div id="container_normal"><h2 class="container_label">normal z-buffer</h2></div>
<div id="container_logarithmic"><h2 class="container_label">logarithmic z-buffer</h2></div>
<div id="container_reverse"><h2 class="container_label">reverse z-buffer</h2></div>
</div>

<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - reverse depth buffer<br/>
</div>

<div id="depth-warning">
Warning: Your browser's WebGL provides less than 24-bit depth buffer precision. This example may not display correctly.
</div>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>

<script type="module">
// https://webgpu.github.io/webgpu-samples/?sample=reversedZ
import * as THREE from 'three';

import Stats from 'three/addons/libs/stats.module.js';

let stats, camera, scene, normalRenderer, logarithmicRenderer, reverseRenderer;
const meshes = [];

init();
animate();

function init() {

const container = document.getElementById( 'container' );

stats = new Stats();
container.appendChild( stats.dom );

camera = new THREE.PerspectiveCamera( 72, 0.33 * window.innerWidth / window.innerHeight, 5, 9999 );
camera.position.z = 12;

scene = new THREE.Scene();

const xCount = 1;
const yCount = 5;
const numInstances = xCount * yCount;

const d = 0.0001; // half distance between two planes
const o = 0.5; // half x offset to shift planes so they are only partially overlaping

const positions = new Float32Array( [
- 1 - o, - 1, d,
1 - o, - 1, d,
- 1 - o, 1, d,
1 - o, - 1, d,
1 - o, 1, d,
- 1 - o, 1, d,

- 1 + o, - 1, - d,
1 + o, - 1, - d,
- 1 + o, 1, - d,
1 + o, - 1, - d,
1 + o, 1, - d,
- 1 + o, 1, - d,
] );

const colors = new Float32Array( [
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,
1, 0, 0,

0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
0, 1, 0,
] );

const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

const material = new THREE.MeshBasicMaterial( { vertexColors: true } );

for ( let i = 0; i < numInstances; i ++ ) {

const mesh = new THREE.Mesh( geometry, material );
meshes.push( mesh );
scene.add( mesh );

}

let i = 0;
for ( let x = 0; x < xCount; x ++ ) {

for ( let y = 0; y < yCount; y ++ ) {

const z = - 800 * i;
const s = 1 + 50 * i;

const mesh = meshes[ i ];
mesh.position.set(
x - xCount / 2 + 0.5,
( 4.0 - 0.2 * z ) * ( y - yCount / 2 + 1.0 ),
z
);
mesh.scale.setScalar( s );

i ++;

}

}

const normalContainer = document.getElementById( 'container_normal' );
normalRenderer = new THREE.WebGLRenderer();
normalRenderer.setPixelRatio( window.devicePixelRatio );
normalRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
normalRenderer.domElement.style.position = 'relative';
normalContainer.appendChild( normalRenderer.domElement );

const logarithmicContainer = document.getElementById( 'container_logarithmic' );
logarithmicRenderer = new THREE.WebGLRenderer( { logarithmicDepthBuffer: true } );
logarithmicRenderer.setPixelRatio( window.devicePixelRatio );
logarithmicRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
logarithmicRenderer.domElement.style.position = 'relative';
logarithmicContainer.appendChild( logarithmicRenderer.domElement );

const reverseContainer = document.getElementById( 'container_reverse' );
reverseRenderer = new THREE.WebGLRenderer( { reverseDepthBuffer: true } );
reverseRenderer.setPixelRatio( window.devicePixelRatio );
reverseRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
reverseRenderer.domElement.style.position = 'relative';
reverseContainer.appendChild( reverseRenderer.domElement );

// Check depth buffer precision
const gl = normalRenderer.getContext();

const depthBits = gl.getParameter( gl.DEPTH_BITS );

if ( depthBits < 24 ) {

document.getElementById( 'depth-warning' ).style.display = 'block';

}

window.addEventListener( 'resize', onWindowResize );

}

function animate() {

requestAnimationFrame( animate );

const now = performance.now() / 1000;

for ( let i = 0; i < meshes.length; i ++ ) {

const angle = THREE.MathUtils.degToRad( 30 );
const axis = new THREE.Vector3( Math.sin( now ), Math.cos( now ), 0 );
meshes[ i ].quaternion.setFromAxisAngle( axis, angle );

}

render();

}

function render() {

normalRenderer.render( scene, camera );
logarithmicRenderer.render( scene, camera );
reverseRenderer.render( scene, camera );

stats.update();

}

function onWindowResize() {

normalRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
logarithmicRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
reverseRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );

camera.aspect = 0.33 * window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

}
</script>

</body>
</html>
18 changes: 9 additions & 9 deletions src/renderers/webgl/WebGLState.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ function WebGLState( gl, extensions ) {
function DepthBuffer() {

let locked = false;
let reversed = false;

let currentReversed = false;
let currentDepthMask = null;
let currentDepthFunc = null;
let currentDepthClear = null;

return {

setReversed: function ( value ) {
setReversed: function ( reversed ) {

if ( reversed !== value ) {
if ( currentReversed !== reversed ) {

const ext = extensions.get( 'EXT_clip_control' );

Expand All @@ -102,19 +102,19 @@ function WebGLState( gl, extensions ) {

}

currentReversed = reversed;

const oldDepth = currentDepthClear;
currentDepthClear = null;
this.setClear( oldDepth );

}

reversed = value;

},

getReversed: function () {

return reversed;
return currentReversed;

},

Expand Down Expand Up @@ -145,7 +145,7 @@ function WebGLState( gl, extensions ) {

setFunc: function ( depthFunc ) {

if ( reversed ) depthFunc = reversedFuncs[ depthFunc ];
if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];

if ( currentDepthFunc !== depthFunc ) {

Expand Down Expand Up @@ -213,7 +213,7 @@ function WebGLState( gl, extensions ) {

if ( currentDepthClear !== depth ) {

if ( reversed ) {
if ( currentReversed ) {

depth = 1 - depth;

Expand All @@ -233,7 +233,7 @@ function WebGLState( gl, extensions ) {
currentDepthMask = null;
currentDepthFunc = null;
currentDepthClear = null;
reversed = false;
currentReversed = false;

}

Expand Down
3 changes: 3 additions & 0 deletions test/e2e/puppeteer.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ const exceptionList = [
'webgl_test_wide_gamut',
'webgl_volume_instancing',

// Intentional z-fighting in this demo makes it non-deterministic
'webgl_reverse_depth_buffer',

// TODO: implement determinism for setTimeout and setInterval
// could it fix some examples from above?
'physics_rapier_instancing',
Expand Down