3
\$\begingroup\$

Does anyone knows a simple solution for calculating vertex normals? I've been looking for this on the internet but i cant find a simple solution, for example, if I have some vertices like this:

GLfloat vertices[] = 
{
 0.5f,  0.5f, 0.0f,  // Top Right
 0.5f, -0.5f, 0.0f,  // Bottom Right
-0.5f, -0.5f, 0.0f,  // Bottom Left
-0.5f,  0.5f, 0.0f   // Top Left 
};
\$\endgroup\$
4
  • \$\begingroup\$ For that model, all vertex normals are are either (0,0,1) or (0,0,-1), depending upon your coordinate handed-ness. \$\endgroup\$
    – 3Dave
    Commented Dec 2, 2016 at 22:55
  • \$\begingroup\$ what you mean by "coordinate handedness" ? \$\endgroup\$
    – khofez
    Commented Dec 2, 2016 at 22:58
  • \$\begingroup\$ Right-hand vs left-hand coordinate system. DirectX and OpenGL use different systems, and it's also dependent upon your application. \$\endgroup\$
    – 3Dave
    Commented Dec 2, 2016 at 22:59
  • 1
    \$\begingroup\$ To generate a face normal, take the cross product of two edges. The resulting vector, normalized, will be the face normal. To get vertex normals... is a little more complicated. \$\endgroup\$
    – 3Dave
    Commented Dec 2, 2016 at 23:18

2 Answers 2

5
\$\begingroup\$

Finding the vertex normal is actual really easy. Lets say that you want to find to normal for the vertex i (i is a 2D/3D vector), where i1 is the vertex after i and i2 is the vertex before i, this is what you do:

  1. Create two vectors, v1 and v2. Set v1 it to i1 - i, and set v2 it to i2 - i

  2. Create another vector called v3 and set it to the cross product between v1 and v2

  3. Finally, your normal will be the v3 normalized.

Note: If your model is not appearing then try inverting the normals or disabling cull face mode(if enabled). Also, by 'the vertex before' and 'the vertex after' I simply mean two different vertices adjacent to i.

\$\endgroup\$
1
  • \$\begingroup\$ This will indeed compute the vertex normal, but only for flat shading. If you are doing some terrain generation or something like that, you will need per face normals(average of all per vertex normals of a triangle), and then average up all the face normals of the adjacent faces. \$\endgroup\$
    – Ian Young
    Commented Dec 5, 2016 at 16:33
2
\$\begingroup\$

I disagree with JasonPh's answer. The result from his approach is face normal---the normal perpendicular to the face of i-i1-i2.

To calculate vertex normal, you need to calculate face normal first. The vertex normal is usually the average of the normals of faces adjacent to this vertex. Alternatively, a weighted average of these face normals can be used.

In order to traverse the faces adjacent to this vertex, half-edge data structure (http://www.sccg.sk/~samuelcik/dgs/half_edge.pdf) are usually adopted. It not only helps find the faces adjacent to a vertex, but also helps answer other questions more easily

  • Which faces use this vertex?
  • Which edges use this vertex?
  • Which faces border this edge?
  • Which edges border this face?
  • Which faces are adjacent to this face?
  • ...

The structure is like

struct HE_edge {
    HE_vert* vert; // vertex at the end of the half-edge
    HE_edge* pair; // oppositely oriented half-edge
    HE_face* face; // the incident face
    HE_edge* prev; // previous half-edge around the face
    HE_edge* next; // next half-edge around the face
};

struct HE_vert {
    float x, y, z; // the vertex coordinates
    HE_edge* edge; // one of the half-edges emanating from the vertex
};

struct HE_face {
    HE_edge* edge; // one of the half-edges bordering the face
};

With this structure, the procedure is basically (just a code to help understand, not the most effective one):

for each vertex v:
    // initialize
    v->normal = vec3(0,0,0);
    //iterate through all v's neighbouring face
    neighbouring_edge = v->edge;
    v->normal += calcFaceNormal(neighbouring_edge->face);
    //find the next edge emanating from vertex v
    neighbouring_edge = neighbouring_edge->pair->next
    while neighbouring_edge!= v->edge:
        v->normal += calcFaceNormal(neighbouring_edge->face);
        neighbouring_edge = neighbouring_edge->pair->next;
    v->normal = normalize(v->normal);

where the calcFaceNormal function can be (assuming triangle mesh):

calcFaceNormal(myface):
    v1 = face->edge->vert;
    v2 = face->edge->next->vert;
    v3 = face->edge->prev->vert;
    e1 = v2-v1;
    e2 = v3-v1;

    return corss_product(e1,e2);
\$\endgroup\$
1
  • \$\begingroup\$ Both answers are correct. Flat shading and smooth shading, both have their use cases. You don't use smooth shading for a box, for example, but you want it for smooth terrain or most living beings. \$\endgroup\$ Commented Feb 21, 2019 at 17:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .