SSAO(4.3+)

Custom implementation of SSAO

Apply this shader to a quad, which is attached to the camera.
Add colorful screenshot as the “ssao_noise”.

Reference: https://learnopengl.com/index.php?p=Advanced-Lighting/SSAO

It would be better to implement this shader as a CompositorEffect, so it would be much more optimized.

The rough process would be as follows:
1. calculate AmbientOcclusion
2. blur in x-direction
3. blur in y-direction

Shader code
shader_type spatial;
render_mode unshaded, depth_draw_never;
const int kernelSize = 16;
const vec3 kernel[16] = {
	vec3(0.019026, 0.014279, 0.010519),
	vec3(-0.024865, 0.007903, 0.064579),
	vec3(-0.019492, 0.042650, 0.017825),
	vec3(0.026718, -0.026148, 0.014359),
	vec3(-0.053264, -0.057006, 0.091722),
	vec3(0.056508, -0.080027, 0.052389),
	vec3(-0.114437, 0.013222, 0.105258),
	vec3(0.084779, -0.132078, 0.057769),
	vec3(-0.013898, -0.089416, 0.171408),
	vec3(-0.131400, -0.059863, 0.038088),
	vec3(-0.009884, 0.009850, 0.001457),
	vec3(-0.010069, -0.031745, 0.012010),
	vec3(0.335164, 0.352856, 0.006707),
	vec3(0.348525, 0.232004, 0.126843),
	vec3(0.415091, 0.146300, 0.212393),
	vec3(0.143938, 0.040199, 0.314998)
};

uniform float radius: hint_range(0.0, 5.0) = 0.5;
uniform float bias: hint_range(0.0, 1.0) = 0.025;

uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, source_color, repeat_disable;
uniform sampler2D DEPTH_TEXTURE: hint_depth_texture, repeat_disable, filter_nearest;
uniform sampler2D NORMAL_ROUGHNESS_TEXTURE: hint_normal_roughness_texture, source_color, repeat_disable, filter_nearest;
uniform sampler2D SSAO_NOISE: filter_nearest, repeat_enable, source_color;



float get_depth(vec2 uv, mat4 inv_proj) {
	float depth = texture(DEPTH_TEXTURE, uv).r;
	float linear_depth = 1.0 / (depth * inv_proj[2].w + inv_proj[3].w);
	return linear_depth;
}

vec3 get_position(vec2 uv, mat4 inv_proj_mat) {
	vec4 clipSpacePosition = vec4(uv * 2.0 - 1.0, texture(DEPTH_TEXTURE, uv).r, 1.0);
	vec4 viewSpacePosition = inv_proj_mat * clipSpacePosition;
	viewSpacePosition /= viewSpacePosition.w;
	return viewSpacePosition.xyz;
}

vec3 get_normal(vec2 uv) {
	vec3 normal = texture(NORMAL_ROUGHNESS_TEXTURE, uv).rgb;
	return (normal - 0.5) * 2.0;
}

void fragment() {
	const vec2 noiseScale = VIEWPORT_SIZE/4.0;
	float occlusionSum = 0.0;
	
	for (int x=-2; x<2; x++) {
		for (int y=-2; y<2; y++) {
			vec2 uv = SCREEN_UV + vec2(float(x),float(y)) / VIEWPORT_SIZE;
			vec3 fragPos = get_position(uv, INV_PROJECTION_MATRIX);
			vec3 normal = texture(NORMAL_ROUGHNESS_TEXTURE, uv).rgb;
			vec3 randomVec = texture(SSAO_NOISE, uv * noiseScale).xyz;
			
			vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
			vec3 bitangent = cross(normal, tangent);
			mat3 TBN = mat3(tangent, bitangent, normal);
			
			float occlusion = 0.0;
			
			for(int i=0; i < kernelSize; i++) {
				// get sample position
				vec3 sample = TBN * kernel[i];
				sample = fragPos + sample * radius;
				
				vec4 offset = vec4(sample, 1.0);
				offset = PROJECTION_MATRIX * offset;
				offset.xyz /= offset.w;
				offset.xyz = offset.xyz * 0.5 + 0.5;
				
				float sampleDepth = get_position(offset.xy, INV_PROJECTION_MATRIX).z;
				float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
				occlusion += (sampleDepth >= sample.z + bias ? 1.0 : 0.0) * rangeCheck;
			}
			occlusion /= float(kernelSize);
			occlusionSum += occlusion;
		}
	}
	
	
	ALBEDO = texture(SCREEN_TEXTURE, SCREEN_UV).rgb;
	ALBEDO *= 1.0 - vec3(occlusionSum / 16.0);
}
Tags
3d, ambien occlusion, screen-space, ScreenSpace, SSAO
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from Firerabbit

2D Pixelart Upscaler/Filter

3D Pixelart Upscaler/Filter

Dither opacity with GLES2 Support

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jooio
Jooio
2 months ago

Not so useless if it worked in compatibility mode