用c ++计算opengl中的顶点法线

时间:2015-05-08 09:41:05

标签: c++ opengl opengl-es

有人可以帮我计算OpenGL中的顶点法线吗? 我正在加载一个obj文件并通过计算顶点法线添加Gouraud着色而不使用glNormal3f或glLight函数。 我已经声明了运算符,交叉产品,内积等功能。 我已经明白,为了得到顶点法线,我首先需要用crossproduct计算表面法线也就是法线向量.. 因为我正在加载一个obj文件..并且我将obj文件的Faces的三个点放在id1,id2,id3之类的东西

如果有人能帮助我编写代码或给我一个如何启动代码的指导,我将不胜感激。请 ... 感谢..

它的绘制

FACE cur_face = cube.face[i];
        glColor3f(cube.vertex_color[cur_face.id1].x,cube.vertex_color[cur_face.id1].y,cube.vertex_color[cur_face.id1].z);
        glVertex3f(cube.vertex[cur_face.id1].x,cube.vertex[cur_face.id1].y,cube.vertex[cur_face.id1].z);
        glColor3f(cube.vertex_color[cur_face.id2].x,cube.vertex_color[cur_face.id2].y,cube.vertex_color[cur_face.id2].z);
        glVertex3f(cube.vertex[cur_face.id2].x,cube.vertex[cur_face.id2].y,cube.vertex[cur_face.id2].z);
        glColor3f(cube.vertex_color[cur_face.id3].x,cube.vertex_color[cur_face.id3].y,cube.vertex_color[cur_face.id3].z);
        glVertex3f(cube.vertex[cur_face.id3].x,cube.vertex[cur_face.id3].y,cube.vertex[cur_face.id3].z);
    }

这是颜色计算的等式

VECTOR kd;
VECTOR ks;
kd=VECTOR(0.8, 0.8, 0.8);
ks=VECTOR(1.0, 0.0, 0.0);
double inner =  kd.InnerProduct(ks);

int i, j;
for(i=0;i<cube.vertex.size();i++)
{
    VECTOR n = cube.vertex_normal[i];
    VECTOR l = VECTOR(100,100,0) - cube.vertex[i];
    VECTOR v = VECTOR(0,0,1) - cube.vertex[i];
    float xl = n.InnerProduct(l)/n.Magnitude();
    VECTOR x = (n * (1.0/ n.Magnitude())) * xl;
    VECTOR r = x - (l-x);

    VECTOR color = kd * (n.InnerProduct(l)) + ks * pow((v.InnerProduct(r)),10);
    cube.vertex_color[i] = color;

3 个答案:

答案 0 :(得分:0)

您需要实现的是从N向量获取平均向量的函数。这是其中一种方法:

struct Vector3f {
    float x, y, z;
};
typedef struct Vector3f Vector3f;

Vector3f averageVector(Vector3f *vectors, int count) {
    Vector3f toReturn;
    toReturn.x = .0f;
    toReturn.y = .0f;
    toReturn.z = .0f;

    // sum all the vectors
    for(int i=0; i<count; i++) {
        Vector3f toAdd = vectors[i];
        toReturn.x += toAdd.x;
        toReturn.y += toAdd.y;
        toReturn.z += toAdd.z;
    }
    // divide with number of vectors
    // TODO: check (count == 0)
    float scale = 1.0f/count;
    toReturn.x *= scale;
    toReturn.y *= scale;
    toReturn.z *= scale;

    return toReturn;
}

我相信你可以将它移植到你的C ++类。然后应该将结果标准化,除非长度iz为零。

找到您拥有的每个顶点的所有曲面法线。然后使用averageVector并对结果进行标准化,以获得您正在寻找的平滑法线。

仍然如前所述,您应该知道这不适合形状的边缘部分。在这些情况下,您应该直接使用表面矢量。您可能只需忽略与其他表面法线太不同的表面法线来解决大多数此类情况。像这样的程序,如同立方体这样的极端锋利的形状是不可能的。你会得到的是:

{
1.0f, .0f, .0f,
.0f, 1.0f, .0f,
.0f, .0f, 1.0f
}

使用{.58f, .58f, .58f}的归一化平均值。结果几乎是一个极低分辨率的球体,而不是一个立方体。

答案 1 :(得分:0)

*此答案适用于三角形网格,也可以扩展到多边形网格。

tempVertices存储所有顶点的列表。

vertexIndices以矢量(以平面方式)存储网格的面(三角形)的细节。

    std::vector<glm::vec3> v_normal;

    // initialize vertex normals to 0
    for (int i = 0; i != tempVertices.size(); i++)
    {
        v_normal.push_back(glm::vec3(0.0f, 0.0f, 0.0f));
    }

    // For each face calculate normals and append to the corresponding vertices of the face
    for (unsigned int i = 0; i < vertexIndices.size(); i += 3)
    {
        //vi v(i+1) v(i+2) are the three faces of a triangle
        glm::vec3 A = tempVertices[vertexIndices[i] - 1];
        glm::vec3 B = tempVertices[vertexIndices[i + 1] - 1];
        glm::vec3 C = tempVertices[vertexIndices[i + 2] - 1];
        glm::vec3 AB = B - A;
        glm::vec3 AC = C - A;
        glm::vec3 ABxAC = glm::cross(AB, AC);
        v_normal[vertexIndices[i] - 1] += ABxAC;
        v_normal[vertexIndices[i + 1] - 1] += ABxAC;
        v_normal[vertexIndices[i + 2] - 1] += ABxAC;
    }

现在将每个v_normal标准化并使用。 请注意,顶点法线的数量等于网格的顶点数量。

答案 2 :(得分:0)

此代码在我的机器上运行良好

glm::vec3 computeFaceNormal(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3) {
    // Uses p2 as a new origin for p1,p3
    auto a = p3 - p2;
    auto b = p1 - p2;
    // Compute the cross product a X b to get the face normal
    return glm::normalize(glm::cross(a, b));
}

void Mesh::calculateNormals() {
    this->normals = std::vector<glm::vec3>(this->vertices.size());
    // For each face calculate normals and append it
    // to the corresponding vertices of the face
    for (unsigned int i = 0; i < this->indices.size(); i += 3) {
        glm::vec3 A = this->vertices[this->indices[i]];
        glm::vec3 B = this->vertices[this->indices[i + 1LL]];
        glm::vec3 C = this->vertices[this->indices[i + 2LL]];
        glm::vec3 normal = computeFaceNormal(A, B, C);
        this->normals[this->indices[i]] += normal;
        this->normals[this->indices[i + 1LL]] += normal;
        this->normals[this->indices[i + 2LL]] += normal;
    }
    // Normalize each normal
    for (unsigned int i = 0; i < this->normals.size(); i++)
        this->normals[i] = glm::normalize(this->normals[i]);
}