我正在尝试学习OpenGL ES 2.0来做一些iPhone游戏开发.我已经阅读了多个教程和一些OpenGL ES 2.0规范.我见过的所有例子都创建了一个网格,将其加载到顶点缓冲区然后渲染它(带有预期的平移,旋转,渐变等)
我的问题是:如何渲染场景中具有不同网格并独立移动的多个对象?如果我有一辆汽车和一辆摩托车,我可以创建2个顶点缓冲区并为每个渲染调用保留两个网格数据,然后为每个对象发送不同的着色器矩阵吗?或者我是否需要以某种方式转换网格然后将它们组合成一个网格,以便它们可以一次渲染?我正在寻找更多的高级策略/程序结构而不是代码示例.我想我的错误心理模式是如何运作的.
谢谢!
Ton*_*ony 12
我发现这样做的最好方法是使用除VBO之外的VAO.
我将首先使用VBO回答您的问题.
首先,假设您将两个对象的两个网格存储在以下数组中:
GLuint _vertexBufferCube1;
GLuint _vertexBufferCube2;
Run Code Online (Sandbox Code Playgroud)
哪里:
GLfloat gCubeVertexData1[36] = {...};
GLfloat gCubeVertexData2[36] = {...};
Run Code Online (Sandbox Code Playgroud)
而且你还必须使用vertix缓冲区:
GLuint _vertexBufferCube1;
GLuint _vertexBufferCube2;
Run Code Online (Sandbox Code Playgroud)
现在,要绘制这两个立方体(没有VAO),你必须做类似的事情:在绘图函数中(来自OpenGLES模板):
//Draw first object, bind VBO, adjust your attributes then call DrawArrays
glGenBuffers(1, &_vertexBufferCube1);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferCube1);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData1), gCubeVertexData1, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glDrawArrays(GL_TRIANGLES, 0, 36);
//Repeat for second object:
glGenBuffers(1, &_vertexBufferCube2);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferCube2);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData2), gCubeVertexData2, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glUseProgram(_program);
glDrawArrays(GL_TRIANGLES, 0, 36);
Run Code Online (Sandbox Code Playgroud)
这将回答你的问题.但是现在要使用VAO,你的绘制函数代码要简单得多(这很好,因为它是重复的函数):
首先,您将定义VAO:
GLuint _vertexArray1;
GLuint _vertexArray2;
Run Code Online (Sandbox Code Playgroud)
然后你将完成之前在draw方法中完成的所有步骤,你将在setupGL函数中完成但在绑定到VAO之后.然后在您的绘图功能中,您只需绑定到您想要的VAO.
这里的VAO就像一个包含很多属性的配置文件(想象一下智能设备配置文件).每次要更改它们时,不要更改颜色,桌面,字体等,而是一次性将其保存在配置文件名称下.然后你只需切换配置文件.
所以你在setupGL中做了一次,然后你在draw中切换它们.
当然,您可以说您可以将代码(没有VAO)放入函数中并调用它.这是事实,但据Apple称,VAO的效率更高:
现在到代码:
在setupGL中:
glGenVertexArraysOES(1, &_vertexArray1); //Bind to first VAO
glBindVertexArrayOES(_vertexArray1);
glGenBuffers(1, &_vertexBufferCube1); //All steps from this one are done to first VAO only
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferCube1);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData1), gCubeVertexData1, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glGenVertexArraysOES(1, &_vertexArray2); // now bind to the second
glBindVertexArrayOES(_vertexArray2);
glGenBuffers(1, &_vertexBufferCube2); //repeat with the second mesh
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferCube2);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData2), gCubeVertexData2, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBindVertexArrayOES(0);
Run Code Online (Sandbox Code Playgroud)
最后在你的绘制方法中:
glBindVertexArrayOES(_vertexArray1);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArrayOES(_vertexArray2);
glDrawArrays(GL_TRIANGLES, 0, 36);
Run Code Online (Sandbox Code Playgroud)
Tay*_*orP 10
您为不同的对象维护单独的顶点/索引缓冲区,是的.例如,您可能有一个RenderedObject类,每个实例都有自己的顶点缓冲区.一个RenderedObject可能从房屋网格中获取它的顶点,一个可能来自角色网格等.
在渲染过程中,为您正在使用的顶点缓冲区设置适当的变换/旋转/着色,可能类似于:
void RenderedObject::render()
{
...
//set textures/shaders/transformations
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
...
}
Run Code Online (Sandbox Code Playgroud)
正如其他答案所述,bufferID只是一个GLuint而不是缓冲区的全部内容.如果您需要有关创建顶点缓冲区和填充数据的更多详细信息,我很乐意添加它们.
| 归档时间: |
|
| 查看次数: |
18266 次 |
| 最近记录: |