Part of the Khronos Group

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 2 of 2

Thread: Help with smooth shading and calculating vertex normals

  1. #1
    Newbie Newbie
    Join Date
    Jun 2014

    Help with smooth shading and calculating vertex normals

    Hello, I have been working with OpenGl for almost two weeks now and I have hit my first road block. Currently I am learning how to do shading and I am having alot of trouble learning how to set the normals for each my of vertices in order for smooth shading to work. Below is the code for a 3D triforce that I have been working on, by triforce I mean three pyramids with two standing side by side on the bottom and one on top of the other two. The program is written in C++ and I am using the linux mint comand prompt as a compiler. My issue is simple, I have no idea how to compute these normals, and everytime I look towards the internet for answers I just get code and formulas thrown at me with no explaination of how to apply it to my own program. If someone can please give me a simple explaination and maybe even a step by step algorithm of how to do this I will be very greatful.

    #include <iostream>
    #include <stdlib.h> //Needed for "exit" function

    //Include OpenGL header files, so that we can use OpenGL
    #ifdef __APPLE__
    #include <OpenGL/OpenGL.h>
    #include <GLUT/glut.h>
    #include <GL/glut.h>

    using namespace std;

    //Called when a key is pressed
    void handleKeypress(unsigned char key, //The key that was pressed
    int x, int y) { //The current mouse coordinates
    switch (key) {
    case 27: //Escape key
    exit(0); //Exit the program

    //Initializes 3D rendering
    void initRendering() {
    //Makes 3D drawing work when something is in front of something else
    glEnable(GL_LIGHTING); //Enable lighting
    glEnable(GL_LIGHT0); //Enable light #0
    glEnable(GL_LIGHT1); //Enable light #1
    glEnable(GL_NORMALIZE); //Automatically normalize normals
    glShadeModel(GL_SMOOTH); //Enables smmoth shading

    //Called when the window is resized
    void handleResize(int w, int h) {
    //Tell OpenGL how to convert from coordinates to pixel values
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective

    //Set the camera perspective
    glLoadIdentity(); //Reset the camera
    gluPerspective(45.0, //The camera angle
    (double)w / (double)h, //The width-to-height ratio
    1.0, //The near z clipping coordinate
    200.0); //The far z clipping coordinate

    float angle = -70;

    //Draws the 3D scene
    void drawScene() {
    //Clear information from last draw

    glMatrixMode(GL_MODELVIEW); //Switch to the drawing perspective
    glLoadIdentity(); //Reset the drawing perspective
    glTranslatef(0.0f, 0.0f, -5.0);

    //Add ambient light
    GLfloat ambientColor[] = {0.2f, 0.2f, 0.2f, 1.0f}; //Color (0.2, 0.2, 0.2)
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);

    //Add positioned light
    GLfloat lightColor0[] = {0.0f, 0.0f, 0.9f, 1.0f}; //Color (0.5, 0.5, 0.5)
    GLfloat lightPos0[] = {2.0f, 2.0f, 5.0f, 0.0f}; //Color (0.5, 0.5, 0.5)
    glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);

    //Add directed light
    GLfloat lightColor1[] = {0.9f, 0.0f, 0.0f, 1.0f}; //Color (0.5, 0.2, 0.2)
    //Coming from the direction (-1.0, 0.5, 0.5)
    GLfloat lightPos1[] = {-1.5f, 1.0f, -1.0f, 0.0f};
    glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor1);
    glLightfv(GL_LIGHT1, GL_POSITION, lightPos1);

    glTranslatef(0.0f, -1.0f, -1.0f);
    glRotatef(angle, 0.0f, 1.0f, 0.0f);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glVertex3f(2.0f, -1.0, 1.0);
    glVertex3f(0.0f, -1.0, 1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glVertex3f(-2.0f, -1.0, 1.0);
    glVertex3f(0.0f, -1.0, 1.0);
    glVertex3f(-1.0, 1.0, 0.0);

    glVertex3f(-1.0, 1.0, 1.0);
    glVertex3f(1.0, 1.0, 1.0);
    glVertex3f(0.0f, 3.0, 0.0);

    glNormal3f(-1.0f, -1.0f, 0.0f);
    glVertex3f(0.0f, -1.0, 1.0);
    glVertex3f(0.0, -1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glNormal3f(1.0f, -1.0f, 0.0f);
    glVertex3f(0.0f, -1.0, 1.0);
    glVertex3f(0.0f, -1.0, -1.0);
    glVertex3f(-1.0, 1.0, 0.0);

    glNormal3f(-0.75f, 0.0f, 0.0f);
    glVertex3f(-2.0f, -1.0, 1.0);
    glVertex3f(-2.0f, -1.0, -1.0);
    glVertex3f(-1.0, 1.0, 0.0);

    glVertex3f(-1.0, 1.0, 1.0);
    glVertex3f(-1.0, 1.0, -1.0);
    glVertex3f(0.0f, 3.0, 0.0);
    glNormal3f(0.75f, 0.0f, 0.0f);
    glVertex3f(2.0f, -1.0, 1.0);
    glVertex3f(2.0, -1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glVertex3f(1.0, 1.0, 1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0f, 3.0, 0.0);
    glNormal3f(0.0f, 0.0f, -1.0f);
    glVertex3f(2.0f, -1.0, -1.0);
    glVertex3f(0.0f, -1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glVertex3f(-2.0f, -1.0, -1.0);
    glVertex3f(0.0f, -1.0, -1.0);
    glVertex3f(-1.0, 1.0, 0.0);

    glVertex3f(-1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0f, 3.0, 0.0);

    glutSwapBuffers(); //Send the 3D scene to the screen

    void update(int value)
    angle += 2.0f;
    if (angle > 360)
    angle -=360;

    glutTimerFunc(10, update, 0);

    int main(int argc, char** argv) {
    //Initialize GLUT
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(400, 400); //Set the window size

    //Create the window
    glutCreateWindow("Basic Shapes -");
    initRendering(); //Initialize rendering

    //Set handler functions for drawing, keypresses, and window resizes
    glutTimerFunc(1, update, 0);

    glutMainLoop(); //Start the main loop. glutMainLoop doesn't return.
    return 0; //This line is never reached

  2. #2
    Advanced Member Frequent Contributor
    Join Date
    Apr 2010
    Please use [code][/code] around source code to preserve formatting.

    The basic algorithm goes like this:
    Code :
    foreach vertex v:
        totalAngle = 0
        normal_v   = (0,0,0)
        foreach face f that contains v:
            totalAngle += angle of f at v
        foreach face f that contains v:
            normal_v += (angle of f at v) / totalAngle * (face_normal of f)

    So, basically you take the face normals of the faces that share a vertex and weight them by the angle the face subtends at the vertex. These kinds of computations are generally easier if you store your vertex data in an array (or similar data structure) so that you can loop over it and access data repeatedly.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts