我的wavefront .obj加载器存在问题,它没有显示我想要显示的内容。我想让它显示一个立方体,但我一直这样:
这是我的obj文件
# cube.obj
#
g cube
v 0.0 0.0 0.0
v 0.0 0.0 1.0
v 0.0 1.0 0.0
v 0.0 1.0 1.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 1.0 1.0 0.0
v 1.0 1.0 1.0
vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0
vn 0.0 1.0 0.0
vn 0.0 -1.0 0.0
vn 1.0 0.0 0.0
vn -1.0 0.0 0.0
f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1
我在代码中添加了部分以查看是否所有内容都正确存储,顶点和法线存储为GLfloats
这是我的绘图功能: 我不太清楚glDrawArrays中的最后一个参数,它是硬编码的,因为我不太确定索引的数量。
void Draw(void)
{
glPushMatrix();
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef( rotate_x, 1.0, 0.0, 0.0 );
glRotatef( rotate_y, 0.0, 1.0, 0.0 );
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, normals);
glVertexPointer(3, GL_FLOAT,0, vertices);
glDrawArrays(GL_TRIANGLES, 0, (14));
glTranslatef(0, 0, -3);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glFlush();
glutSwapBuffers();
glPopMatrix();
}
这是我的主要观点:
int main(int argc,char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("Object Loader!");
glEnable(GL_DEPTH_TEST);
//glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
GLfloat posLight0[] = {0.0f, 0.0f, -1.0f, 0.0f};
GLfloat lightColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, posLight0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
setUpArrays();
glutDisplayFunc(Draw);
glutSpecialFunc(specialKeys);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
最后一件事是我不允许使用glDrawElements或glBegin()直接模式。
如果有帮助的话,这里有更多我的程序: 全局变量设置在开头
GLfloat* vertices;
GLfloat* normals;
GLint* faces;
int amountOfFaces;
double rotate_y=0;
double rotate_x=0;
Loader* loader = new Loader();
设置顶点,法线和索引的数组:
void setUpArrays()
{
loader->loadObject("cube.obj");
vector<GLfloat> temp = loader->getVerticies();
vertices = new GLfloat[temp.size()];
int tempSize = 0;
cout << "vectors: ";
for(vector<GLfloat>::const_iterator i = temp.begin(); i != temp.end(); ++i)
{
vertices[tempSize] = *i;
cout << vertices[tempSize] << ", ";
tempSize++;
}
cout << endl;
vector<GLfloat> tempNormal = loader->getNormals();
normals = new GLfloat[tempNormal.size()];
tempSize = 0;
cout << "normals: ";
for(vector<GLfloat>::const_iterator i = tempNormal.begin(); i != tempNormal.end(); ++i)
{
normals[tempSize] = *i;
cout << normals[tempSize] << ", ";
tempSize++;
}
amountOfFaces = tempSize;
cout << endl;
vector<GLint> tempIndices = loader->getFaces();
faces = new GLint[tempIndices.size()];
tempSize = 0;
cout << "Indices: ";
for(vector<GLint>::const_iterator i = tempIndices.begin(); i != tempIndices.end(); ++i)
{
faces[tempSize] = *i;
cout << faces[tempSize] << ", ";
tempSize++;
}
cout << endl;
amountOfFaces += tempSize;
}
答案 0 :(得分:3)
我感到困惑的是为什么但是OBJ格式给出了从1开始的顶点属性索引,而不是0。 f 1//2
指的是第一个顶点和第二个法线。你的调试输出并没有显示索引为零,所以我猜测加载器没有考虑到这一点。
有效顶点索引从1开始,并匹配先前定义的顶点列表的相应顶点元素。每个面可以包含三个或更多顶点。 [wikipedia]
希望修复程序非常简单:faces[tempSize] = *i - 1;
[修改]
你的绘制调用指定了14个顶点,但你有12个三角形,所以应该绘制36个。amountOfFaces
听起来应该是tempIndices.size()/3
。
您的向量应该是引用以避免副本,并且使用单个faces
填充memcpy
等会更快。例如:memcpy(faces, &tempIndices.front(), sizeof(GLint) * tempIndices.size())
[修改]
哦,当然,对。现在,我觉得愚蠢的不注意。 Faces索引顶点,因此可以重用它们(节省内存和额外处理)。而不是glDrawArrays
你想要这个:
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, faces); //replate 36 for things you draw that aren't cubes
如果您想使用glDrawArrays
,则必须重新排列顶点数组,以便每个顶点按faces
给出的顺序显示,包括所有重复项。例如,您的新位置数组将[0,0,0, 1,1,0 1,0,0 ...]
为向量0,6,4,形成第一个三角形。 std::vector
使这种重新排列变得容易编码。
最后一件事。法线数组不像位置数组那么大,但OpenGL不支持混合索引。所以你必须复制一些法线,这样每个顶点都有一个位置和正常位置。