【发布时间】:2022-08-18 01:04:30
【问题描述】:
我创建了一个 obj 模型解析器,并决定按照 http://opengl-tutorial.org 的教程进行操作,但是法线和顶点的解析无法正常工作。我决定稍微更改一下代码,看看会发生什么并可能修复它,但是当我这样做时,输出的顶点完全改变了它们之前的样子。然后我注意到我在循环中犯了一个错误,我修复了它,使顶点与以前一样,但只有正面正确渲染。我不知道我做错了什么,我似乎无法充分理解索引是如何工作的。这是代码,仅正确呈现正面(这只是顶点,法线的代码以相同的方式工作。):
for(i = 0; i < vertexsize; i += 3){
verticesind[i] = verticesout[vertexindices[i] - 1];
verticesind[i + 1] = verticesout[vertexindices[i + 1] - 1];
verticesind[i + 2] = verticesout[vertexindices[i + 2] - 1];
verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + sizeof(vertices[i + 2]);
}
对于任何想知道这是 model.obj 文件的人:
# Blender v2.93.8 OBJ File: \'\'
# www.blender.org
o Cube
v 0.500000 0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
v 0.500000 0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v -0.500000 0.500000 0.500000
v -0.500000 -0.500000 0.500000
vt 0.875000 0.500000
vt 0.625000 0.750000
vt 0.625000 0.500000
vt 0.375000 1.000000
vt 0.375000 0.750000
vt 0.625000 0.000000
vt 0.375000 0.250000
vt 0.375000 0.000000
vt 0.375000 0.500000
vt 0.125000 0.750000
vt 0.125000 0.500000
vt 0.625000 0.250000
vt 0.875000 0.750000
vt 0.625000 1.000000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
s off
f 5/1/1 3/2/1 1/3/1
f 3/2/2 8/4/2 4/5/2
f 7/6/3 6/7/3 8/8/3
f 2/9/4 8/10/4 6/11/4
f 1/3/5 4/5/5 2/9/5
f 5/12/6 2/9/6 6/7/6
f 5/1/1 7/13/1 3/2/1
f 3/2/2 7/14/2 8/4/2
f 7/6/3 5/12/3 6/7/3
f 2/9/4 4/5/4 8/10/4
f 1/3/5 3/2/5 4/5/5
f 5/12/6 1/3/6 2/9/6
顶部三角形之一应该是
-0.5, 0.5, -0.5,
0.5, 0.5, 0.5,
0.5, 0.5, -0.5
这导致了一个完整的三角形,但由于某种原因,它们在最终结果中被打乱了,同一个三角形变成了
-0.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
0.5, -0.5, 0.5
这是我的函数的完整代码(我认为在正确加载 obj 文件时不需要它,但它仍可用于检查我如何保存值):
int load_obj(const char* filename, float* vertices, float* texcoords, float* normals, unsigned int* vertexindexsize, unsigned int* texcoordindexsize, unsigned int* normalindexsize){
FILE* file = fopen(filename, \"r\");
char lineheader[128];
int res;
int i = 0;
int f = 0;
int d = 0;
int g = 0;
unsigned int vertexsize = 0;
unsigned int texcoordsize = 0;
unsigned int normalsize = 0;
unsigned int verticessize = 0;
unsigned int texturecoordsize = 0;
unsigned int normalssize = 0;
float verticesout[500];
float texcoordsout[500];
float normalsout[500];
float verticesind[500];
float texturecoordsind[500];
float normalsind[500];
unsigned int vertexindex[3];
unsigned int texindex[3];
unsigned int normalindex[3];
vec3 vertex;
vec2 texcoord;
vec3 normal;
int vertexindices[500];
int texindices[500];
int normalindices[500];
if(file == NULL){
printf(\"Failed to open file!\\n\");
return 1;
}
while(1){
res = fscanf(file, \"%s\", lineheader);
if(res == EOF){
break;
}
if(strcmp(lineheader, \"v\") == 0){
fscanf(file, \"%f %f %f\\n\", &vertex[0], &vertex[1], &vertex[2]);
verticesout[i] = vertex[0];
verticesout[i + 1] = vertex[1];
verticesout[i + 2] = vertex[2];
i += 3;
}else if(strcmp(lineheader, \"vt\") == 0){
fscanf(file, \"%f %f\\n\", &texcoord[0], &texcoord[1]);
texcoordsout[f] = texcoord[0];
texcoordsout[f + 1] = texcoord[1];
f += 2;
}else if(strcmp(lineheader, \"vn\") == 0){
fscanf(file, \"%f %f %f\\n\", &normal[0], &normal[1], &normal[2]);
normalsout[d] = normal[0];
normalsout[d + 1] = normal[1];
normalsout[d + 2] = normal[2];
d += 3;
}else if(strcmp(lineheader, \"f\") == 0){
fscanf(file, \"%d/%d/%d %d/%d/%d %d/%d/%d\\n\", &vertexindex[0], &texindex[0], &normalindex[0], &vertexindex[1], &texindex[1], &normalindex[1], &vertexindex[2], &texindex[2], &normalindex[2]);
vertexindices[g] = vertexindex[0];
vertexindices[g + 1] = vertexindex[1];
vertexindices[g + 2] = vertexindex[2];
vertexsize += 3;
texindices[g] = texindex[0];
texindices[g + 1] = texindex[1];
texindices[g + 2] = texindex[2];
texcoordsize += 3;
normalindices[g] = normalindex[0];
normalindices[g + 1] = normalindex[1];
normalindices[g + 2] = normalindex[2];
normalsize += 3;
g += 3;
}
}
for(i = 0; i < vertexsize; i += 3){
verticesind[i] = verticesout[vertexindices[i] - 1];
verticesind[i + 1] = verticesout[vertexindices[i + 1] - 1];
verticesind[i + 2] = verticesout[vertexindices[i + 2] - 1];
verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + sizeof(vertices[i + 2]);
}
for(i = 0; i < texcoordsize; i++){
texturecoordsind[i] = texcoordsout[texindices[i] - 1];
texturecoordsize += sizeof(texturecoordsind[i]);
}
for(i = 0; i < normalsize; i += 3){
normalsind[i] = normalsout[normalindices[i] - 1];
normalsind[i + 1] = normalsout[normalindices[i + 1] - 1];
normalsind[i + 2] = normalsout[normalindices[i + 2] - 1];
normalssize += sizeof(normalsind[i]) + sizeof(normalsind[i + 1]) + sizeof(normalsind[i + 2]);
}
memcpy(vertices, verticesind, sizeof(verticesind));
memcpy(texcoords, texturecoordsind, sizeof(texturecoordsind));
memcpy(normals, normalsind, sizeof(normalsind));
*vertexindexsize = verticessize;
*texcoordindexsize = texturecoordsize;
*normalindexsize = normalssize;
return 0;
}
-
verticessize += sizeof(verticesind[i]) + sizeof(verticesind[i + 1]) + ...您是否希望数组的不同元素具有不同的大小?他们没有。 -
您应该始终检查
scanf和朋友的返回值以获取预期值。 -
为了获得更好的可测试性,您可以删除加载文件的部分并配置示例中硬编码的值。这也将验证阅读真的是正确的。
-
我检查了 fscanf 返回值,每次都是正确的。正如我所说,问题不在于代码部分,我从文件中获取值,而在于代码部分,我尝试解析顶点和法线及其索引文件。
-
我遇到的代码的第一个问题是您处理 cmets 的方式。每当找到 # 字符时,将忽略该行的其余部分。问题是,您不会一次阅读整行。所以,如果你注释掉一个 vert 行,你仍然会读到 8 个 verts。相反,您可以阅读整行,将其拆分为 \' \' 字符,然后检查从 strtok 返回的数组的第一个元素是否是 o、v、vt、vn、s 或 f,然后再相应地处理该行。当您遇到 # 字符时,您可以立即丢弃该行的其余部分。