你是对的,你必须复制顶点。
除此之外,您必须按绘制顺序对它们进行排序,这意味着您必须对具有与纹理坐标和法线相同的偏移量的顶点进行排序。
基本上你需要这种结构:
float *verts = {v1_x,v1_y,v1_z,v1_w,v2_x,v2_y,v2_z,v2_w,...};
float *normals = {n1_x,n1_y,n1_z,n2_x,n2_y,n2_z,...};
float *texcoords = {t1_u,t1_v,t1_w,t2_u,t2_v,t2_w,...};
然而,这意味着每个三角形至少有 108 个字节。
3(vert,norm,tex)
*3(xyz/uvw)
*3(points in tri)
*4(bytes in a float))
-----------------------
= 108
您可以通过仅复制实际重复的顶点(具有相同的纹理坐标、顶点和法线意味着:平滑法线和无 UV 边界)并使用索引缓冲区对象设置绘制顺序来显着减少该数量。
我最近在一个小项目中遇到了同样的问题,我只是沿着硬边和 UV-Shell 边界分割模型,因此只创建了必要的重复顶点。然后我使用了 Nate Robins 的 glm.h 和 glm.cpp 并以与顶点相同的顺序复制/排序法线和纹理坐标。
然后设置 VBO 和 IBO:
//this is for Data that does not change dynamically
//GL_DYNAMIC_DRAW and others are available
GLuint mDrawMode = GL_STATIC_DRAW;
//////////////////////////////////////////////////////////
//Setup the VBO
//////////////////////////////////////////////////////////
GLuint mId;
glGenBuffers(1, &mId);
glBindBuffer(GL_ARRAY_BUFFER, mId);
glBufferData(GL_ARRAY_BUFFER,
mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize),
0,
mDrawMode);
glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices);
glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals);
glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors);
glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords);
//////////////////////////////////////////////////////////
//Setup the IBO
//////////////////////////////////////////////////////////
GLuint IBOId;
glGenBuffers(1, &IBOId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mMaxNumberOfIndices * sizeof(GLuint), 0, mDrawMode);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numberOfIndicesToStore * sizeof(GLuint), indices);
//////////////////////////////////////////////////////////
//This is how to draw the object
//////////////////////////////////////////////////////////
glBindBuffer(GL_ARRAY_BUFFER, mId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
//Enables and Disables are only necessary each draw
//when they change between objects
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset);
if(mNormalBlockSize){
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset);
}
if(mColorBlockSize){
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset);
}
if(mTexCoordBlockSize){
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset);
}
glDrawRangeElements(primMode,
idFirstVertex,
idLastVertex,
idLastVertex - idFirstVertex + 1,
mAttachedIndexBuffer->getDataType(),
0);
if(mTexCoordBlockSize)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
if(mColorBlockSize)
glDisableClientState(GL_COLOR_ARRAY);
if(mNormalBlockSize)
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);