Skip to content

Commit 818a279

Browse files
haxiomicMugen87
andauthored
Fix setReversed() so reverseDepthBuffer: true works (#30809)
* Fix setReversed() so reverseDepthBuffer: true works * Use the same pattern as other state functions * Whitespace change to rerun e2e * Whitespace change to rerun e2e * Add @CodyJasonBennett's example for reverse depth buffer * Add e2e exception for webgl_reverse_depth_buffer (z-fighting) * Update webgl_reverse_depth_buffer.html Clean up title. * Update webgl_reverse_depth_buffer.html * Remove intermediate render texture * Add < 24 bit depth warning * Clarity * Case * Use setFromAxisAngle --------- Co-authored-by: Michael Herzog <[email protected]>
1 parent 3285194 commit 818a279

File tree

5 files changed

+292
-9
lines changed

5 files changed

+292
-9
lines changed

examples/files.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@
276276
"webgl_multiple_rendertargets",
277277
"webgl_multisampled_renderbuffers",
278278
"webgl_rendertarget_texture2darray",
279+
"webgl_reverse_depth_buffer",
279280
"webgl_shadowmap_csm",
280281
"webgl_shadowmap_pcss",
281282
"webgl_shadowmap_progressive",
37.2 KB
Loading
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>three.js webgl - reverse depth buffer</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7+
<link type="text/css" rel="stylesheet" href="main.css">
8+
<style>
9+
body {
10+
margin: 0;
11+
background-color: #000;
12+
color: #fff;
13+
font-family: Monospace;
14+
font-size: 13px;
15+
line-height: 24px;
16+
overscroll-behavior: none;
17+
}
18+
19+
a {
20+
color: #ff0;
21+
text-decoration: none;
22+
}
23+
24+
a:hover {
25+
text-decoration: underline;
26+
}
27+
28+
#info {
29+
position: absolute;
30+
top: 0px;
31+
width: 100%;
32+
padding: 10px;
33+
box-sizing: border-box;
34+
text-align: center;
35+
-moz-user-select: none;
36+
-webkit-user-select: none;
37+
-ms-user-select: none;
38+
user-select: none;
39+
pointer-events: none;
40+
z-index: 1; /* TODO Solve this in HTML */
41+
}
42+
43+
#container {
44+
display: flex;
45+
}
46+
47+
#container_normal,
48+
#container_logarithmic,
49+
#container_reverse {
50+
width: 33%;
51+
display: inline-block;
52+
position: relative;
53+
}
54+
55+
.container_label {
56+
position: absolute;
57+
bottom: 1em;
58+
width: 100%;
59+
color: white;
60+
z-index: 10;
61+
display: block;
62+
text-align: center;
63+
}
64+
65+
#depth-warning {
66+
position: absolute;
67+
top: 40px;
68+
width: 100%;
69+
padding: 10px;
70+
box-sizing: border-box;
71+
text-align: center;
72+
color: #ff5555;
73+
font-weight: bold;
74+
z-index: 2;
75+
display: none;
76+
}
77+
</style>
78+
</head>
79+
<body>
80+
<div id="container">
81+
<div id="container_normal"><h2 class="container_label">normal z-buffer</h2></div>
82+
<div id="container_logarithmic"><h2 class="container_label">logarithmic z-buffer</h2></div>
83+
<div id="container_reverse"><h2 class="container_label">reverse z-buffer</h2></div>
84+
</div>
85+
86+
<div id="info">
87+
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - reverse depth buffer<br/>
88+
</div>
89+
90+
<div id="depth-warning">
91+
Warning: Your browser's WebGL provides less than 24-bit depth buffer precision. This example may not display correctly.
92+
</div>
93+
94+
<script type="importmap">
95+
{
96+
"imports": {
97+
"three": "../build/three.module.js",
98+
"three/addons/": "./jsm/"
99+
}
100+
}
101+
</script>
102+
103+
<script type="module">
104+
// https://webgpu.github.io/webgpu-samples/?sample=reversedZ
105+
import * as THREE from 'three';
106+
107+
import Stats from 'three/addons/libs/stats.module.js';
108+
109+
let stats, camera, scene, normalRenderer, logarithmicRenderer, reverseRenderer;
110+
const meshes = [];
111+
112+
init();
113+
animate();
114+
115+
function init() {
116+
117+
const container = document.getElementById( 'container' );
118+
119+
stats = new Stats();
120+
container.appendChild( stats.dom );
121+
122+
camera = new THREE.PerspectiveCamera( 72, 0.33 * window.innerWidth / window.innerHeight, 5, 9999 );
123+
camera.position.z = 12;
124+
125+
scene = new THREE.Scene();
126+
127+
const xCount = 1;
128+
const yCount = 5;
129+
const numInstances = xCount * yCount;
130+
131+
const d = 0.0001; // half distance between two planes
132+
const o = 0.5; // half x offset to shift planes so they are only partially overlaping
133+
134+
const positions = new Float32Array( [
135+
- 1 - o, - 1, d,
136+
1 - o, - 1, d,
137+
- 1 - o, 1, d,
138+
1 - o, - 1, d,
139+
1 - o, 1, d,
140+
- 1 - o, 1, d,
141+
142+
- 1 + o, - 1, - d,
143+
1 + o, - 1, - d,
144+
- 1 + o, 1, - d,
145+
1 + o, - 1, - d,
146+
1 + o, 1, - d,
147+
- 1 + o, 1, - d,
148+
] );
149+
150+
const colors = new Float32Array( [
151+
1, 0, 0,
152+
1, 0, 0,
153+
1, 0, 0,
154+
1, 0, 0,
155+
1, 0, 0,
156+
1, 0, 0,
157+
158+
0, 1, 0,
159+
0, 1, 0,
160+
0, 1, 0,
161+
0, 1, 0,
162+
0, 1, 0,
163+
0, 1, 0,
164+
] );
165+
166+
const geometry = new THREE.BufferGeometry();
167+
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
168+
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
169+
170+
const material = new THREE.MeshBasicMaterial( { vertexColors: true } );
171+
172+
for ( let i = 0; i < numInstances; i ++ ) {
173+
174+
const mesh = new THREE.Mesh( geometry, material );
175+
meshes.push( mesh );
176+
scene.add( mesh );
177+
178+
}
179+
180+
let i = 0;
181+
for ( let x = 0; x < xCount; x ++ ) {
182+
183+
for ( let y = 0; y < yCount; y ++ ) {
184+
185+
const z = - 800 * i;
186+
const s = 1 + 50 * i;
187+
188+
const mesh = meshes[ i ];
189+
mesh.position.set(
190+
x - xCount / 2 + 0.5,
191+
( 4.0 - 0.2 * z ) * ( y - yCount / 2 + 1.0 ),
192+
z
193+
);
194+
mesh.scale.setScalar( s );
195+
196+
i ++;
197+
198+
}
199+
200+
}
201+
202+
const normalContainer = document.getElementById( 'container_normal' );
203+
normalRenderer = new THREE.WebGLRenderer();
204+
normalRenderer.setPixelRatio( window.devicePixelRatio );
205+
normalRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
206+
normalRenderer.domElement.style.position = 'relative';
207+
normalContainer.appendChild( normalRenderer.domElement );
208+
209+
const logarithmicContainer = document.getElementById( 'container_logarithmic' );
210+
logarithmicRenderer = new THREE.WebGLRenderer( { logarithmicDepthBuffer: true } );
211+
logarithmicRenderer.setPixelRatio( window.devicePixelRatio );
212+
logarithmicRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
213+
logarithmicRenderer.domElement.style.position = 'relative';
214+
logarithmicContainer.appendChild( logarithmicRenderer.domElement );
215+
216+
const reverseContainer = document.getElementById( 'container_reverse' );
217+
reverseRenderer = new THREE.WebGLRenderer( { reverseDepthBuffer: true } );
218+
reverseRenderer.setPixelRatio( window.devicePixelRatio );
219+
reverseRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
220+
reverseRenderer.domElement.style.position = 'relative';
221+
reverseContainer.appendChild( reverseRenderer.domElement );
222+
223+
// Check depth buffer precision
224+
const gl = normalRenderer.getContext();
225+
226+
const depthBits = gl.getParameter( gl.DEPTH_BITS );
227+
228+
if ( depthBits < 24 ) {
229+
230+
document.getElementById( 'depth-warning' ).style.display = 'block';
231+
232+
}
233+
234+
window.addEventListener( 'resize', onWindowResize );
235+
236+
}
237+
238+
function animate() {
239+
240+
requestAnimationFrame( animate );
241+
242+
const now = performance.now() / 1000;
243+
244+
for ( let i = 0; i < meshes.length; i ++ ) {
245+
246+
const angle = THREE.MathUtils.degToRad( 30 );
247+
const axis = new THREE.Vector3( Math.sin( now ), Math.cos( now ), 0 );
248+
meshes[ i ].quaternion.setFromAxisAngle( axis, angle );
249+
250+
}
251+
252+
render();
253+
254+
}
255+
256+
function render() {
257+
258+
normalRenderer.render( scene, camera );
259+
logarithmicRenderer.render( scene, camera );
260+
reverseRenderer.render( scene, camera );
261+
262+
stats.update();
263+
264+
}
265+
266+
function onWindowResize() {
267+
268+
normalRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
269+
logarithmicRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
270+
reverseRenderer.setSize( 0.33 * window.innerWidth, window.innerHeight );
271+
272+
camera.aspect = 0.33 * window.innerWidth / window.innerHeight;
273+
camera.updateProjectionMatrix();
274+
275+
}
276+
</script>
277+
278+
</body>
279+
</html>

