Как ограничить испущенные вершины с помощью Geometry shader с использованием обратной связи Transform?

Я работаю над простой системой Particle в OpenGL, и мне нужно генерировать частицы на графическом процессоре. Обычно я представляю частицы как GL_POINTS и использую только одну генераторную точку частиц в начале. Что я делаю, так это то, что я создаю два буфера Vertex Objects (VBO) и выделяю память на GPU в зависимости от Максимальное количество частиц. Затем создайте два Transform Feedback Buffers (TFB), и каждый из них привязан к выходу одного VBO. Первый TFB представляет вход для второго VBO и наоборот (буферы заменяются).

Затем я генерирую новые вершины (= точки, частицы) в шейдере Geometry.

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

#version 330 compatibility

#extension GL_ARB_geometry_shader4 : enable

layout(points) in;
layout(points, max_vertices = 3) out;

in block{
  vec4 v_WorldPosition;

  vec3 f_Position;
  vec3 f_Color;  
} In[];

out block{
  vec4 v_WorldPosition;
  vec4 v_Color;
} Out;

out feedback{
  vec3 f_Position; 
  vec3 f_Color;  
} feedOut;


const int i = 0; // No need for loop (points. In.length() == 1)

void main()
{  
    feedOut.f_Position = In[i].f_Position; 
    feedOut.f_Color    = In[i].f_Color; 

    if(In[i].f_Color.g == 1){
        feedOut.f_Color.g = 0;
    }

    Out.v_Color = vec4(feedOut.f_Color, 1);
    gl_Position = In[i].v_WorldPosition; 

    EmitVertex();
    EndPrimitive();

    if(In[i].f_Color.g == 1){
        // create new particle
        feedOut.f_Position  = In[i].f_Position; 
        feedOut.f_Color     = vec3(1,0,0);

        Out.v_Color = vec4(feedOut.f_Color, 1);
        gl_Position = In[i].v_WorldPosition;

        EmitVertex();
        EndPrimitive();
    }
  }
}

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

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

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

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

Есть ли способ предотвратить переопределение? Мне нужны, чтобы новые частицы на самом деле не создавались в случае полного буфера и только тогда, когда частица была удалена (= не выбрана) из буфера - новая может быть создан. Это стандартное поведение?

Примечание: Пробовал GeForce GT 630M и GeForce GTX 260 (Windows 7 x64).

Ответ 1

Я думаю, что вам следует сначала прочитать о gl Объекты запроса. Там определен объект запроса для GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN. Из спецификации: Записывает количество примитивов, записанных потоком Geometry Shader, в объект Transform Feedback.

Как только вы выяснили, есть ли слишком много примитивов (или в случае точки, одна вершина, которая может быть цветом и положением, и что когда-либо до вызова вызова EndPrimitive()), вы можете сделать другую функцию обновления обратной связи с преобразованием и соответствующую glsl-прогу, которая имеет ту же структуру, что и та, которая добавляет примитивы, кроме этого, только обновляет то, что у вас уже есть или удаляет текущие. Убедитесь, что вы знаете, какой размер каждого примитива (в данном случае это точка), так что вы можете легко запросить свой размер, чтобы убедиться, что вы не переходите на то, что вы выделили. Кроме того, было бы неплохо дать каждому таймеру, чтобы вы могли легко решить всю жизнь. Подобно тому, что вы делаете в своем вершинном шейдере, чтобы увидеть, должны ли они разделяться, но отличаться тем, что вы проверили бы свою жизнь в геометрическом шейдере и не испустили бы эту вершину, если бы они были мертвы.

Ответ 2

Вы ищете что-то вроде:

//read 
int temp;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &temp);

//write
glProgramParameteriEXT(m_Program, GL_GEOMETRY_VERTICES_OUT_EXT, count);

Ответ 3

В конце концов, я узнал, что забыл отобразить буферный диапазон буфера обратной связи Transform.

glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VBO_id, 0, nMaxParticleBound * sizeof(Particle));

Итак, когда в Geometry shader создаются дополнительные частицы, они не записываются в буфер обратной связи Transform.