浏览代码

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 <michael.herzog@human-interactive.org>
George Corney 11 月之前
父节点
当前提交
818a27987a

+ 1 - 0
examples/files.json

@@ -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",

二进制
examples/screenshots/webgl_reverse_depth_buffer.jpg


+ 279 - 0
examples/webgl_reverse_depth_buffer.html

@@ -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>

+ 9 - 9
src/renderers/webgl/WebGLState.js

@@ -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' );
 
@@ -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;
 
 			},
 
@@ -145,7 +145,7 @@ function WebGLState( gl, extensions ) {
 
 			setFunc: function ( depthFunc ) {
 
-				if ( reversed ) depthFunc = reversedFuncs[ depthFunc ];
+				if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];
 
 				if ( currentDepthFunc !== depthFunc ) {
 
@@ -213,7 +213,7 @@ function WebGLState( gl, extensions ) {
 
 				if ( currentDepthClear !== depth ) {
 
-					if ( reversed ) {
+					if ( currentReversed ) {
 
 						depth = 1 - depth;
 
@@ -233,7 +233,7 @@ function WebGLState( gl, extensions ) {
 				currentDepthMask = null;
 				currentDepthFunc = null;
 				currentDepthClear = null;
-				reversed = false;
+				currentReversed = false;
 
 			}
 

+ 3 - 0
test/e2e/puppeteer.js

@@ -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',

粤ICP备19079148号