Получение позиций вершин в шейдере фрагментов


По определенной причине мне нужно получить положение всех вершин, которые образуют примитив (треугольник)в моем шейдере фрагментов.

Есть три способа сделать это: дополнительные атрибуты, униформа и геометрический шейдер.

Атрибуты :

// vertex shader
in vec3 vPosition;
in vec3 vposA;
in vec3 vposB;
in vec3 vposC;
out vec3 posA;
out vec3 posB;
out vec3 posC;

void main() {
    // ....
    posA = vposA;
    posB = vposB;
    posC = vposC;
}

Проблема заключается в том, что мне нужно отправить дополнительные атрибуты, что означает дополнительную память, используемую в VBO.

Униформа :

// fragment shader
uniform vec3 posA;
uniform vec3 posB;
uniform vec3 posC;

void main() {
    // ...
}

Главным недостатком, очевидно, является необходимость привязки униформ для каждого треугольника это рисуется, так что я могу нарисовать только один треугольник на каждый drawcall.

GS :

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

out vec3 posA;
out vec3 posB;
out vec3 posC;

void main()
{
    posA = gl_in[0].gl_Position.xyz;
    posB = gl_in[1].gl_Position.xyz;
    posC = gl_in[2].gl_Position.xyz;

    gl_Position = gl_in[0].gl_Position;
    EmitVertex();
    gl_Position = gl_in[1].gl_Position;
    EmitVertex();
    gl_Position = gl_in[2].gl_Position;
    EmitVertex();
    EndPrimitive();
}

С GS мне не нужно ничего хранить в памяти, я могу нарисовать столько треугольников, сколько захочу, но проблема в том, что используется весь новый этап шейдера.

Я также рассматривал возможность использования ключевого слова flat, но здесь это не подходит.

Вопрос в том, есть ли другие варианты, что-то, что я могу упустить?

Спасибо.

1 3

1 ответ:

Геометрические шейдеры являются наиболее практичным подходом, но это обычно исключает WebGL.

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

Вот модифицированная версия вашего исходного атрибута на основе попытка:

// vertex shader
in int vIdxA; // Index of vtx 0 in current triangle
in int vIdxB; // Index of vtx 1 in current triangle
in int vIdxC; // Index of vtx 2 in current triangle

out vec3 posA;
out vec3 posB;
out vec3 posC;

uniform samplerBuffer vtx_buf; // Actual vertex position array, as a buffer texture

void main() {
    int vtx = gl_VertexID % 3;

    // ....
    posA = texelFetch (vtx_buf, vIdxA);
    posB = texelFetch (vtx_buf, vIdxB);
    posC = texelFetch (vtx_buf, vIdxC);

    if (vtx == 0)
        gl_Position = posA;
    else if (vtx == 1)
        gl_Position = posB;
    else
        gl_Position = posC;
}

Как реализовано, это также исключает WebGL, но должно быть проще адаптировать этот подход к OpenGL ES, чем что-то основанное на геометрическом шейдере.