THREE.js - Reading depth buffer normal vs logarithmic

by PhilQ

HTML

<div class="canvas" id="normal"></div>
<div class="canvas" id="logarithmic"></div>

<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

<script type="x-shader/x-vertex" id="vertexShader">
	#include <common>

#ifdef USE_LOGDEPTHBUF
	uniform float logDepthBufFC;
#endif

	varying vec2 vUv;

	void main() {
		vUv = uv;
		gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

#ifdef USE_LOGDEPTHBUF

	if ( isPerspectiveMatrix( projectionMatrix ) ) {
			gl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;
			gl_Position.z *= gl_Position.w;
		}

#endif

	}
</script>

<script type="x-shader/x-fragment" id="fragmentShader">
  #include <common>
	#include <packing>

  varying vec2 vUv;
  uniform sampler2D tDiffuse;
  uniform sampler2D tDepth;
  uniform float cameraNear;
  uniform float cameraFar;

	// See: https://stackoverflow.com/a/40479068/2142071
	float linearizeDepth(in float depth) {
		float a = cameraFar / (cameraFar - cameraNear);
		float b = cameraFar * cameraNear / (cameraNear - cameraFar);
		return a + b / depth;
	}

	float readDepth( sampler2D depthSampler, vec2 coord ) {
			float depthValue = texture2D( depthSampler, coord ).x;

#ifdef USE_LOGDEPTHBUF

			float invClipZ = linearizeDepth(exp2(depthValue * log2(cameraFar + 1.0)) - 1.0);
			float viewZ = perspectiveDepthToViewZ( invClipZ, cameraNear, cameraFar );
			return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );

#else

      float invClipZ = depthValue;
      float viewZ = perspectiveDepthToViewZ( invClipZ, cameraNear, cameraFar );
			return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );

#endif

}

  void main() {
    float depth = readDepth( tDepth, vUv );
    gl_FragColor.rgb = 1.0 - vec3( depth );
    gl_FragColor.a = 1.0;
  }
</script>

CSS

*, ::before, ::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
.canvas {
	width: 50%;
	display: inline-block;
	float: left;
	position: relative;
}

.canvas::after {
	position: absolute;
	top: 10px;
	display: inline-block;
	font-weight: bold;
	font-family: sans-serif;
	font-size: 16px;
	color: #000;
	background: rgba(255,255,255, 0.8);
	border-radius: 6px;
	padding: 10px 12px;
}

.canvas:nth-of-type(1)::after {
	right: 10px;
	content: 'Normal depth';
}
.canvas:nth-of-type(2)::after {
	left: 10px;
	content: 'Logarithmic depth';
}

JavaScript

let camera, scene, renderer, renderer2, controls, stats;
let target, target2;
let postScene, postCamera, postMaterial;
let supportsExtension = true;

let width = window.innerWidth / 2;
let height = window.innerHeight;

const params = {
	format: THREE.DepthFormat,
	//type: THREE.UnsignedShortType
	type: THREE.UnsignedInt248Type
};

const formats = { DepthFormat: THREE.DepthFormat, DepthStencilFormat: THREE.DepthStencilFormat };
const types = { UnsignedShortType: THREE.UnsignedShortType, UnsignedIntType: THREE.UnsignedIntType, UnsignedInt248Type: THREE.UnsignedInt248Type };

init();
animate();

function init() {

	renderer = new THREE.WebGLRenderer( {
		antialias: true,
		logarithmicDepthBuffer: false,
		// alpha: true,
	} );
	renderer2 = new THREE.WebGLRenderer( {
		antialias: true,
		logarithmicDepthBuffer: true,
		// alpha: true,
	} );

	if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'WEBGL_depth_texture' ) === false ) {

		supportsExtension = false;
		return;

	}

	renderer.setPixelRatio( window.devicePixelRatio );
	renderer.setSize( width, height );
	document.getElementById('normal').appendChild( renderer.domElement );

	renderer2.setPixelRatio( window.devicePixelRatio );
	renderer2.setSize( width, height );
	document.getElementById('logarithmic').appendChild( renderer2.domElement );

	//

	camera = new THREE.PerspectiveCamera( 70, width / height, 0.01, 50 );
	camera.position.z = 4;

	controls = new THREE.OrbitControls( camera, renderer.domElement );
	controls.enableDamping = true;

	// Create a render target with depth texture
	setupRenderTarget();

	// Our scene
	setupScene();

	// Setup post-processing step
	setupPost();

	onWindowResize();
	window.addEventListener( 'resize', onWindowResize );

}

function setupRenderTarget() {

	if ( target ) target.dispose();

	const format = parseFloat( params.format );
	const type = parseFloat( params.type );

	target = new THREE.WebGLRenderTarget( width, height );
	target.texture.minFilter =...