编辑 - 为了帮助澄清问题,我想我正在寻找哪种排序会更好:按程序排序还是按纹理排序?这有关系吗?我的所有对象都在相似的z空间中,并且都存储在同一个VBO中。如果我不通过glUseProgram切换着色器,我是否必须为每个对象重新设置属性?
原帖:
这是一个由两部分组成的问题。我试图弄清楚在绘制它们之前如何最好地对我的3d对象进行排序,以及每个glDrawElements必须完成哪些open gl调用以及每次刷新屏幕时可以完成哪些操作(甚至只需一次)。目的当然是速度。对于我的游戏,让我们假设z从前到后都不是一个大问题(大多数对象都在同一个z)。所以除了最后做透明度的所有对象之外,我不会为z排序。
当然,我不希望排序过程花费的时间比渲染未分类要长。
第2部分是每个glDrawElements必须使用哪些open gl调用,哪些只能在信息发生变化时才能使用?而且,presentRenderbuffer会清除某些内容,因此您必须重新调用它们。
大多数opengl 2演示都会对每个对象进行每次调用。实际上大多数演示只画了一个对象。所以在3d引擎中(比如我写作)我想避免不必要的冗余调用。
这是我正在做的命令(未分类,未经优化):
glUseProgram(glPrograms[useProgram]);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
Loop through objects {
Do all matrix calcs
Set Uniforms (matrix, camera pos, light pos, light colors, material properties)
Activate Textures.. (x2)
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture0);
glUniform1i(glUniforms[useProgram][U_textureSampler], 0);
Bind VBOs
glBindBuffer(GL_ARRAY_BUFFER, modelVertVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelIndVBO);
Set Attributes (vertexpos, texcoord, norm, tan, bitan)
glDrawElements(GL_TRIANGLES, models[modelToUse].indSize, GL_UNSIGNED_INT, (void *) (models[modelToUse].indOffset * sizeof(GLuint)));
}
当然,只有当所有对象使用相同的着色器/程序时才有效。在实践中,他们赢了。
3D对象是一个数组,其中包含每个对象的所有属性:模型ID,着色器ID,纹理ID,位置等。所以我的想法是进行快速简单的排序以堆叠类似的对象'其他数组中的索引号。然后在每个阵列中绘制项目。我可以按3D模型(对象类型),纹理或着色器排序。许多模型共享相同的纹理。许多模型共享相同的着色器。此时我有3个着色器。所有对象共享一个VBO。
我可以这样做吗?
Bind the VBO - since all objects use the same one
Loop through object types {
If shader hasn't changed
glUseProgram
Set Attributes
If texture hasn't changed
glActiveTexture(s) - based on which program is active
Loop through objects of that type {
Do matrix calcs
Set Uniforms - based on which program is active
glDrawElements
}
}
编辑 - 要清楚 - 我还在绘制所有对象,只是以不同的顺序组合着色器和/或纹理的使用,以避免绑定,然后在一帧内再次重新绑定&# 39;游戏。
我目前在第二次刷新时遇到glDrawElements崩溃,但我认为这很容易找到。我只包含这个事实,因为它让我认为绑定纹理可能不会延续到第二帧(或presentBuffers)。
避免更改着色器或更改纹理会更快吗?在多个glDrawElement调用中,属性,vbo和纹理是否保持活动状态?跨多个presentBuffers?
答案 0 :(得分:0)
回答我自己的问题。
首先是一些背景。我目前有3个着色器,并期望我最终不会超过4或5.示例我有一个使用基本和普通纹理的凹凸贴图着色器。我还有一个不使用基础纹理的着色器,而是使用纯色作为对象,但仍然具有普通纹理。然后我有相反的,一个仅使用基本纹理的平面照明简单着色器。
我有许多不同的3D模型,但都使用相同的VBO。有些3D模型使用与其他模型相同的纹理。
所以在3d对象的定义中,我添加了一个renderSort属性,我可以预设它知道它使用什么着色器程序以及它需要什么样的纹理。
然后当我更新对象并确定它们是否需要在屏幕上绘制时,我还根据它们的3d对象类型的renderSort属性对它们进行一次简单排序...我只是抛出数组的索引'bucket'数组中的对象。我看不到有超过10个桶。
更新后快速排序我渲染。
渲染遍历存储桶,并通过每个存储桶中的对象进行迭代。在内部循环内部,我检查程序是否自上一个对象以来已经改变,并且如果它被改变则执行glUseProgram。与纹理相同..如果它们当前没有绑定,我只绑定它们。然后更新所有其他制服并执行glDrawElements。
以前的方式..未排序..如果有1000个对象,它会调用glUseProgram,绑定纹理,绑定vbo,设置所有属性.. 1000次。
现在..它只在需要时改变这些东西..如果它需要1000次,它仍然会做1000次。但是对于桶的排序,它应该只需要每桶一次。这样,即使它们没有正确分类,我也会优先正确绘图。
以下是代码:
排序...
if (drawThisOne) {
// if an object needs to be drawn - toss it in a sort bucket.
// each itemType has a predetermined bucket number so that objects will be grouped into rough program and texture groups
int itemTypeID = allObjects[objectIndex].itemType;
int bucket = itemTypes[itemTypeID].renderSort;
sorted3dObjects[bucket][sorted3Counts[bucket]]=objectIndex;
// increment the count for that bucket
sorted3Counts[bucket]++;
}
渲染...
// only do these once per cycle as all objects are in the same VBO
glBindBuffer(GL_ARRAY_BUFFER, modelVertVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelIndVBO);
for (int bucket=0; bucket<10; bucket++) {
// does this bucket have anything in it?
if (sorted3Counts[bucket]>0) {
// if so itterate though items in that bucket
for (int thisObject=0; thisObject < sorted3Counts[bucket]; thisObject++) {
// get the object index for this object in this bucket
int objectIndex = sorted3dObjects[bucket][thisObject];
int itemTypeID = candyPieces[objectIndex].pieceType;
int modelToUse = itemTypes[itemTypeID].model;
// switching to psudocode...
GLuint useProgram = itemTypes[itemTypeID].shader;
if (Program Changed or is not set) {
glUseProgram(glPrograms[useProgram]);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
currentProgram=useProgram;
USE glVertexAttribPointer to set all attributes
}
// based on which program is active set textures and program specific uniforms
switch (useProgram) { ....
if (Texture Changed or is not set) {
glActiveTexture(s)
}
}
Matrix Calculations
glUniform - to set unforms
glDrawElements(GL_TRIANGLES, models[modelToUse].indSize, GL_UNSIGNED_INT, (void *) (models[modelToUse].indOffset * sizeof(GLuint)));
}}}