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 =...