Реализация Ambient Occlusion в простом Voxel Renderer - PullRequest
0 голосов
/ 08 февраля 2020

В настоящее время я пытаюсь реализовать Ambient Occlusion в простом Voxel Renderer, каждый блок визуализируется (если не виден) с 24 вершинами и 12 треугольниками, так что никаких зацеплений нет.

Я следовал этот учебник о том, как может работать окружающая окклюзия для миров, похожих на майнкрафт, но он не объяснил, как на самом деле реализовать это в шейдерах / графическом программировании, так что то, что я сделал до сих пор, это только мои необразованные лучшие догадки.

This is what it looks like currently

Основная идея c заключается в том, чтобы каждая вершина генерировала значение из окружающих блоков о том, насколько «темной» должна быть окружающая окклюзия. , (Не берите в голову мои ценности, являющиеся полностью неправильными в настоящее время). Это от 0 (без окружения) до 3 (полностью окруженная вершина). Картинка в уроке, который я связал, помогает объяснить это.

Итак, я попробовал это, но, похоже, не затемняет область вокруг вершины, но вместо этого весь треугольник, вершина находится в ... Как я могу заставить это не делать этого? Я абсолютный новичок в шейдерах и графическом программировании, поэтому любая помощь приветствуется: D

Вот мой вершинный шейдер, входные данные

  • позиция вершины
  • нормаль вершины
  • tex_coord в текстурном атласе
  • tile_uv: позиция в блоке (0 или 1 для левого / правого нижнего / верхнего угла)
  • значение ambient_occlusion
#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);
}

А вот мой фрагментный шейдер:

#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)));
}

1 Ответ

2 голосов
/ 10 февраля 2020

«Плоская» часть этого ...

layout(location = 4) in flat uint v_ambient_occlusion;

... означает, что одно и то же значение используется для всего треугольника (взятого из провоцирующей вершины). Если вы хотите интерполяцию между 3 значениями на вершину, просто удалите квалификатор flat.

Обратите внимание, что в настоящее время это целочисленное значение атрибута, которое должно быть плоским затенением, поэтому вам необходимо преобразовать ввод в поплавок тоже.

...