Рисование с использованием VAO с несколькими VBO и IBO (несколько объектов) OpenGLES 2 на iOS

У меня есть некоторая путаница с использованием VAO (объект массива вершин) для нескольких объектов (около 200 объектов, 15 из которых видимы одновременно, каждый из которых имеет свою собственную вершину и буфер индекса). Ниже моя функция рендеринга

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
 {

glClearColor(0.50f, 0.50f, 0.50f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

[super drawLines];


for(int i=0; i< self.numberofBars; i++) //numberofBars

{

    // Render the object

    [self.barShaderProg use];

    iVBarNode *temp = [theBars objectAtIndex:i];

    _modelViewProjectionMatrix = GLKMatrix4Multiply(ProjectionView, modelMatrix);
    _modelViewProjectionMatrix =  GLKMatrix4Multiply(_modelViewProjectionMatrix, temp.modelMatrix);
    GLKMatrix4 modeltotalMatrix = GLKMatrix4Multiply(modelMatrix, temp.modelMatrix);
    GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(ViewMatrix, modeltotalMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);


    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0,_normalMatrix.m);//
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MATRIX], 1, 0, modelViewMatrix.m);

    glUniform4f(uniforms[COLOR_VECTOR], temp.barColor.r, temp.barColor.g, temp.barColor.b, temp.barColor.a);

    //bind corresponding buffer before drawing
    glBindBuffer(GL_ARRAY_BUFFER, [temp getVertexID]);


    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(12));


    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [temp getIndexID]);
    glDrawElements(GL_TRIANGLES, [temp.bar getIndicesSize], GL_UNSIGNED_SHORT, (void*)0); 
}


if(self.translation>0)
{
    self.paused = NO;

}
else{
    self.paused = YES;
} 
}

Это прекрасно работает. После анализа моего кода в анализаторе OpenGLES он показал, что для получения выгоды от них можно использовать VAO, поскольку вызовы glVertexAttribPointer были избыточными (одинаково для всех). Но я просто не могу понять, можно ли их использовать с разными объектами буфера вершин. Большинство примеров, которые я нашел в Интернете, используют их только с одним VBO или двумя VBO, где второй VBO определяет другой атрибут, а не тот же атрибут, что и в моем случае. Я попытался привязать каждый индекс буфера вершин, который я генерировал для своего объекта с одним VAO, но он не работал, как показано ниже

-(void) configureVertexArrayObject

{

// Create and bind the vertex array object.

glGenVertexArraysOES(1,&vertexArrayObject);

glBindVertexArrayOES(vertexArrayObject);

for(int i=0;i<self.numberofBars;i++)
{
    iVBarNode *myNode = [theBars objectAtIndex:i];

 glBindBuffer(GL_ARRAY_BUFFER, [myNode getVertexID]);
// Configure the attributes in the VAO
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), BUFFER_OFFSET(12));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, [myNode getIndexID]);

}

// Bind back to the default state.

glBindBuffer(GL_ARRAY_BUFFER,0);

glBindVertexArrayOES(0);

}

вот как я рендер

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{

glClearColor(0.50f, 0.50f, 0.50f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

[super drawLines];

glBindVertexArrayOES(vertexArrayObject);

for(int i=0; i< self.numberofBars; i++) //numberofBars

{

    // Render the object

    [self.barShaderProg use];

    iVBarNode *temp = [theBars objectAtIndex:i];

    _modelViewProjectionMatrix = GLKMatrix4Multiply(ProjectionView, modelMatrix);
    _modelViewProjectionMatrix =  GLKMatrix4Multiply(_modelViewProjectionMatrix, temp.modelMatrix);
    GLKMatrix4 modeltotalMatrix = GLKMatrix4Multiply(modelMatrix, temp.modelMatrix);
    GLKMatrix4 modelViewMatrix = GLKMatrix4Multiply(ViewMatrix, modeltotalMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);


    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0,_normalMatrix.m);//
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEW_MATRIX], 1, 0, modelViewMatrix.m);

    glUniform4f(uniforms[COLOR_VECTOR], temp.barColor.r, temp.barColor.g, temp.barColor.b, temp.barColor.a);

    //all buffer associated with VAO now

    glDrawElements(GL_TRIANGLES, [temp.bar getIndicesSize], GL_UNSIGNED_SHORT, (void*)0); 
}

  glBindVertexArrayOES(0);

 if(self.translation>0)
 {
     self.paused = NO;


 }
  else{
    self.paused = YES;

 }


}

Во второй попытке я попытался указать только макет для VAO, используя glVertexAttribPointer () для вершин и нормалей (без указания идентификаторов VBO и IBO), и выполнить рендеринг, как я делал без VAO (первый код рендеринга выше), но теперь я не указывал макет вершин с помощью glVertexAttribPointer (), поскольку я уже упоминал об этом в VAO (на самом деле, это был весь смысл использования VAO). Оба этих подхода дали мне объекты одинакового размера, заставив меня подумать, что каким-то образом VAO дублирует геометрию для всех моих объектов. Все мои объекты имеют одинаковую геометрию, но разную высоту. Теперь у меня есть один вариант - иметь одну вершину и объект буфера индекса, и я могу масштабировать по высоте и позиционировать объекты в зависимости от того, что мне нужно. Тем не менее, я хотел бы знать, что на самом деле содержит VAO, а что нет, и есть ли способ заставить его работать.


person OpenGLESbeginner    schedule 14.11.2012    source источник


Ответы (1)


После анализа моего кода в анализаторе OpenGLES он показал, что для получения выгоды от них можно использовать VAO, поскольку вызовы glVertexAttribPointer были избыточными (одинаково для всех).

Если ваш glBindBuffer вызов не связывает каждый раз один и тот же буфер, я считаю это рассуждение сомнительным.

Вы получите от этого больше, упаковав все свои объекты в тот же буфер и, таким образом, выполняя вызовы bind + glVertexAttribPointer один раз при рисовании. Поскольку все ваши объекты имеют один и тот же формат вершин, похоже, нет причин, по которым вы не можете просто сделать это. Вам нужно будет настроить индексы вершин, чтобы выбрать правильные места в теперь более крупном буфере, но это не так уж сложно.

person Nicol Bolas    schedule 14.11.2012
comment
Я очень уверен, что glBindBuffer не привязывает один и тот же буфер каждый раз, когда я проверял дескрипторы буфера (как для индекса, так и для буфера вершин). Они начинаются с 1 и увеличиваются по мере того, как я связываю новую вершину или буфер индекса, пока все мои объекты не будут выполнены. Что касается второй части вашего ответа, вместо упомянутого вами подхода, я думаю, лучше использовать одни и те же VBO и IBO для каждого объекта, где я могу просто разместить их где угодно с разными размерами, используя modelMatrix. - person OpenGLESbeginner; 15.11.2012
comment
На самом деле glBindBuffer(GL_ARRAY_BUFFER... ничего не связывает, он просто устанавливает глобальную переменную open GL как «текущую», фактическая загрузка происходит, когда вы вызываете glVertexAttribPointer(GLKVertexAttribNormal. Каждый из вызовов цикла for отменяет предыдущий атрибут вершины. Либо используйте один VBO, либо несколько VAO - по одному на объект (см. stackoverflow.com/questions/8862578/) - person Vinzzz; 01.02.2013