Как нарисовать TRIANGLE_FAN с координатами, созданными геометрическим шейдером? (GLSL 3.3)

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

Следующий геометрический шейдер работает, как и ожидалось, с точками как на входе, так и на выходе:

uniform mat4 VP;
uniform mat4 sharedModelMatrix;

const int STATE_VERTEX_NUMBER = 38;

layout (shared) uniform stateShapeData {
    vec2 data[STATE_VERTEX_NUMBER];
};

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

void main(void)
{
    int i;
    mat4 modelMatrix = sharedModelMatrix;
    modelMatrix[3]   = gl_in[0].gl_Position;
    mat4 MVP = VP * modelMatrix;

    gl_Position = MVP * vec4( 0, 0 , 0, 1 );
    EmitVertex(); // epicenter

    for (i = 37; i >= 0; i--) {
        gl_Position = MVP * vec4( data[i], 0, 1 );
        EmitVertex();
     }

     gl_Position = MVP * vec4( data[0], 0, 1 );
     EmitVertex();
}

Я пытался запустить это с glDrawElements, glDrawArrays и glMultiDrawArrays. Ни одна из этих команд не рисует полный веер. Каждый рисует первый заполненный треугольник и остальные вершины как точки.

Итак, нижний вопрос: можно ли нарисовать веер с вершинами, созданными GS, и как?


person user3054986    schedule 24.02.2015    source источник


Ответы (1)


Вывод вееров в геометрическом шейдере, как вы уже заметили, очень неестественен.

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

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

void main(void)
{
    int i;
    mat4 modelMatrix = sharedModelMatrix;
    modelMatrix[3]   = gl_in[0].gl_Position;
    mat4 MVP = VP * modelMatrix;

    for (i = 37; i >= 0; i--) {
        gl_Position = MVP * vec4( 0, 0 , 0, 1 );
        EmitVertex(); // epicenter

        gl_Position = MVP * vec4( data[i], 0, 1 );
        EmitVertex();

        gl_Position = MVP * vec4( data[i-1], 0, 1 );
        EmitVertex();

        // Fan and strip DNA just won't splice
        EndPrimitive ();
     }
}

Вы не можете использовать порядок полос при рисовании таким образом; вам придется заканчивать выходной примитив (полосу) несколько раз. Единственное возможное преимущество, которое вы получаете при рисовании веерным порядком, — это локальность кеша внутри цикла. Если вы понимаете, что геометрические шейдеры должны выводить полосы треугольников, почему бы не упорядочить входные вершины таким образом для начала?

person Andon M. Coleman    schedule 25.02.2015
comment
Поскольку я предоставляю только 1 полезную вершину в качестве входных данных для GS, а опция TRIANGLE_FAN интерпретируется во время сборки примитивов между VS и GS, а не так, как я предполагал после GS, в моем случае эта опция менее эффективна. Это привело бы к выводу, что примитивная сборка просто сконструирует вентилятор с треугольной полосой, и единственным преимуществом будет передача данных от ЦП к ГП. Выход GS будет одинаковым, если он построен с помощью TRIANGLE_FAN или TRIANGLE_STRIP, правильно? - person user3054986; 26.02.2015
comment
@ user3054986: Правильно. GL_TRIANGLE_FAN будет для входного примитивного типа. Я бы пошел дальше и упорядочил вершины, которые вы выводите в своем геометрическом шейдере, как полосу и вообще проигнорировал попытки сделать это как веер. Однако, судя по вашему описанию, ваш тип ввода на самом деле должен быть points (1 вершина испускает много треугольников), а не triangles. - person Andon M. Coleman; 26.02.2015
comment
Я также использую обратную связь по преобразованию, поэтому очки не вариант. (Я добавляю цвет и коэффициент масштабирования в оставшиеся 2 вершины.). Я также хочу отметить, что, помимо локальности кеша, мы НЕ должны создавать MVP для каждой вершины, а только один раз для каждого эллипса. - person user3054986; 26.02.2015