You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.9 KiB
HTML
297 lines
7.9 KiB
HTML
2 months ago
|
<!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;
|
||
|
}
|
||
|
|
||
|
#info_note {
|
||
|
position: absolute;
|
||
|
top: 24px;
|
||
|
width: 100%;
|
||
|
padding: 10px;
|
||
|
box-sizing: border-box;
|
||
|
text-align: center;
|
||
|
color: rgba(255, 255, 255, 0.8);
|
||
|
z-index: 2;
|
||
|
}
|
||
|
</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="info_note">
|
||
|
Note: For best results, a floating-point depth buffer should be used with post-processing. See <a href="https://developer.nvidia.com/blog/visualizing-depth-precision" target="_blank" rel="noopener">Visualizing Depth Precision</a>.
|
||
|
</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';
|
||
|
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
|
||
|
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
|
||
|
import { OutputPass } from 'three/addons/postprocessing/OutputPass.js';
|
||
|
|
||
|
let stats, camera, scene;
|
||
|
let normalRenderer, logarithmicRenderer, reverseRenderer;
|
||
|
let normalComposer, logarithmicComposer, reverseComposer;
|
||
|
const meshes = [];
|
||
|
|
||
|
const renderTarget = new THREE.WebGLRenderTarget();
|
||
|
renderTarget.depthTexture = new THREE.DepthTexture();
|
||
|
renderTarget.depthTexture.type = THREE.FloatType;
|
||
|
|
||
|
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 overlapping
|
||
|
|
||
|
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 );
|
||
|
|
||
|
normalComposer = new EffectComposer( normalRenderer, renderTarget );
|
||
|
normalComposer.addPass( new RenderPass( scene, camera ) );
|
||
|
normalComposer.addPass( new OutputPass() );
|
||
|
|
||
|
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 );
|
||
|
|
||
|
logarithmicComposer = new EffectComposer( logarithmicRenderer, renderTarget );
|
||
|
logarithmicComposer.addPass( new RenderPass( scene, camera ) );
|
||
|
logarithmicComposer.addPass( new OutputPass() );
|
||
|
|
||
|
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 );
|
||
|
|
||
|
reverseComposer = new EffectComposer( reverseRenderer, renderTarget );
|
||
|
reverseComposer.addPass( new RenderPass( scene, camera ) );
|
||
|
reverseComposer.addPass( new OutputPass() );
|
||
|
|
||
|
window.addEventListener( 'resize', onWindowResize );
|
||
|
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() {
|
||
|
|
||
|
normalComposer.render();
|
||
|
logarithmicComposer.render();
|
||
|
reverseComposer.render();
|
||
|
|
||
|
stats.update();
|
||
|
|
||
|
}
|
||
|
|
||
|
function onWindowResize() {
|
||
|
|
||
|
const width = 0.33 * window.innerWidth;
|
||
|
const height = window.innerHeight;
|
||
|
const dpr = window.devicePixelRatio;
|
||
|
|
||
|
normalComposer.setSize( width * dpr, height * dpr );
|
||
|
logarithmicComposer.setSize( width * dpr, height * dpr );
|
||
|
reverseComposer.setSize( width * dpr, height * dpr );
|
||
|
|
||
|
normalRenderer.setSize( width, height );
|
||
|
logarithmicRenderer.setSize( width, height );
|
||
|
reverseRenderer.setSize( width, height );
|
||
|
|
||
|
camera.aspect = 0.33 * window.innerWidth / window.innerHeight;
|
||
|
camera.updateProjectionMatrix();
|
||
|
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
</body>
|
||
|
</html>
|