Logarithmic Depth Buffer & set camera far to a super big number, horizon line show error

turn logarithmic Depth Buffer on , add a very large horizontal plane, and set camera far to super high number, the horizon line will show error, can anyone help me explain, many thanks


<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl -logarithmicDepthBuffer -horizon</title>
		<meta charset="utf-8" />
		<meta
			name="viewport"
			content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
		/>
		<style>
			html,
			body,
			#container {
				width: 100%;
				height: 100%;
				padding: 0;
				margin: 0;
			}
		</style>
	</head>

	<body>
		<div id="container"></div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "../examples/jsm/"
				}
			}
		</script>

		<script type="module">
			import * as THREE from 'three';

			import Stats from 'three/addons/libs/stats.module.js';
			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
			import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';

			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

			const clock = new THREE.Clock();
			const container = document.getElementById('container');

			const stats = new Stats();
			container.appendChild(stats.dom);

			const renderer = new THREE.WebGLRenderer({
				antialias: true,
				logarithmicDepthBuffer: true,
			});
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(window.innerWidth, window.innerHeight);
			container.appendChild(renderer.domElement);

			const pmremGenerator = new THREE.PMREMGenerator(renderer);
			const scene = new THREE.Scene();
			scene.background = new THREE.Color(0xbfe3dd);
			scene.environment = pmremGenerator.fromScene(
				new RoomEnvironment(),
				0.04
			).texture;

			const camera = new THREE.PerspectiveCamera(
				60,
				window.innerWidth / window.innerHeight,
				0.1,
				1e7
			);
			camera.position.set(
				623.884570178913,
				95.42968802545737,
				9.024963847710772
			);

			const controls = new OrbitControls(camera, renderer.domElement);
			controls.update();
			controls.enablePan = false;
			controls.enableDamping = true;

			const panel = new GUI({ width: 310 });

			panel
				.add(
					{
						isEnvironmentTexture: true,
					},
					'isEnvironmentTexture'
				)
				.onChange((val) => {
					if (val) {
						scene.environment = pmremGenerator.fromScene(
							new RoomEnvironment(),
							0.04
						).texture;
					} else {
						scene.environment = false;
					}
				});

			{
				const dracoLoader = new DRACOLoader();
				dracoLoader.setDecoderPath('jsm/libs/draco/gltf/');

				const loader = new GLTFLoader();
				loader.setDRACOLoader(dracoLoader);
				loader.load(
					'models/gltf/LittlestTokyo.glb',
					function (gltf) {
						const model = gltf.scene;
						model.position.y += 210;
						scene.add(model);

						renderer.setAnimationLoop(animate);
					},
					undefined,
					function (e) {
						console.error(e);
					}
				);
			}

			const geo = new THREE.PlaneGeometry(1e8, 1e5);
			const mt = new THREE.MeshBasicMaterial({ color: '#fff' });
			const ms = new THREE.Mesh(geo, mt);
			ms.rotateX(-Math.PI / 2);
			scene.add(ms);

			window.onresize = function () {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize(window.innerWidth, window.innerHeight);
			};

			function animate() {
				const delta = clock.getDelta();

				controls.update();

				stats.update();

				renderer.render(scene, camera);
			}
		</script>
	</body>
</html>

Try subdividing the plane.. or shrinking down the scene.

Dealing with number precision is a multi-layer problem.

Depth buffer storage precision is only one part of the story.
(which logdepthbuffer helps with.)

32bit float precision on the GPU is another part of the issue.

I think intuitively you can understand that there must be some limit to the sizes of numbers in the scene.

Even if 1e7 is close to the “safe” range for 32 bit.. keep in mind, it will also get multiplied by other values in the graphics pipeline, so even though it might be in the “safe” range, it will go out of that range as it goes through the pipeline.

Long story short.. use smaller numbers.

3 Likes