我编写了自己的代码来解析.obj模型文件 - 基本上只是ASCII文本。根据我的测试,文件被正确解析并存储在类中。我可以在加载函数中读回值(来自数据成员)。
当我尝试回读主渲染循环中的值时,会出现问题。从“int v”开始的行上存在访问冲突错误:
for(int i = 0; i<data.numFaces; i++){
for(int j = 0; j<3; j++){ //Assuming triangles for now.
int v = data.faceList[i].vertex[j]; // Access violation here.
double vX = data.vertexList[v].x;
double vY = data.vertexList[v].y;
double vZ = data.vertexList[v].z;
glVertex3d(vX, vY, vZ);
}
}
我不确定为什么会这样,我已经检查了我能想到的一切。我在C ++方面不是很有经验。我的大部分编程经验都是Java,Python和PHP,尽管我以前用C ++编写了一个中型项目。
我确信这个问题与内存分配或用于动态数组的指针有关。
以下是obj加载类中代码的相关部分:
ObjData ObjLoader::LoadObj(std::string filename){
//... Initalization ...
// 1st pass: find number of elements so array sizes can be defined.
while(!file.eof()){
//...
}
//...close file...
_data.faceList = new ObjFace[_data.numFaces];
_data.vertexList = new ObjVert[_data.numVertices];
_data.uvList = new ObjUV[_data.numUVcoords];
_data.normalList = new ObjNormal[_data.numNormals];
//TODO: Make size dynamic according to each face. Just use the first 3 points for now.
for (int i = 0; i < _data.numFaces; i++){
_data.faceList[i].vertex = new int[3];
_data.faceList[i].normal = new int[3];
_data.faceList[i].uv = new int[3];
}
//... file stuff ...
// 2nd pass: read values into arrays.
while(!file.eof()){
//...
if(type=="v"){
_data.vertexList[currentVertex].x = atof(param1.c_str());
_data.vertexList[currentVertex].y = atof(param2.c_str());
_data.vertexList[currentVertex].z = atof(param3.c_str());
currentVertex++;
}else if(type=="vt"){
_data.uvList[currentUV].u = atof(param1.c_str());
_data.uvList[currentUV].v = atof(param2.c_str());
currentUV++;
}else if(type=="vn"){
_data.normalList[currentNormal].x = atof(param1.c_str());
_data.normalList[currentNormal].y = atof(param2.c_str());
_data.normalList[currentNormal].z = atof(param3.c_str());
currentNormal++;
}else if(type=="f"){
//...Within loop over each vertex in a single face ...
if(endPos != string::npos){
// Value before 1st "/" (Vertex index).
// ...find value in string...
_data.faceList[currentFace].vertex[i] = atoi(token.c_str()) -1; // File format begins indices from 1.
// Value between slashes (UV index).
// ...find value in string...
_data.faceList[currentFace].uv[i] = atoi(token.c_str()) -1;
// Value after 2nd "/" (Normal index).
// ...find value in string...
_data.faceList[currentFace].normal[i] = atoi(token.c_str()) -1;
}
//...End of loop over every vertex in a single face...
currentFace++;
}
}
return _data;
}
结构ObjFace,ObjVert,ObjUV和ObjNormal被定义为:
struct ObjVert{
float x, y, z;
};
struct ObjUV{
float u, v;
};
struct ObjNormal{
float x, y, z;
};
// Contains indexes.
struct ObjFace{
int* vertex;
int* uv;
int* normal;
};
感谢您的帮助。此外,任何有关未来避免这些类型错误的好消息都将受到赞赏。
答案 0 :(得分:2)
int v = data.faceList[i].vertex[j];
爆炸,那么问题似乎很可能是i
或j
,或者两者都太大或太小。
除了使用调试器变得舒适并且将这个错误弄平的明显方法之外,解决这些问题的最佳方法可能是完全避免它们。程序员所做的某些事情比其他人更容易出错。列表很长,但你的代码中至少有两个,黑桃。
1)您使用动态分配的数组 2)你使用手工制作的循环
尽量避免使用C ++提供的工具来做这些事情。从#1开始,摆脱动态分配的数组。
你有一个结构:
struct ObjFace{
int* vertex;
int* uv;
int* normal;
};
...有3个指向数组的指针 - int
。而不是这样做,使用vector
:
struct ObjFace{
vector<int> vertex;
vector<int> uv;
vector<int> normal;
};
...然后你之前编写的大量代码现在变得更加简单,而且更不容易出错:
// all this goes away
//_data.faceList = new ObjFace[_data.numFaces];
//_data.vertexList = new ObjVert[_data.numVertices];
//_data.uvList = new ObjUV[_data.numUVcoords];
//_data.normalList = new ObjNormal[_data.numNormals];
...和
// now you ask the vector how many elements it really has
for(int i = 0; i<data.faceList.size(); i++){
for(int j = 0; j<data.faceList.size(); j++){ //Ask the vector instead of assuming triangles
int v = data.faceList[i].vertex[j]; // Access violation here.
double vX = data.vertexList[v].x;
double vY = data.vertexList[v].y;
double vZ = data.vertexList[v].z;
glVertex3d(vX, vY, vZ);
}
}
现在,看看那个循环。循环是一个非常常见的错误来源。最好的循环是你永远不必写的循环。因此,请使用STL的算法。向ObjFace添加一个函数,在每个元素上执行glVertex3d
:
struct ObjFace{
//...
void do_vertex() const
{
typedef vector<int> ints;
for( ints::iterator it = vertex.begin(); it != vertex.end(); ++it )
glVertex3d(it->x, it->y, it->z);
}
};
...然后返回并缩小原始循环: (psudocode,实际语法更复杂)
typedef vector<ObjFace> ObjFaces;
for( ObjFaces::iterator it = data.faceList.begin(); it != data.faceList.end(); ++it )
it->do_vertex();
......或者,稍加努力:
for_each( data.faceList.begin(), data.faceList.end(), &ObjFace::do_vertex );
答案 1 :(得分:2)
我输入了一些愚蠢的回应,我意识到这是不对的......但我不得不继续思考它,我想出了另一个想法。
此对象在哪里分配?
如果data
和_data
是同一个对象,您的代码不清楚,但我注意到您的方法似乎将_data
作为对象返回。我被引导相信你可能正在某处使用像ObjData data = LoadObj("myfilename");
这样的作业?
如果是这种情况,我相信您的问题可能来自缺少复制构造函数或您的ObjData
类的重载赋值运算符。 (我不是C ++大师,所以我不记得究竟属于哪一个。希望其他人可以确认我们是否在正确的轨道上。)
如果在复制和赋值期间没有正确复制指针(从LoadObj
返回,则调用复制构造函数iirc,然后明确赋值给data
),那么即使你已经打算在该位置有一个int
数组,实际上您可能正在访问未初始化的内存,从而导致您的访问冲突。
我不是复制构造函数或重载赋值运算符的专家,但快速解决此问题的方法是返回指向ObjData
的指针,而不是返回对象本身。