Node.JS
Node.JS

Reputation: 1592

OpenGL/GLUT is my approach in lighting correct?

I'm asked to make a simple Propeller using GL_TRIANGLE_STRIP. However, writing the structure wasn't hard, but making the lighting to work properly is causing me trouble as I'm using GL_TRIANGLE_STRIP. Before I used GL_POLYGON and making lighting for shapes (e.g. rectangles) was very easy as I just specify glNormal3f once for each shape.

Question: Based on some internet search, apparently I need to specify the normal vector for vortex not each shape. So is my current lighting (the way that I am specifying the normal vectors) correct?

enter image description here

enter image description here

#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define PI 3.14159265

static GLfloat lpos[] = { 0.0, 0.0, 4.0, 1.0 };
static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
static GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };
static GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
static GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 };
static float alpha = 0.0;
static float beta = PI / 6.0;
static float zoom = 10.0;
static bool lightSource = true;
float twistConstant = 0;
float rotateConstant = 0;
float numberOfObj = 3;
float numberOfTriangles = 1;
static GLdouble cpos[3];



void DrawTopTriangleSet(){
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
    glBegin(GL_TRIANGLE_STRIP);

    for (int i = 180; i >= 0; i = i - numberOfTriangles){
        glNormal3f(0, cos(i*PI / 180), sin(i*PI / 180));
        glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
        glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
    }

    glEnd();
}

void DrawBottomTriangleSet(){
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
    glBegin(GL_TRIANGLE_STRIP);

    for (int i = 180; i >= 0; i = i - numberOfTriangles){
        glNormal3f(0, -cos(i*PI / 180), sin(i*PI / 180));
        glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
        glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
    }

    glEnd();
}

void DrawBackTriangleSet(){
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
    glBegin(GL_TRIANGLE_STRIP);


    for (int i = 180; i >= 0; i = i - numberOfTriangles){
        glNormal3f(0, -cos(i*PI / 180), -sin(i*PI / 180));
        glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
        glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
    }

    glEnd();
}

void DrawInsideTriangleSet(){
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glBegin(GL_TRIANGLE_STRIP);

    for (int i = 180; i >= 0; i = i - numberOfTriangles){
        glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
        glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
        glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
    }

    glEnd();
}

void writemessage()
{
    printf(" X => x++ <= Move light source in direction of +X\n");
    printf(" Y => y++ <= Move light source in direction of +Y\n");
    printf(" Z => z++ <= Move light source in direction of +Z\n");
    printf("\n");
    printf("^X => x-- <= Move light source in direction of -X\n");
    printf("^Y => y-- <= Move light source in direction of -Y\n");
    printf("^Z => z-- <= Move light source in direction of -Z\n");
    printf("\n");
    printf(" ^ => Move camera up\n");
    printf(" > => Move camera right\n");
    printf(" < => Move camera left\n");
    printf(" down arrow => Move camera down\n");
    printf("\n");
    printf(" t => More Twist\n");
    printf(" f => Less Twist\n");
    printf("\n");
    printf(" q => More Propeller\n");
    printf(" f => Less Propeller\n");
    printf("\n");
    printf(" w => More Triangles\n");
    printf(" s => Less Triangles\n");
    printf("\n");
    printf(" 0 => Toggling light source\n");
    printf("\n");
    printf(" r => Rotates Propeller\n");
    printf("\n");
    printf(" You can not move the light source when the light source is off !!!");
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.01, 20.0);
    glMatrixMode(GL_MODELVIEW);
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    cpos[0] = zoom * cos(beta) * sin(alpha);
    cpos[1] = zoom * sin(beta);
    cpos[2] = zoom * cos(beta) * cos(alpha);
    gluLookAt(cpos[0], cpos[1], cpos[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    if (lightSource == true){
        glLightfv(GL_LIGHT0, GL_POSITION, lpos);
        glMaterialfv(GL_FRONT, GL_EMISSION, white);
        glPushMatrix();
        glTranslatef(lpos[0], lpos[1], lpos[2]);
        glutSolidSphere(0.1, 10, 8);
        glPopMatrix();
        glMaterialfv(GL_FRONT, GL_EMISSION, black);
    }
    glRotatef(rotateConstant, 0, 0, 1);


    for (int i = 0; i < numberOfObj; i++){
        glPushMatrix();
        glRotatef(i * 360 / numberOfObj, 0, 0, 1);

        DrawTopTriangleSet();
        DrawBottomTriangleSet();
        DrawBackTriangleSet();
        DrawInsideTriangleSet();

        glPopMatrix();
    }


    // Cone
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, red);
    glPushMatrix();
    glTranslated(0, 0, -1.5);
    glutSolidCone(1, 2, 50, 50);
    glPopMatrix();

    // Back of Cone
    glMaterialfv(GL_FRONT, GL_EMISSION, black);
    glMaterialfv(GL_BACK, GL_EMISSION, black);
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, red);
    glBegin(GL_POLYGON);
    glNormal3f(0, 0, 1);
    for (int i = 0; i <= 360; i++)
    {
        glVertex3f(cos(i*PI / 180) * 1, sin(i*PI / 180) * 1, -1.5);
    }

    glEnd();


    glutSwapBuffers();
    glFlush();
}


