2

更新

看起来我的法线工作正常,这与我画脸的方式有关(只画了一半),我不知道为什么——

顶点,法线被正确绘制

如果您可以查看我之前的代码(如下所示)


原帖

我目前正在为 .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);
4

3 回答 3

1

你在使用元素吗?Obj 文件从 1 开始计数,但 OpenGL 从 0 开始计数。只需从每个元素中减去 1,您就应该得到正确的渲染。

于 2012-11-22T09:20:17.770 回答
1

法线的方向很重要。看起来您的对象的面方向不一致,因此具有相似平面的相邻面的法线指向相反的方向。

如果你从模型文件中导入了该模型,我建议你不要在代码中计算法线——无论如何你都不应该这样做,因为艺术家可能会手动调整法线以局部微调照明——但将它们存储在模型文件也是如此。所有 3D 建模器都具有将法线翻转为共同方向的功能。例如,在 Blender 中,此功能可通过CTRL + N编辑模式下的热键来实现。

于 2012-11-22T10:01:52.050 回答
0
for(int i = 0; i < 3; i++) this->normals.push_back(point[i]);

这只为每个面提供一个法线。每个顶点都需要一个法线。

于 2012-11-22T16:28:56.243 回答