src/renderers/webgl/WebGLState.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,17 @@ function WebGLState( gl, extensions ) {
7878
function DepthBuffer() {
7979

8080
let locked = false;
81-
let reversed = false;
8281

82+
let currentReversed = false;
8383
let currentDepthMask = null;
8484
let currentDepthFunc = null;
8585
let currentDepthClear = null;
8686

8787
return {
8888

89-
setReversed: function ( value ) {
89+
setReversed: function ( reversed ) {
9090

91-
if ( reversed !== value ) {
91+
if ( currentReversed !== reversed ) {
9292

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

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

103103
}
104104

105+
currentReversed = reversed;
106+
105107
const oldDepth = currentDepthClear;
106108
currentDepthClear = null;
107109
this.setClear( oldDepth );
108110

109111
}
110112

111-
reversed = value;
112-
113113
},
114114

115115
getReversed: function () {
116116

117-
return reversed;
117+
return currentReversed;
118118

119119
},
120120

@@ -145,7 +145,7 @@ function WebGLState( gl, extensions ) {
145145

146146
setFunc: function ( depthFunc ) {
147147

148-
if ( reversed ) depthFunc = reversedFuncs[ depthFunc ];
148+
if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];
149149

150150
if ( currentDepthFunc !== depthFunc ) {
151151

@@ -213,7 +213,7 @@ function WebGLState( gl, extensions ) {
213213

214214
if ( currentDepthClear !== depth ) {
215215

216-
if ( reversed ) {
216+
if ( currentReversed ) {
217217

218218
depth = 1 - depth;
219219

@@ -233,7 +233,7 @@ function WebGLState( gl, extensions ) {
233233
currentDepthMask = null;
234234
currentDepthFunc = null;
235235
currentDepthClear = null;
236-
reversed = false;
236+
currentReversed = false;
237237

238238
}
239239

test/e2e/puppeteer.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ const exceptionList = [
107107
'webgl_test_wide_gamut',
108108
'webgl_volume_instancing',
109109

110+
// Intentional z-fighting in this demo makes it non-deterministic
111+
'webgl_reverse_depth_buffer',
112+
110113
// TODO: implement determinism for setTimeout and setInterval
111114
// could it fix some examples from above?
112115
'physics_rapier_instancing',

0 commit comments

Comments
 (0)