开发者

Problems when dealing with lighting and shadowing in opengl

I am trying to put lights, materials and shadows to my robot arm but unfortunately something weird happens (please compile or see the below picture), now I am still annoying by

Problems when dealing with lighting and shadowing in opengl

1) Not showing correct lighting and reflection properties as well as material properties

2) No shadow painted, although I have done the shadow casting in function "void showobj(void)"

I appreciate if anyone can help, I have already working for it 2 days with no progress :(

The following 开发者_JAVA百科is my code

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <GL/glut.h>
#include "gsrc.h"   
#include <Windows.h>

const double PI = 3.14159265;
// angles to rotate the base, lower and upper arms of the robot arm
static GLfloat theta, phi, psi = 0.0;
//Starting time
double startT;
//Time Diff variable
double dif,startTime,endTime,deltaT;
//define n
double n = 3;
//Set the parameters of the light number one
GLfloat Xs = 35.0;
GLfloat Ys = 35.0;
GLfloat Zs = 35.0;
//Shadow color
GLfloat shadowcolor[] = {0.0,0.0,0.0};

//initialize the window and everything to prepare for display
void init_gl() {
    //set display color to white
    glClearColor(1,1,1,0);
    //clear and enable z-buffer 
    glClear (GL_DEPTH_BUFFER_BIT);
    glEnable (GL_DEPTH_TEST);
    //clear display window
    glClear(GL_COLOR_BUFFER_BIT);
}

//Draw the base of the robot arm
void draw_base(){
    glPushMatrix();
        //to create the quadric objects
        GLUquadric *qobj,*qobjl,*qobju;
        qobj = gluNewQuadric(); 
        qobjl = gluNewQuadric(); 
        qobju = gluNewQuadric(); 

        //set the color of the cylinder
        glColor3f(1.0,0.0,0.0); 
        //Re-position the cylinder (x-z plane is the base)
        glRotatef(-90,1.0,0.0,0.0);
        //Draw the cylinder
        gluCylinder(qobj, 30.0, 30.0, 40.0, 40.0, 40.0);
        //Draw the upper disk of the base
        gluDisk(qobju,0,30,40,40);

        glPushMatrix();
            //Change the M(lowdisk<updisk)
            glTranslatef(0,0,40);
            glColor3f(0,0,0); 
            //Draw the lower disk of the base
            gluDisk(qobjl,0,30,40,40);
        glPopMatrix();
   glPopMatrix();
}

/***********************Texture Work Starts************************************/
//Load the raw file for texture
/* Global Declarations */
#define IW  256             // Image Width    
#define IH  256             // Image Height

//3D array to store image data
unsigned char InputImage     [IW][IH][4];  

// Read an input image from a .raw file with double
void ReadRawImage ( unsigned char Image[][IH][4] )
{
    FILE *fp;
    int  i, j, k;
    char* filename;
    unsigned char temp;

    filename = "floor.raw";

    if ((fp = fopen (filename, "rb")) == NULL)
    {
        printf("Error (ReadImage) : Cannot read the file!!\n");
        exit(1);
    }

    for ( i=0; i<IW; i++)
    {
        for ( j=0; j<IH; j++)
        {
            for (k = 0; k < 3; k++)       // k = 0 is Red  k = 1 is Green K = 2 is Blue
            {
                fscanf(fp, "%c", &temp);
                Image[i][j][k] = (unsigned char) temp;
            }
            Image[i][j][3] = (unsigned char) 0;         // alpha = 0.0
        }
    }
    fclose(fp);

}

/****************************Texture Work Ends***************************************/

/****************************Light and Shadows***************************************/
void lightsrc(){
GLfloat light1PosType [] = {Xs, Ys, Zs, 1.0};
    //GLfloat light2PosType [] = {0.0, 100.0, 0.0, 0.0};

    glLightfv(GL_LIGHT1, GL_POSITION, light1PosType);
    //glEnable(GL_LIGHT1);
    //glLightfv(GL_LIGHT2, GL_POSITION, light2PosType);
    //glEnable(GL_LIGHT2);

    GLfloat whiteColor[] = {1.0, 1.0, 1.0, 1.0};
    GLfloat blackColor[] = {0.0, 0.0, 0.0, 1.0};
    glLightfv(GL_LIGHT1, GL_AMBIENT, blackColor);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, whiteColor);
    glLightfv(GL_LIGHT1, GL_SPECULAR, whiteColor);
    glEnable(GL_LIGHT1);

    glEnable( GL_LIGHTING );
}

