PDA

View Full Version : Help with smooth shading and calculating vertex normals



astrelke
06-10-2014, 01:27 PM
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>
#else
#include <GL/glut.h>
#endif

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_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
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
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

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);
glBegin(GL_TRIANGLES);
//Front
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);

//Middle
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);

//Left
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);
//Right
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);
//Back
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);
glEnd();


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


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

glutPostRedisplay();
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 - videotutorialsrock.com");
initRendering(); //Initialize rendering

//Set handler functions for drawing, keypresses, and window resizes
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
glutTimerFunc(1, update, 0);

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

carsten neumann
06-11-2014, 12:48 AM
Please use
around source code to preserve formatting.

The basic algorithm goes like this:


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)
normalize(normal_v)


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.