我第一次在3D项目上工作(实际上,我正在使用Quartz Composer插件编写Bullet Physics集成),当我尝试优化渲染方法时,我开始使用glDrawElements而不是glVertex3d直接访问顶点......
我对结果感到非常惊讶。我没有检查它是否真的更快,但我尝试了下面这个非常简单的场景。而且,从我的角度来看,渲染在立即模式下真的更好。
“绘制元素”方法会持续显示三角形的边缘以及立方体上非常难看的阴影。
我非常感谢有关这种差异的一些信息,并且可能是一种通过glDrawElements保持质量的方法。我知道这真的是地雷的错误......
立即模式
DrawElements
顶点,索引和法线在两种方法中的计算方法相同。这是2个代码。
立即模式
glBegin (GL_TRIANGLES);
int si=36;
for (int i=0;i<si;i+=3)
{
const btVector3& v1 = verticesArray[indicesArray[i]];;
const btVector3& v2 = verticesArray[indicesArray[i+1]];
const btVector3& v3 = verticesArray[indicesArray[i+2]];
btVector3 normal = (v1-v3).cross(v1-v2);
normal.normalize ();
glNormal3f(-normal.getX(),-normal.getY(),-normal.getZ());
glVertex3f (v1.x(), v1.y(), v1.z());
glVertex3f (v2.x(), v2.y(), v2.z());
glVertex3f (v3.x(), v3.y(), v3.z());
}
glEnd();
glDrawElements
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(btVector3), &(normalsArray[0].getX()));
glVertexPointer(3, GL_FLOAT, sizeof(btVector3), &(verticesArray[0].getX()));
glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_BYTE, indicesArray);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
谢谢。
这是顶点/索引/法线的代码
GLubyte indicesArray[] = {
0,1,2,
3,2,1,
4,0,6,
6,0,2,
5,1,4,
4,1,0,
7,3,1,
7,1,5,
5,4,7,
7,4,6,
7,2,3,
7,6,2 };
btVector3 verticesArray[] = {
btVector3(halfExtent[0], halfExtent[1], halfExtent[2]),
btVector3(-halfExtent[0], halfExtent[1], halfExtent[2]),
btVector3(halfExtent[0], -halfExtent[1], halfExtent[2]),
btVector3(-halfExtent[0], -halfExtent[1], halfExtent[2]),
btVector3(halfExtent[0], halfExtent[1], -halfExtent[2]),
btVector3(-halfExtent[0], halfExtent[1], -halfExtent[2]),
btVector3(halfExtent[0], -halfExtent[1], -halfExtent[2]),
btVector3(-halfExtent[0], -halfExtent[1], -halfExtent[2])
};
indicesCount = sizeof(indicesArray);
verticesCount = sizeof(verticesArray);
btVector3 normalsArray[verticesCount];
int j = 0;
for (int i = 0; i < verticesCount * 3; i += 3)
{
const btVector3& v1 = verticesArray[indicesArray[i]];;
const btVector3& v2 = verticesArray[indicesArray[i+1]];
const btVector3& v3 = verticesArray[indicesArray[i+2]];
btVector3 normal = (v1-v3).cross(v1-v2);
normal.normalize ();
normalsArray[j] = btVector3(-normal.getX(), -normal.getY(), -normal.getZ());
j++;
}
答案 0 :(得分:2)
您可以(并且将会)使用立即模式和基于顶点数组的渲染实现完全相同的结果。你的照片表明你的法线错了。由于您没有包含用于创建阵列的代码,因此我只能猜出可能出现的问题。我可以想象的一件事:你在每个三角形使用一个法线,所以在普通数组中,你必须为每个顶点重复该法线。
你应该知道GL中的一个顶点不仅仅是你在立即模式下通过glVertex
指定的位置),而是一组所有属性,如位置,法线,texcoords等。因此,如果你有一个网格,其中一个终点是不同三角形的一部分,如果共享所有属性,这只是一个顶点,而不仅仅是位置。在您的情况下,法线是每个三角形,因此每个三角形需要不同的顶点(与其他顶点共享位置,但使用不同的法线)。
答案 1 :(得分:2)
我开始使用glDrawElements
好!
而不是glVertex3d直接访问顶点...
关于立即模式没有任何“直接”。实际上,它与GPU相差甚远(在现代GPU架构上)。
实际上它的几个数量级更慢。每个glVertex调用都会导致上下文切换的开销。 GPU也需要更大批量的数据才能高效工作,因此glVertex调用首先填充临时创建的缓冲区。我对结果感到非常惊讶。我没有检查它是否真的更快,但我尝试了下面这个非常简单的场景。而且,从我的观点来看,使用直接访问方法渲染真的更好。
您的直接代码段必须实际理解如下
glNormal3f(-normal.getX(),-normal.getY(),-normal.getZ());
glVertex3f (v1.x(), v1.y(), v1.z());
// implicit copy of the glNormal supplied above
glVertex3f (v2.x(), v2.y(), v2.z());
// implicit copy of the glNormal supplied above
glVertex3f (v3.x(), v3.y(), v3.z());
原因是,顶点不仅仅是一个位置,而是它的属性的整个组合。在处理顶点数组时,必须提供完整的属性向量以形成有效的顶点。