/****************************Light and Shadows work ends***************************************/

//Draw the 2x2x2 cube with center (0,1,0)
void cube(){ 
    glPushMatrix();
        glTranslatef(0,1,0);
        glutSolidCube(2);
    glPopMatrix();  
}

//Draw the lower arm
void draw_lower_arm(){
    glPushMatrix();
    glScalef(15.0/2.0,70.0/2.0,15.0/2.0);//scale half is enough (some part is in the negative side)
    cube();
    glPopMatrix();
}

//Draw the upper arm
void draw_upper_arm(){
    glPushMatrix();
    glScalef(15.0/2.0,40.0/2.0,15.0/2.0);//scale half is enough (some part is in the negative side)
    cube();
    glPopMatrix();
}

void drawCoordinates(){
    glBegin (GL_LINES);
        glColor3f (1,0,0);
        glVertex3f (0,0,0);
        glVertex3f (600,0,0);

        glColor3f (0,1,0);
        glVertex3f (0,0,0);
        glVertex3f (0,600,0);

        glColor3f (0,0,1);
        glVertex3f (0,0,0);
        glVertex3f (0,0,600);
    glEnd();        
}

//To draw the whole robot arm
void drawRobot(){
    //Robot Drawing Starts
      //Rotate the base by theta degrees
      glRotatef(theta,0.0,1.0,0.0); 
      //Draw the base
      draw_base();
      //M(B<La)
      glTranslatef(0.0,40.0,0.0);
      //Rotate the lower arm by phi degree
      glRotatef(phi,0.0,0.0,1.0);
      //change the color of the lower arm
      glColor3f(0.0,0.0,1.0);
      //Draw the lower arm
      draw_lower_arm();
      //M(La<Ua)
      glTranslatef(0.0,70.0,0.0);
      //Rotate the upper arm by psi degree
      glRotatef(psi,0.0,0.0,1.0);
      //change the color of the upper arm
      glColor3f(0.0,1.0,0.0);
      //Draw the upper arm
      draw_upper_arm();
      //Drawing Finish
      glutSwapBuffers();
}

void showobj(void) {
   //set the projection and perspective parameters/arguments
    GLint viewport[4];
    glGetIntegerv( GL_VIEWPORT, viewport );
    glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluPerspective( 45, double(viewport[2])/viewport[3], 0.1, 1000 );
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      gluLookAt(-200, 300, 200, 0, 0, 0, 0,1,0 );
      // get the rotation matrix from the rotation user-interface
      glMultMatrixf(gsrc_getmo() );  
      //Clear the display and ready to show the robot arm
      init_gl();    

      //put the light source
      lightsrc();
      //Draw coordinates
      drawCoordinates();
      //give material properties
        GLfloat diffuseCoeff[] = {0.2, 0.4, 0.9, 1.0}; // kdR= 0.2, kdG= 0.4, kdB= 0.9
        GLfloat specularCoeff[] = {1.0, 1.0, 1.0, 1.0}; // 
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuseCoeff);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 100.0 ); // ns= 25

      //Draw the ground floor
      glColor3f(0.4,0.4,0.4);
      glPushMatrix();
        glRotatef(90,1,0,0);
        glRectf(-500,-500,500,500);
      glPopMatrix();

        int i,j;
        GLfloat M[4][4];
        for (i=0; i<4; i++){
            for (j=0; j<4; j++){
                M[i][j] = 0;
            }
            M[0][0]=M[1][1]=M[2][2]=1;
            M[2][3]=-1.0/Zs;
        }

        //Start drawing shadow
        drawRobot(); // draw the objects
        glPushMatrix( ); // save state
        glMatrixMode(GL_MODELVIEW);
        glTranslatef(Xs, Ys, Zs);// Mwc&#8592;s
        glMultMatrixf(M[4]);// perspective project
        glTranslatef(-Xs, -Ys, -Zs);// Ms&#8592;wc
        glColor3fv (shadowcolor);
        //Draw the robot arm
        drawRobot();
        glPopMatrix(); // restore state
        //Shadow drawing ends

      glFlush ();  
}

