更新
看起来好像我的法线正常工作,而且这是我画脸的方式(只画了一半),我无法弄明白为什么 -
如果您可以查看我之前的代码(如下所示)
原帖
我目前正在研究.obj文件类型的解析器/渲染器。我遇到了显示法线向量的问题:
没有法线:
有法线:
出于某种原因,我无法弄清楚为什么只有一半的法线载体有效,而另一半则表现得好像根本没有脸。
这是我在obj文件中加载的代码:
void ObjModel::Load(string filename){
ifstream file(filename.c_str());
if(!file) return;
stringstream ss;
string param, line;
float nparam, cur;
vector<vector<float> > coords;
vector<float> point;
while(getline(file, line)){
ss.clear();
ss.str(line);
ss >> param;
//vertex
if(param == "v"){
for(int i = 0; i < 3; i++){
ss >> nparam;
this->vertices.push_back(nparam);
}
}
//face
else if(param == "f"){
coords.clear();
point.clear();
for(int i = 0; i < 3; i++){
ss >> nparam;
nparam--;
for(int j = 0; j < 3; j++){
cur = this->vertices[nparam * 3 + j];
this->faces.push_back(cur);
point.push_back(cur);
}
coords.push_back(point);
}
point = this->ComputeNormal(coords[0], coords[1], coords[2]);
for(int i = 0; i < 3; i++) this->normals.push_back(point[i]);
}
else continue;
}
}
void ObjModel::Render(){
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &this->faces[0]);
glNormalPointer(GL_FLOAT, 0, &this->normals[0]);
glDrawArrays(GL_TRIANGLES, 0, this->faces.size() / 3);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
这是计算法线向量的函数:
vector<float> ObjModel::ComputeNormal(vector<float> v1, vector<float> v2, vector<float> v3){
vector<float> vA, vB, vX;
float mag;
vA.push_back(v1[0] - v2[0]);
vA.push_back(v1[1] - v2[1]);
vA.push_back(v1[2] - v2[2]);
vB.push_back(v1[0] - v3[0]);
vB.push_back(v1[1] - v3[1]);
vB.push_back(v1[2] - v3[2]);
vX.push_back(vA[1] * vB[2] - vA[2] * vB[1]);
vX.push_back(vA[2] * vB[0] - vA[0] * vB[2]);
vX.push_back(vA[0] * vB[1] - vA[1] * vB[0]);
mag = sqrt(vX[0] * vX[0] + vX[1] * vX[1] + vX[2] * vX[2]);
for(int i = 0; i < 3; i++) vX[i] /= mag;
return vX;}
我已经检查过以确保有相同数量的法向量和面(如果我是正确的话,那应该是这样的。)
提前谢谢! :)
编辑以下是我启用/禁用OpenGL功能的方法:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
GLfloat amb_light[] = 0.1, 0.1, 0.1, 1.0 ;
GLfloat diffuse[] = {0.6, 0.6, 0.6, 1};
GLfloat specular[] = {0.7, 0.7, 0.3, 1};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb_light);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
glLightModeli(L_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_CULL_FACE);
答案 0 :(得分:1)
你在使用元素吗? Obj文件从1开始计数,但OpenGL从0开始计数。只需从每个元素中减去1即可得到正确的渲染。
答案 1 :(得分:1)
法线的方向很重要。看起来你的物体的面部方向不一致,所以具有相似平面的相邻面的法线指向相反的方向。
如果您从模型文件导入该模型,我建议您不要计算代码中的法线 - 无论如何都不应该这样做,因为艺术家可能会手动调整法线来局部微调照明 - 但是存储它们也在模型文件中。所有3D建模器都具有将法线翻转为共同方向的功能。在Blender中,例如在编辑模式下使用热键CTRL + N
可以访问此功能。
答案 2 :(得分:0)
for(int i = 0; i < 3; i++) this->normals.push_back(point[i]);
仅为每张脸提供一个法线。每个顶点需要一个法线。