【Three.js】遮挡剔除

背景

考虑到场景中模型顶点过多会让fps过低,所以想把相机看不到的模型从场景中移除,来提高渲染性能,但是后续测试结果让我恍然大悟。虽然场景中的顶点数降低了很多,但是每次渲染检查遮挡的过程本身就是一个消耗性能的行为,有点适得其反了。虽然并没有解决问题,但是在此做一下探索记录。

效果


【Three.js】遮挡剔除_第1张图片

例子

index.html

DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - geometry hierarchytitle>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				background:#fff;
				padding:0;
				margin:0;
				font-weight: bold;
				overflow:hidden;
			}
		style>
	head>
	<body>
		
		<script src="./three.js">script>

		<script type="module">
    	import Stats from '../jsm/libs/stats.module.js'
			var container, stats, occlusionStats;

			var camera, scene, renderer;

			var geometry;

			var mouseX = 0, mouseY = 0;
			
			var debugMode = 0;

			var windowHalfX = window.innerWidth / 2;
			var windowHalfY = window.innerHeight / 2;

			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
			document.addEventListener( 'click', onDocumentClick, false );

			init();
			animate();

			function init() {

				container = document.createElement( 'div' );
				document.body.appendChild( container );

				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 10, 10000 );
				camera.position.z = 500;

				scene = new THREE.Scene();
				scene.fog = new THREE.Fog( 0xffffff, 1, 10000 );

				var geometry = new THREE.CubeGeometry( 100, 100, 100 );
				var material = new THREE.MeshNormalMaterial();
				
				for ( var gz = -10; gz < 10 ; gz++ ) {
					
					if ( gz % 3 === 0 ) continue;

					for ( var gx = -10; gx < 10 ; gx++ ) {
						
						if ( gx % 3 === 0 ) continue;
						
						var height = Math.random() * 10;
						
						for ( var gy = 0; gy < height ; gy++ ) {
							
							var mesh = new THREE.Mesh( geometry, material );
							
							mesh.occluder = true;
							mesh.occludable = THREE.EdgeOccludable;

							mesh.position.x = gx * 100;
							mesh.position.y = gy * 100;
							mesh.position.z = gz * 100;

							mesh.matrixAutoUpdate = false;
							mesh.updateMatrix();

							scene.add( mesh );

						}
						
					}
					
				}

				renderer = new THREE.WebGLRenderer();
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.sortObjects = true;
				renderer.occlusionCulling = true;

				container.appendChild( renderer.domElement );

				stats = new Stats();
				stats.domElement.style.position = 'absolute';
				stats.domElement.style.top = '0px';
				stats.domElement.style.zIndex = 100;
				container.appendChild( stats.domElement );

				window.addEventListener( 'resize', onWindowResize, false );
				
				occlusionStats = document.createElement('DIV');
				occlusionStats.style.position = 'absolute';
				occlusionStats.style.top = '200px';
				occlusionStats.style.zIndex = 100;
				occlusionStats.style.whiteSpace = 'pre';
				occlusionStats.style.fontFamily = 'monospace';
				container.appendChild( occlusionStats );
				
				var instruction = document.createElement('P');
				instruction.textContent = 'Click to cycle through debug views';
				instruction.style.position = 'absolute';
				instruction.style.bottom = '10px';
				instruction.style.zIndex = 100;
				instruction.style.fontFamily = 'sans-serif';
				container.appendChild( instruction );
			}

			function onWindowResize() {

				windowHalfX = window.innerWidth / 2;
				windowHalfY = window.innerHeight / 2;

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

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

			}

			function onDocumentMouseMove(event) {

				mouseX = event.clientX / window.innerWidth;
				mouseY = event.clientY / window.innerHeight;

			}
			
			function onDocumentClick(event) {
				
				debugMode++;
				
				if ( debugMode & 1 ) {
					
					if ( ! scene.overrideMaterial ) {

						scene.overrideMaterial = new THREE.MeshBasicMaterial({wireframe:true, color:0xff00ff});

					}
					
				}
				else if ( scene.overrideMaterial ) {

					scene.overrideMaterial = null;

				}

				if ( debugMode & 2 ) {

					if ( ! window.threejsOcclusionOverlayCanvas ) {
						var overlayCanvas = document.createElement('CANVAS');
						overlayCanvas.style.position = 'absolute';
						overlayCanvas.style.top = '0';
						overlayCanvas.style.left = '0';
						overlayCanvas.style.bottom = '0';
						overlayCanvas.style.right = '0';
						overlayCanvas.style.width = '100%';
						overlayCanvas.style.height = '100%';
						container.appendChild(overlayCanvas);
						window.threejsOcclusionOverlayCanvas = overlayCanvas;
					}
					
				}
				else if ( window.threejsOcclusionOverlayCanvas ) {
					window.threejsOcclusionOverlayCanvas.parentNode.removeChild(window.threejsOcclusionOverlayCanvas);
					window.threejsOcclusionOverlayCanvas = null;
				}

			}

			function animate() {

				requestAnimationFrame( animate );

				render();
				stats.update();

			}

			function render() {
				
				camera.position.x = Math.cos(mouseX * Math.PI) * 2000;
				camera.position.y = mouseY * 1000;
				camera.position.z = Math.sin(mouseX * Math.PI) * 2000;

				camera.lookAt( scene.position );

				renderer.render( scene, camera );

				var occlusionStatsText = '';

//				console.log(renderer.info);

				for ( var stat in renderer.info.occlusion ) {
					
					occlusionStatsText += stat + ": " + renderer.info.occlusion[ stat ] + "\n";
				}
				if ( occlusionStats.textContent !== occlusionStatsText ) {
					
					occlusionStats.textContent = occlusionStatsText;
					
				}

			}

		script>

	body>
html>

three.js

rendererocclusionCulling 属性在r58版本有,最新版的该属性被移除了,移除原因我想也是我开头说的原因吧,有兴趣的同学可以深入研究一下。

webgl实现

https://tsherif.github.io/webgl2examples/occlusion.html这个是webgl的例子。

你可能感兴趣的:(前端,web,three.js,javascript,前端)