180 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {
 | |
| 	Matrix4,
 | |
| 	Vector2
 | |
| } from 'three';
 | |
| 
 | |
| /**
 | |
|  * TODO
 | |
|  */
 | |
| 
 | |
| const SAOShader = {
 | |
| 
 | |
| 	name: 'SAOShader',
 | |
| 
 | |
| 	defines: {
 | |
| 		'NUM_SAMPLES': 7,
 | |
| 		'NUM_RINGS': 4,
 | |
| 		'DIFFUSE_TEXTURE': 0,
 | |
| 		'PERSPECTIVE_CAMERA': 1
 | |
| 	},
 | |
| 
 | |
| 	uniforms: {
 | |
| 
 | |
| 		'tDepth': { value: null },
 | |
| 		'tDiffuse': { value: null },
 | |
| 		'tNormal': { value: null },
 | |
| 		'size': { value: new Vector2( 512, 512 ) },
 | |
| 
 | |
| 		'cameraNear': { value: 1 },
 | |
| 		'cameraFar': { value: 100 },
 | |
| 		'cameraProjectionMatrix': { value: new Matrix4() },
 | |
| 		'cameraInverseProjectionMatrix': { value: new Matrix4() },
 | |
| 
 | |
| 		'scale': { value: 1.0 },
 | |
| 		'intensity': { value: 0.1 },
 | |
| 		'bias': { value: 0.5 },
 | |
| 
 | |
| 		'minResolution': { value: 0.0 },
 | |
| 		'kernelRadius': { value: 100.0 },
 | |
| 		'randomSeed': { value: 0.0 }
 | |
| 	},
 | |
| 
 | |
| 	vertexShader: /* glsl */`
 | |
| 
 | |
| 		varying vec2 vUv;
 | |
| 
 | |
| 		void main() {
 | |
| 			vUv = uv;
 | |
| 			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
 | |
| 		}`,
 | |
| 
 | |
| 	fragmentShader: /* glsl */`
 | |
| 		#include <common>
 | |
| 
 | |
| 		varying vec2 vUv;
 | |
| 
 | |
| 		#if DIFFUSE_TEXTURE == 1
 | |
| 		uniform sampler2D tDiffuse;
 | |
| 		#endif
 | |
| 
 | |
| 		uniform highp sampler2D tDepth;
 | |
| 		uniform highp sampler2D tNormal;
 | |
| 
 | |
| 		uniform float cameraNear;
 | |
| 		uniform float cameraFar;
 | |
| 		uniform mat4 cameraProjectionMatrix;
 | |
| 		uniform mat4 cameraInverseProjectionMatrix;
 | |
| 
 | |
| 		uniform float scale;
 | |
| 		uniform float intensity;
 | |
| 		uniform float bias;
 | |
| 		uniform float kernelRadius;
 | |
| 		uniform float minResolution;
 | |
| 		uniform vec2 size;
 | |
| 		uniform float randomSeed;
 | |
| 
 | |
| 		// RGBA depth
 | |
| 
 | |
| 		#include <packing>
 | |
| 
 | |
| 		vec4 getDefaultColor( const in vec2 screenPosition ) {
 | |
| 			#if DIFFUSE_TEXTURE == 1
 | |
| 			return texture2D( tDiffuse, vUv );
 | |
| 			#else
 | |
| 			return vec4( 1.0 );
 | |
| 			#endif
 | |
| 		}
 | |
| 
 | |
| 		float getDepth( const in vec2 screenPosition ) {
 | |
| 			return texture2D( tDepth, screenPosition ).x;
 | |
| 		}
 | |
| 
 | |
| 		float getViewZ( const in float depth ) {
 | |
| 			#if PERSPECTIVE_CAMERA == 1
 | |
| 			return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
 | |
| 			#else
 | |
| 			return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
 | |
| 			#endif
 | |
| 		}
 | |
| 
 | |
| 		vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {
 | |
| 			float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];
 | |
| 			vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );
 | |
| 			clipPosition *= clipW; // unprojection.
 | |
| 
 | |
| 			return ( cameraInverseProjectionMatrix * clipPosition ).xyz;
 | |
| 		}
 | |
| 
 | |
| 		vec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition ) {
 | |
| 			return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );
 | |
| 		}
 | |
| 
 | |
| 		float scaleDividedByCameraFar;
 | |
| 		float minResolutionMultipliedByCameraFar;
 | |
| 
 | |
| 		float getOcclusion( const in vec3 centerViewPosition, const in vec3 centerViewNormal, const in vec3 sampleViewPosition ) {
 | |
| 			vec3 viewDelta = sampleViewPosition - centerViewPosition;
 | |
| 			float viewDistance = length( viewDelta );
 | |
| 			float scaledScreenDistance = scaleDividedByCameraFar * viewDistance;
 | |
| 
 | |
| 			return max(0.0, (dot(centerViewNormal, viewDelta) - minResolutionMultipliedByCameraFar) / scaledScreenDistance - bias) / (1.0 + pow2( scaledScreenDistance ) );
 | |
| 		}
 | |
| 
 | |
| 		// moving costly divides into consts
 | |
| 		const float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES );
 | |
| 		const float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES );
 | |
| 
 | |
| 		float getAmbientOcclusion( const in vec3 centerViewPosition ) {
 | |
| 			// precompute some variables require in getOcclusion.
 | |
| 			scaleDividedByCameraFar = scale / cameraFar;
 | |
| 			minResolutionMultipliedByCameraFar = minResolution * cameraFar;
 | |
| 			vec3 centerViewNormal = getViewNormal( centerViewPosition, vUv );
 | |
| 
 | |
| 			// jsfiddle that shows sample pattern: https://jsfiddle.net/a16ff1p7/
 | |
| 			float angle = rand( vUv + randomSeed ) * PI2;
 | |
| 			vec2 radius = vec2( kernelRadius * INV_NUM_SAMPLES ) / size;
 | |
| 			vec2 radiusStep = radius;
 | |
| 
 | |
| 			float occlusionSum = 0.0;
 | |
| 			float weightSum = 0.0;
 | |
| 
 | |
| 			for( int i = 0; i < NUM_SAMPLES; i ++ ) {
 | |
| 				vec2 sampleUv = vUv + vec2( cos( angle ), sin( angle ) ) * radius;
 | |
| 				radius += radiusStep;
 | |
| 				angle += ANGLE_STEP;
 | |
| 
 | |
| 				float sampleDepth = getDepth( sampleUv );
 | |
| 				if( sampleDepth >= ( 1.0 - EPSILON ) ) {
 | |
| 					continue;
 | |
| 				}
 | |
| 
 | |
| 				float sampleViewZ = getViewZ( sampleDepth );
 | |
| 				vec3 sampleViewPosition = getViewPosition( sampleUv, sampleDepth, sampleViewZ );
 | |
| 				occlusionSum += getOcclusion( centerViewPosition, centerViewNormal, sampleViewPosition );
 | |
| 				weightSum += 1.0;
 | |
| 			}
 | |
| 
 | |
| 			if( weightSum == 0.0 ) discard;
 | |
| 
 | |
| 			return occlusionSum * ( intensity / weightSum );
 | |
| 		}
 | |
| 
 | |
| 		void main() {
 | |
| 			float centerDepth = getDepth( vUv );
 | |
| 			if( centerDepth >= ( 1.0 - EPSILON ) ) {
 | |
| 				discard;
 | |
| 			}
 | |
| 
 | |
| 			float centerViewZ = getViewZ( centerDepth );
 | |
| 			vec3 viewPosition = getViewPosition( vUv, centerDepth, centerViewZ );
 | |
| 
 | |
| 			float ambientOcclusion = getAmbientOcclusion( viewPosition );
 | |
| 
 | |
| 			gl_FragColor = getDefaultColor( vUv );
 | |
| 			gl_FragColor.xyz *=  1.0 - ambientOcclusion;
 | |
| 		}`
 | |
| 
 | |
| };
 | |
| 
 | |
| export { SAOShader };
 |