Spaces:
Running
Running
| THREE.SAOShader = { | |
| defines: { | |
| 'NUM_SAMPLES': 7, | |
| 'NUM_RINGS': 4, | |
| 'NORMAL_TEXTURE': 0, | |
| 'DIFFUSE_TEXTURE': 0, | |
| 'DEPTH_PACKING': 1, | |
| 'PERSPECTIVE_CAMERA': 1 | |
| }, | |
| uniforms: { | |
| 'tDepth': { type: 't', value: null }, | |
| 'tDiffuse': { type: 't', value: null }, | |
| 'tNormal': { type: 't', value: null }, | |
| 'size': { type: 'v2', value: new THREE.Vector2( 512, 512 ) }, | |
| 'cameraNear': { type: 'f', value: 1 }, | |
| 'cameraFar': { type: 'f', value: 100 }, | |
| 'cameraProjectionMatrix': { type: 'm4', value: new THREE.Matrix4() }, | |
| 'cameraInverseProjectionMatrix': { type: 'm4', value: new THREE.Matrix4() }, | |
| 'scale': { type: 'f', value: 1.0 }, | |
| 'intensity': { type: 'f', value: 0.1 }, | |
| 'bias': { type: 'f', value: 0.5 }, | |
| 'minResolution': { type: 'f', value: 0.0 }, | |
| 'kernelRadius': { type: 'f', value: 100.0 }, | |
| 'randomSeed': { type: 'f', value: 0.0 } | |
| }, | |
| vertexShader: [ | |
| "varying vec2 vUv;", | |
| "void main() {", | |
| " vUv = uv;", | |
| " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", | |
| "}" | |
| ].join( "\n" ), | |
| fragmentShader: [ | |
| "#include <common>", | |
| "varying vec2 vUv;", | |
| "#if DIFFUSE_TEXTURE == 1", | |
| "uniform sampler2D tDiffuse;", | |
| "#endif", | |
| "uniform sampler2D tDepth;", | |
| "#if NORMAL_TEXTURE == 1", | |
| "uniform sampler2D tNormal;", | |
| "#endif", | |
| "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 ) {", | |
| " #if DEPTH_PACKING == 1", | |
| " return unpackRGBAToDepth( texture2D( tDepth, screenPosition ) );", | |
| " #else", | |
| " return texture2D( tDepth, screenPosition ).x;", | |
| " #endif", | |
| "}", | |
| "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 ) {", | |
| " #if NORMAL_TEXTURE == 1", | |
| " return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );", | |
| " #else", | |
| " return normalize( cross( dFdx( viewPosition ), dFdy( viewPosition ) ) );", | |
| " #endif", | |
| "}", | |
| "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;", | |
| "}" | |
| ].join( "\n" ) | |
| }; | |