//To animate the robot arm
void animate(void)
{
    //get the end time
    endTime = timeGetTime();
    //float angle;
    //calculate deltaT 
    deltaT = (endTime - startTime); //in msecs
    //float test;
    float deltaTSecs = deltaT/1000.0f;  //in secs
    //apply moving equation 
    psi = (90.0) * 0.50 * (1-cos((deltaTSecs/(n+1)) * PI));
    glutPostRedisplay ();
}

void main (int argc, char** argv)
{ 
    glutInit(&argc, argv); 
    //DOUBLE mode better for animation
    // Set display mode.
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowPosition( 50, 100 ); // Set top-left display-window position.
    glutInitWindowSize( 400, 300 ); // Set display-window width and height.
    glutCreateWindow( "Robot arm : my first self-learning opengl program" ); // Create display window.
    // Register mouse-click and mouse-move glut callback functions
    // for the rotation user-interface.
    //Allow user to drag the mouse and view the object
    glutMouseFunc( gsrc_mousebutton );
    glutMotionFunc( gsrc_mousemove );   
    //record the starting time
    startTime = timeGetTime();
    // Display everything in showobj function
    glutDisplayFunc(showobj); 
    //Perform background processing tasks or continuous animation
    glutIdleFunc(animate);
    glutMainLoop(); 
}


your screen flashes because you are calling glutSwapBuffers() in drawRobot(). That makes your screen repaint two times, once when you draw the robot, and once more when you draw the shadow. Also, you are missing glPushMatrix() at the beginning of drawRobot() and glPopMatrix() at the end. You need to put it there, otherwise it will affect rendering afterwards (the shadow will move with the upper link of the arm).

Then, you specify the shadow matrix wrong. Let's try this:

    int i,j;
    GLfloat M[4][4];
    for (i=0; i<4; i++){
        for (j=0; j<4; j++){
            M[i][j] = 0;
        }
    }
    M[0][0]=M[1][1]=M[2][2]=1;
    M[2][3]=-1.0/Zs;

    drawRobot(); // draw the objects

    //Start drawing shadow
    glEnable(GL_CULL_FACE);
    glDisable(GL_LIGHTING); // want constant-color shadow
    glPushMatrix( ); // save state
        glMatrixMode(GL_MODELVIEW);
        glTranslatef(Xs, Ys, Zs);// Mwc&#8592;s
        glMultMatrixf(&M[0][0]);// perspective project
        glTranslatef(-Xs, -Ys, -Zs);// Ms&#8592;wc
        glColor3fv (shadowcolor);
        //Draw the robot arm
        drawRobot();
    glPopMatrix(); // restore state
    glDisable(GL_CULL_FACE);
    glEnable(GL_LIGHTING); // enable again ...
    //Shadow drawing ends

Also, you can see i've added GL_CULL_FACE arround the shadow, it is to avoid depth fighting. This more or less fixes it technically.

But still - the shadow position is calculated incorrectly. Let's try looking at projection shadows.

So first, we need to have position for the ground plane and for the light:

float g[] = {0, 1, 0, 0}; // ground plane
float l[] = {20, 300, 50, 1}; // light position and "1"

That is a plane equation and a homogenous light position (normal 3D position, padded with a "1"). Then you throw away your shadow matrix setup (glTranslatef(), glMultMatrixf() and glTranslatef()) and call myShadowMatrix(g, l) instead, so it becomes:

glPushMatrix( ); // save state
    glMatrixMode(GL_MODELVIEW);
    float g[] = {0, 1, 0, 0}; // ground plane
    float l[] = {20, 300, 50, 1}; // light position and "1"
    myShadowMatrix(g, l);
    glColor3fv (shadowcolor);
    //Draw the robot arm
    drawRobot();
glPopMatrix(); // restore state

And that mostly does work. There is still a lot of z-fighting going on, and the shadow has four different colors. As for the colors, stop calling glColor3f() in drawRobot(), as for the z-fighting, use this:

glPolygonOffset(-1, -1);
glEnable(GL_POLYGON_OFFSET_FILL);
// before

// draw shadow

glDisable(GL_POLYGON_OFFSET_FILL);
// afterwards

And that makes one nice planar shadows demo :). Cheers ...

sw.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