void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case 27:
        exit(0);
        break;
    case 'x':
        if (lightSource == true)
            lpos[0] = lpos[0] + 0.2;
        glutPostRedisplay();
        break;
    case 'X':
        if (lightSource == true)
            lpos[0] = lpos[0] - 0.2;
        glutPostRedisplay();
        break;
    case 'y':
        if (lightSource == true)
            lpos[1] = lpos[1] + 0.2;
        glutPostRedisplay();
        break;
    case 'Y':
        if (lightSource == true)
            lpos[1] = lpos[1] - 0.2;
        glutPostRedisplay();
        break;
    case 'z':
        if (lightSource == true)
            lpos[2] = lpos[2] + 0.2;
        glutPostRedisplay();
        break;
    case 'Z':
        if (lightSource == true)
            lpos[2] = lpos[2] - 0.2;
        glutPostRedisplay();
        break;

    case '+':
        if (zoom != 1.5)zoom = zoom - 0.5;
        glutPostRedisplay();
        break;
    case '-':
        if (zoom != 15)zoom = zoom + 0.5;
        glutPostRedisplay();
        break;
    case '0':
        if (lightSource == true){
            glDisable(GL_LIGHT0);
            lightSource = false;
        }
        else{
            glEnable(GL_LIGHT0);
            lightSource = true;
        }
        glutPostRedisplay();
        break;
    case 't':
        if (twistConstant <= 1){
            twistConstant = twistConstant + 0.05;
            glutPostRedisplay();
        }
        break;
    case 'f':
        if (twistConstant >= 0){
            twistConstant = twistConstant - 0.05;
            glutPostRedisplay();
        }
        break;
    case 'r':
        rotateConstant = rotateConstant + 2;
        glutPostRedisplay();

        break;
    case 'q':
        if (numberOfObj <= 6){
            numberOfObj++;
            glutPostRedisplay();
        }

        break;
    case 'a':
        if (numberOfObj >= 0){
            numberOfObj--;
            glutPostRedisplay();
        }

        break;
    case 's':
        if (numberOfTriangles <90){
            numberOfTriangles++;
            glutPostRedisplay();
        }

        break;
    case 'w':
        if (numberOfTriangles > 1){
            numberOfTriangles--;
            glutPostRedisplay();
        }

        break;
    default:
        break;
    }
}


void specialkey(GLint key, int x, int y)
{
    switch (key) {
    case GLUT_KEY_RIGHT:
        alpha = alpha + PI / 180;
        if (alpha > 2 * PI) alpha = alpha - 2 * PI;
        glutPostRedisplay();
        break;
    case GLUT_KEY_LEFT:
        alpha = alpha - PI / 180;
        if (alpha < 0) alpha = alpha + 2 * PI;
        glutPostRedisplay();
        break;
    case GLUT_KEY_UP:
        if (beta < 0.45*PI) beta = beta + PI / 180;
        glutPostRedisplay();
        break;
    case GLUT_KEY_DOWN:
        if (beta > -0.05*PI) beta = beta - PI / 180;
        glutPostRedisplay();
        break;


    default:
        break;
    }
}

int main(int argc, char** argv)
{
    writemessage();
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(1200, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow(argv[0]);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);

    glEnable(GL_LIGHTING);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
    glEnable(GL_LIGHT0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 5.0, 10.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0);

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialkey);

    glutMainLoop();
    return 0;
}

Upvotes: 2

Views: 550

Answers (1)

Reto Koradi
Reto Koradi

Reputation: 54652

I don't think your normals are quite correct. For example for this part of the geometry:

glNormal3f(0, cos(i*PI / 180), sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));

Since twistConstant is part of the vertex coordinate calculation, it looks very suspicious that it's not also part of the normal calculation. I don't think it's possible for the normal to not depend on the constant value if it changes how the vertices are calculated.

Let's try and calculate the normal for this case. This is just for illustration of the process, it's quite likely that I won't get this exactly right without trying it out.

For parameterized surfaces, you normally calculate the normal as the cross product of the two gradient vectors (one for each parameter). Using a short for the value of the angle I * PI / 180, and c short for twistConstant, the two vertices from the code above are:

     | a            |         | a            |
v1 = | 0            |    v2 = | 0.5 * sin(a) |
     | 0.5 * sin(a) |         | - c * sin(a) |

The gradient for parameter a at vertex v1 is then:

           | 1            |
dv1 / da = | 0            |
           | 0.5 * cos(a) |

The way I read your code, the surface is flat in the direction between these two vertices, so we can use the difference between the two vectors as the second gradient:

          | 0                    |
v2 - v1 = | 0.5 * sin(a)         |
          | - (c + 0.5) * sin(a) |

The cross product between these two gradient vectors is then:

| 1            |   | 0                    |   | -0.25 * sin(a) * cos(a) |
| 0            | x | 0.5 * sin(a)         | = | (c + 0.5) * sin(a)      |
| 0.5 * cos(a) |   | - (c + 0.5) * sin(a) |   | 0.5 * sin(a)            |

This would then be the normal at vertex v1. The normal at v2 will be different, which makes sense because the blade is twisted.

Beyond the math, you're also missing to specify normals in DrawInsideTriangleSet():

glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));

The first call was probably supposed to be glNormal3f() instead of glVertex3f().

Upvotes: 3

Related Questions