Рекламный щит для сфер OpenGL - PullRequest
0 голосов
/ 26 февраля 2019

Мир состоит из сфер.Поскольку рисование сферы в OpenGL занимает много треугольников, я подумал, что было бы быстрее использовать точку и радиус для представления сферы, а затем использовать Billboarding в OpenGL для ее рисования.При текущем подходе, который я выбрал, смежные сферы не соприкасаются при повороте вида.

Вот пример:

Есть две сферы:

Сфера 1 Позиция (0, 0, -3) Радиус (0.5)

Сфера 2 Позиция (-1, 0, -3) Радиус (0,5)

Матрица проекции определяется с помощью:

glm::perspective(glm::radians(120.0f), 1.0f, 1.0f, 100.0f);

Изображение 1 : если вращение отсутствует, оно выглядит так, как ожидалось.

No rotation

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

Rotation

Что я пробовал:

  • Я пытался GL_POINTS, они не работали так хорошо, потому что мне показалось, что тест глубины для меня не совсем корректный.
  • Я пробовал геометрический шейдер, который создает квадрат до и после применения матрицы проекции.

Вот код, который я сейчас создал для создания изображений:

Вершинный шейдер

#version 460

layout(location = 0) in vec3 position;
layout(location = 1) in float radius;


out float radius_vs;

void main()
{

    gl_Position = vec4(position, 1.0);
    radius_vs = radius;
}

Геометрический шейдер

#version 460

layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
layout(location = 2) uniform mat4 view_mat;
layout(location = 3) uniform mat4 projection_mat;

in float radius_vs[];
out vec2 bounds;

void main()
{
    vec3 x_dir = vec3(view_mat[0][0], view_mat[1][0], view_mat[2][0]) * radius_vs[0];
    vec3 y_dir = vec3(view_mat[0][1], view_mat[1][1], view_mat[2][1]) * radius_vs[0];


    mat4 fmat = projection_mat * view_mat;


    gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz - x_dir - y_dir, 1.0f);
    bounds = vec2(-1.0f, -1.0f);
    EmitVertex();

    gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz - x_dir + y_dir, 1.0f);
    bounds = vec2(-1.0f, 1.0f);
    EmitVertex();

    gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz + x_dir - y_dir, 1.0f);
    bounds = vec2(1.0f, -1.0f);
    EmitVertex();

    gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz + x_dir + y_dir, 1.0f);
    bounds = vec2(1.0f, 1.0f);
    EmitVertex();

    EndPrimitive();
}

Фрагмент шейдера

#version 460

out vec4 colorOut;

in vec2 bounds;

void main()
{
    vec2 circCoord = bounds;
    if (dot(circCoord, circCoord) > 1.0) 
    {
        discard;
    }
    colorOut = vec4(1.0f, 1.0f, 0.0f, 1.0);
}
...