webgl_postprocessing_ssao.html 6.9 KB
Newer Older
D
Daosheng Mu 已提交
1 2 3 4 5 6 7 8 9
<!DOCTYPE html>

<!--Reference: 
SSAO algo: http://devlog-martinsh.blogspot.tw/2011/12/ssao-shader-update-v12.html?showComment=1398158188712#c1563204765906693531
log depth http://outerra.blogspot.tw/2013/07/logarithmic-depth-buffer-optimizations.html
convert the exponential depth to a linear value: http://www.ozone3d.net/blogs/lab/20090206/how-to-linearize-the-depth-value/
Spiral sampling http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere-->

<html lang="en">
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
	<head>
		<title>three.js webgl - postprocessing - Screen Space Ambient Occlusion</title>
		<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-color: #000000;
				margin: 0px;
				overflow: hidden;
				font-family:Monospace;
				font-size:13px;
				text-align:center;
				font-weight: bold;
			}

			a {
				color:#0078ff;
			}

			#info {
				color:#fff;
				position: relative;
				top: 0px;
				width: 50em;
				margin: 0 auto -2.1em;
				padding: 5px;
				z-index:100;
			}
		</style>
	</head>
	<body>
		<script src="../build/three.js"></script>
		<script src="js/shaders/SSAOShader.js"></script>
D
Daosheng Mu 已提交
43
		<script src="js/shaders/CopyShader.js"></script>
44 45
		<script src="js/postprocessing/RenderPass.js"></script>
		<script src="js/postprocessing/ShaderPass.js"></script>
D
Daosheng Mu 已提交
46
		<script src="js/postprocessing/MaskPass.js"></script>
47
		<script src="js/postprocessing/EffectComposer.js"></script>
48 49 50 51 52
		<script src="js/Detector.js"></script>
		<script src="js/libs/stats.min.js"></script>
		<script src='js/libs/dat.gui.min.js'></script>

		<div id="info">
D
Daosheng Mu 已提交
53 54
			<a href="http://threejs.org" target="_blank">three.js</a> - webgl screen space ambient occlusion example			
			<p id="info">shader by <a href="http://alteredqualia.com">alteredq</a></p>
55 56 57 58 59 60 61
		</div>

		<script>

			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
						
			var container, stats;   
D
Daosheng Mu 已提交
62 63
			var camera, scene, renderer;
			var depthMaterial, effectComposer, depthRenderTarget;
64
			var ssaoPass;
65 66 67 68 69 70 71 72 73 74 75 76 77 78
			var group;
			var depthScale = 1.0;
			var postprocessing = { enabled : true, renderMode: 0 }; // renderMode: 0('framebuffer'), 1('onlyAO')

			init();
			animate();

			function init() {

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

				renderer = new THREE.WebGLRenderer( { antialias: false } );
				renderer.setClearColor( 0xa0a0a0 );
79
				renderer.setPixelRatio( window.devicePixelRatio );
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 100, 700 );
				camera.position.z = 500;

				scene = new THREE.Scene();

				group = new THREE.Object3D();
				scene.add( group );
		   
				var geometry = new THREE.IcosahedronGeometry( 5, 1 );
				for ( var i = 0; i < 200; i ++ ) {
				
					var material = new THREE.MeshBasicMaterial();
					material.color.r = Math.random();
					material.color.g = Math.random();
					material.color.b = Math.random();
				   
					var mesh = new THREE.Mesh( geometry, material );
					mesh.position.x = Math.random() * 400 - 200;
					mesh.position.y = Math.random() * 400 - 200;
					mesh.position.z = Math.random() * 400 - 200;
					mesh.rotation.x = Math.random();
					mesh.rotation.y = Math.random();
					mesh.rotation.z = Math.random();

					mesh.scale.x = mesh.scale.y = mesh.scale.z = Math.random() * 10 + 1;
					group.add( mesh );
				}
				
				stats = new Stats();
				stats.domElement.style.position = 'absolute';
				stats.domElement.style.top = '0px';
				container.appendChild( stats.domElement );

116
				// Init postprocessing                
117 118 119 120 121 122 123 124 125 126 127 128 129
				initPostprocessing();
			
				// Init gui
				var gui = new dat.GUI();
				gui.add( postprocessing, "enabled" ).onChange();
				gui.add( postprocessing, "renderMode", { framebuffer: 0, onlyAO: 1 } ).onChange( renderModeChange ).listen();

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

			function renderModeChange( value ) {

				if ( value == 0 ) { // framebuffer
130
					ssaoPass.uniforms[ 'onlyAO' ].value = false;
131
				} else if ( value == 1 ) {  // onlyAO
132
					ssaoPass.uniforms[ 'onlyAO' ].value = true;
133 134 135 136 137 138 139 140 141 142 143
				} else {
					console.error( "Not define renderModeChange type: " + value );
				}
			}
			
			function onWindowResize() {

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

D
Daosheng Mu 已提交
144 145 146 147
				// Resize renderTargets
				ssaoPass.uniforms[ 'size' ].value.set( window.innerWidth, window.innerHeight );
				depthRenderTarget.setSize( window.innerWidth, window.innerHeight );
				effectComposer.setSize( window.innerWidth, window.innerHeight );
148 149 150
			}

			function initPostprocessing() {
151 152 153 154 155 156 157 158 159 160 161

				// Setup render pass
				var renderPass = new THREE.RenderPass( scene, camera );

				// Setup depth pass
				var depthShader = THREE.ShaderLib[ "depthRGBA" ];
				var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );

				depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader,
					uniforms: depthUniforms, blending: THREE.NoBlending } );
								
162
				var pars = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter };
163
				depthRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
164
				
165 166 167 168 169 170 171 172 173
				// Setup SSAO pass
				ssaoPass = new THREE.ShaderPass( THREE.SSAOShader );
				ssaoPass.renderToScreen = true;
				//ssaoPass.uniforms[ "tDiffuse" ].value will be set by ShaderPass 
				ssaoPass.uniforms[ "tDepth" ].value = depthRenderTarget; 
				ssaoPass.uniforms[ 'size' ].value.set( window.innerWidth, window.innerHeight );
				ssaoPass.uniforms[ 'cameraNear' ].value = camera.near;
				ssaoPass.uniforms[ 'cameraFar' ].value = camera.far;
				ssaoPass.uniforms[ 'onlyAO' ].value = ( postprocessing.renderMode == 1 );
D
Daosheng Mu 已提交
174 175
				ssaoPass.uniforms[ 'aoClamp' ].value = 0.3;
				ssaoPass.uniforms[ 'lumInfluence' ].value = 0.5;
176
				
177 178 179 180
				// Add pass to effect composer
				effectComposer = new THREE.EffectComposer( renderer );
				effectComposer.addPass( renderPass );
				effectComposer.addPass( ssaoPass );
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
			}
			
			function animate() {
				requestAnimationFrame( animate );

				render();
				stats.update();
			}

			function render() {                                
				var timer = performance.now();
				group.rotation.x = timer * 0.0002;
				group.rotation.y = timer * 0.0001;

				if ( postprocessing.enabled ) {
					
197
					// Render depth into depthRenderTarget                    
198
					scene.overrideMaterial = depthMaterial;
199
					renderer.render( scene, camera, depthRenderTarget, true );
200

201 202 203
					// Render renderPass and SSAO shaderPass
					scene.overrideMaterial = null;
					effectComposer.render();
204 205 206 207 208 209 210 211
					
				} else {
					renderer.render( scene, camera );
				}
			}
			
		</script>
	</body>
D
Daosheng Mu 已提交
212
</html>