Я помещаю объект в позиции, рассчитанные в вычислительном шейдере. Я хочу связать выходные данные вычислительного шейдера, содержащего позиции, с буфером массива для рисования, но я не могу заставить его работать. Я извиняюсь за арифметику индекса, я стал супер параноиком по поводу выравнивания памяти и отбросил все векторы.
Соответствующий код упрощен:
Инициализация:
//x, y, z, 1 stored in succession
/*float*/positions = new float[maxPositionCount * 4];
//initialize positions_vbo
glGenBuffers(1, &position_vbo);
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//initialize positionsOUT_ssbo
glGenBuffers(1, &positionsOUT_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, positionsOUT_ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * maxPositionCount * sizeof(float), NULL, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, positionsOUT_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
//initialize positionCounter
glGenBuffers(1, &positionCount_acb);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, positionCount_acb);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
Draw Loop:
//initialize the counter
posCount = 0;
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &posCount);
//send other data to compute shader in order to calculate positions
//dispatch and wait
//....
//retrieve the counter
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, positionCount_acb);
glGetBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), &positionCount_acb);
//retrieve the positions (1)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, positionsOUT_ssbo);
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float), positions);
//bind position_vbo (2)
glBindBuffer(GL_ARRAY_BUFFER, position_vbo);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(float) * posCount, posCount > 0 ? &positions[0] : NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glVertexAttribDivisor(2, 1);
//instead of (1)+(2) I would like to know if something like this is possible
//glBindBuffer(GL_ARRAY_BUFFER, positionsOUT_ssbo);
//glEnableVertexAttribArray(2);
//glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
//glVertexAttribDivisor(2, 1);
//bind vertex array and draw the object instances
glBindVertexArray(vertexArrayOfTheObjectImDrawing);
glDrawElementsInstanced(GL_TRIANGLES, objectSharedVertexCount, GL_UNSIGNED_SHORT, 0, posCount);
вычислить шейдер:
layout(local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
//just in case they are relevant somehow
//can set and get them fine but they have fixed size (maxPositionCount)
//---------v
layout(std430, binding=4) buffer A {
int a[ ];
};
layout(std430, binding=5) buffer B {
int b[ ];
};
layout(std430, binding=6) buffer C {
int c1,c2,c3,c4,c5;
};
//----------^
layout(binding = 7, offset = 0) uniform atomic_uint returnedPositionsIndex;
layout(std430, binding=8) buffer pos_Out
{
float positionsOUT[ ];
};
void main()
{
ivec3 currentPos = gl_GlobalInvocationID.xyz;
if (I_want_that_position_returned(currentPos))
{
uint i = atomicCounterIncrement(returnedPositionsIndex);
positionsOUT[i * 4 + 0] = float(index3D.x);
positionsOUT[i * 4 + 1] = float(index3D.y);
positionsOUT[i * 4 + 2] = float(index3D.z);
positionsOUT[i * 4 + 3] = 1.0;
}
}
вершинный шейдер:
uniform mat4 worldViewProjection;
layout(location = 1) in vec4 vertPosition;
layout(location = 2) in vec4 position;
int main() {
gl_Position = worldViewProjection * (vertPosition + position);
}
В настоящее время он падает на
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float), positions);
звоните, даже если это единственная незакомментированная строка в программе. Ошибка отладки:
Exception thrown at 0x0000000001A132A9 (atio6axx.dll) in asd.exe:
0xC0000005: Access violation writing location 0x0000000000000000.
Я попытался инициализировать данные, вызвав glBufferData (… позиции) заранее. Атомный счетчик получен с правильным счетом. Кроме того, есть ли способ отправить данные позиции из позиции OUT_ssbo без копирования и привязки к позициям_vbo?
РЕДАКТИРОВАТЬ: Исправлен сбой, повторно объявленные переменные «позиции» при инициализации ..
EDIT2: строки, которые я прокомментировал выше, действительно способ «привязать» содержимое ssbo прямо к буферу массива. Если есть лучший способ, пожалуйста, не стесняйтесь поделиться.
Ну, это было стыдно. Я повторно объявил положения переменных класса в фазе инициализации, затеняя одно в цикле рисования. Работает нормально сейчас. Спасибо, что указал мне правильное направление!
Основываясь на вашем комментарии, я воспроизвел мой оригинальный комментарий ниже в качестве ответа.
Я вижу, что у вас есть float* positions = new float[maxPositionCount * 4];
но я никогда не вижу, когда значения фактически добавляются в этот массив, так что, насколько я могу судить, это неинициализированный блок памяти.
Вы тогда звоните glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, posCount * 4 * sizeof(float), positions);
который отправляет этот неинициализированный блок памяти, который может быть установлен на ноль, и объясняет, почему вы получаете Access violation writing location 0x0000000000000000.
ошибка.
Других решений пока нет …