I am currently trying to implement Ambient Occlusion in a simple Voxel Renderer, each block is rendered (unless not visible) with 24 vertices and 12 triangles, so no meshing of any kind.
I followed this tutorial on how ambient occlusion for minecraft-like worlds could work, but it didn't explain how to actually implement that in shaders / graphics programming, so what I've done so far are only my uneducated best guesses.
The basic idea is, for each vertex to generate a value from the surrounding blocks about how "dark" the ambient occlusion should be. (Nevermind my values being completely wrong currently). These are from 0 (no surroundings) to 3 (vertex completely surrounded) The picture in the tutorial I linked helps to explain that.
So I tried that, but it seems to not darken the area around a vertex, but instead the whole triangle, the vertex is in... How do I make it not do that? I am a total beginner in shaders and graphics programming, so any help is appreciated :D
Here is my vertex shader, the inputs are
- position of vertex
- normal of vertex
- tex_coord in texture atlas
- tile_uv: position on block (0 or 1 for left/right bottom/top)
- the ambient_occlusion value
#version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 tex_coord;
layout(location = 3) in vec2 tile_uv;
layout(location = 4) in uint ambient_occlusion;
layout(location = 0) out vec3 v_position;
layout(location = 1) out vec3 v_normal;
layout(location = 2) out vec2 v_tex_coord;
layout(location = 3) out vec2 v_tile_uv;
layout(location = 4) out uint v_ambient_occlusion;
layout(set = 0, binding = 0) uniform Data {
mat4 world;
mat4 view;
mat4 proj;
vec2 tile_size;
} uniforms;
void main() {
mat4 worldview = uniforms.view * uniforms.world;
v_normal = mat3(transpose(inverse(uniforms.world))) * normal;
v_tex_coord = tex_coord;
v_tile_uv = tile_uv;
v_position = vec3(uniforms.world * vec4(position, 1.0));
v_ambient_occlusion = ambient_occlusion;
gl_Position = uniforms.proj * worldview * vec4(position.x, position.y, position.z, 1.0);
}
And here is my fragment shader:
#version 450
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec2 v_tex_coord;
layout(location = 3) in vec2 v_tile_uv;
layout(location = 4) in flat uint v_ambient_occlusion;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 1) uniform sampler2D block_texture;
void main() {
vec3 ao_color;
switch (v_ambient_occlusion) {
case 0: ao_color = vec3(1.0, 0.0, 0.0); break;
case 1: ao_color = vec3(0.0, 1.0, 0.0); break;
case 2: ao_color = vec3(0.0, 0.0, 1.0); break;
case 3: ao_color = vec3(1.0, 1.0, 1.0); break;
}
f_color = texture(block_texture, v_tex_coord);
f_color.rgb = mix(f_color.rgb, vec3(0.05, 0.05, 0.05), 0.3 * v_ambient_occlusion * distance(v_tile_uv, vec2(0.5)));
}