three
Version:
JavaScript 3D library
183 lines (144 loc) • 5.76 kB
JavaScript
console.warn( "THREE.SAOShader: As part of the transition to ES6 Modules, the files in 'examples/js' were deprecated in May 2020 (r117) and will be deleted in December 2020 (r124). You can find more information about developing using ES6 Modules in https://threejs.org/docs/#manual/en/introduction/Installation." );
/**
* TODO
*/
THREE.SAOShader = {
defines: {
"NUM_SAMPLES": 7,
"NUM_RINGS": 4,
"NORMAL_TEXTURE": 0,
"DIFFUSE_TEXTURE": 0,
"DEPTH_PACKING": 1,
"PERSPECTIVE_CAMERA": 1
},
uniforms: {
"tDepth": { value: null },
"tDiffuse": { value: null },
"tNormal": { value: null },
"size": { value: new THREE.Vector2( 512, 512 ) },
"cameraNear": { value: 1 },
"cameraFar": { value: 100 },
"cameraProjectionMatrix": { value: new THREE.Matrix4() },
"cameraInverseProjectionMatrix": { value: new THREE.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: [
"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" )
};