//////////////////// // Screen Spaced Ambient Occlusion shader // mainly based on Kustls shader #define NUM_SAMPLES 8 #define SAMPLE_INTENSITY 0.5f //#define SAMPLE_INTENSITY 0.7f #define AREA_SIZE 5e-1f // kustls magic sample positions /*static const float2 samples[NUM_SAMPLES] = { {-0.326212f, -0.405805f}, {-0.840144f, -0.07358f}, {-0.695914f, 0.457137f}, {-0.203345f, 0.620716}, {0.96234f, -0.194983f}, {0.473434f, -0.480026f}, {0.519456, 0.767022f}, {0.185461f, -0.893124f}, {0.507431f, 0.064425f}, {0.89642f, 0.412458f}, {-0.32194f, -0.932615f}, {-0.791559f, -0.597705f}, {0.326212f, 0.405805f}, {0.840144f, 0.07358f}, {0.695914f, -0.457137f}, {0.203345f, -0.620716}, {-0.96234f, 0.194983f}, {-0.473434f, 0.480026f}, {-0.519456, -0.767022f}, {-0.185461f, 0.893124f}, {-0.507431f, -0.064425f}, {-0.89642f, -0.412458f}, {0.32194f, 0.932615f}, {0.791559f, 0.597705f} };*/ struct fragment { float4 pos: WPOS; // normalized screen position float4 texCoord: TEXCOORD0; }; struct pixel { float4 color: COLOR0; }; float2 reflect(float2 pt, float2 n) { // distance to plane float d = dot(n, pt); // reflect around plane float2 rpt = pt - d * 2.0f * n; //return pt; return rpt; } float2 rotate(float2 pt, float2 n) { float2 ptTransformed; ptTransformed.x = n.r * pt.x - n.g * pt.y; ptTransformed.y = n.g * pt.x + n.r * pt.y; return ptTransformed; } //based on kustls shader float ssao(fragment IN, uniform sampler2D positions, uniform sampler2D noiseTexture, uniform float2 samples[NUM_SAMPLES], uniform float3 currentNormal ) { // the current world position float4 centerPosition = tex2D(positions, IN.texCoord.xy); // the w coordinate from the persp. projection float w = centerPosition.w; // Check in a circular area around the current position. // Shoot vectors to the positions there, and check the angle to these positions. // Summing up these angles gives an estimation of the occlusion at the current position. float total_ao = 0.0; const float areaSize = 5e-1f; //const float areaSize = 3e-1f; //const float sampleIntensity = 0.2f; for (int i = 0; i < NUM_SAMPLES; i ++) { float2 offset = samples[i]; //sample noisetex; r stores costheta, g stores sintheta float2 noise = tex2D(noiseTexture, IN.texCoord.xy * 7.0f).xy * 2.0f - 1.0f; // rotation //float2 offsetTransformed = offset; float2 offsetTransformed = rotate(offset, noise); //float2 offsetTransformed = reflect(offset, noise); // weight with projected coordinate to reach similar kernel size for near and far float2 texcoord = IN.texCoord.xy + offsetTransformed * AREA_SIZE * w; float3 sample_position = tex2D(positions, texcoord).xyz; float3 vector_to_sample = sample_position - centerPosition.xyz; float length_to_sample = length(vector_to_sample); float3 direction_to_sample = vector_to_sample / length_to_sample; // Angle between current normal and direction to sample controls AO intensity. float cos_angle = dot(direction_to_sample, currentNormal); cos_angle = max(cos_angle, 0.0f); cos_angle *= cos_angle; // distance between current position and sample position controls AO intensity. //const float maxdist = 2e-1f; //const float maxdist = 5e-1f; const float distanceScale = 1e-6f; //float distance_intensity = maxdist - length_to_sample; float distance_intensity = (SAMPLE_INTENSITY * distanceScale) / (distanceScale + length_to_sample * length_to_sample); //distance_intensity = max(distance_intensity, 0.0f); // quadratic influence //distance_intensity *= distance_intensity; total_ao += cos_angle * distance_intensity; } return (1.0f - total_ao); } float4 shade(fragment IN, uniform sampler2D colors, uniform sampler2D positions, uniform float3 normal, uniform float amb) { float4 lightDir = float4(0.8f, -1.0f, 0.7f, 0.0f); float4 lightDir2 = float4(-0.5f, 0.5f, 0.4f, 0.0f); float4 color = tex2D(colors, IN.texCoord.xy); float4 position = tex2D(positions, IN.texCoord.xy); float4 ambient = 0.3f; // float3 L = normalize(lightPosition - position); float3 light = normalize(lightDir.xyz); float3 light2 = normalize(lightDir2.xyz); float diffuseLight = max(dot(normal, light), 0.0f); float diffuseLight2 = max(dot(normal, light2), 0.0f); float diffuse = diffuseLight + diffuseLight2; return (ambient + diffuse) * color * (1.0f - amb) + amb * color; } pixel main_ssao(fragment IN, uniform sampler2D colors, uniform sampler2D positions, uniform sampler2D normals, uniform sampler2D noiseTexture, uniform float2 samples[NUM_SAMPLES]) { pixel OUT; float4 normal = tex2D(normals, IN.texCoord.xy); float amb = normal.w; // expand normal normal = normalize(normal * 2.0f - 1.0f); float4 col = shade(IN, colors, positions, normal, amb); float ao = ssao(IN, positions, noiseTexture, samples, normal); //OUT.color = ao; OUT.color = ao * col; return OUT; } pixel main(fragment IN, uniform sampler2D colors, uniform sampler2D positions, uniform sampler2D normals) { pixel OUT; float4 normal = tex2D(normals, IN.texCoord.xy); float amb = normal.w; // expand normal normal = normalize(normal * 2.0f - 1.0f); float4 col = shade(IN, colors, positions, normal.xyz, amb); OUT.color = col; return OUT; }