在opengl中处理光照和阴影时的问题

时间:2011-04-03 16:31:36

标签: c opengl glut

我正试图将灯光,材料和阴影放到我的机器人手臂上,但遗憾的是发生了一些奇怪的事情(请编译或看下图),现在我仍然烦恼于 weird 3d

1)未显示正确的光照和反射属性以及材料属性

2)没有画过阴影,虽然我已经在函数“void showobj(void)”中完成了阴影投射

我很感激,如果有人可以提供帮助,我已经为它工作了2天没有进展:(

以下是我的代码

#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(); 
}

1 个答案:

答案 0 :(得分:1)

你的屏幕闪烁,因为你在drawRobot()中调用了glutSwapBuffers()。这会使您的屏幕重绘两次,一次是在绘制机器人时,另一次是在绘制阴影时。此外,您在最后的drawRobot()和glPopMatrix()开头缺少glPushMatrix()。你需要把它放在那里,否则它会影响渲染(阴影将随着手臂的上部链接移动)。

然后,您指定阴影矩阵错误。我们试试这个:

    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

另外,你可以看到我已经在阴影周围添加了GL_CULL_FACE,这是为了避免深度战斗。这或多或少在技术上修复了它。

但仍然 - 阴影位置计算不正确。让我们试着看projection shadows

首先,我们需要有地平面和光线的位置:

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

这是平面方程和均匀光位置(正常3D位置,用“1”填充)。然后你丢弃你的阴影矩阵设置(glTranslatef(),glMultMatrixf()和glTranslatef())并调用myShadowMatrix(g,l),所以它变成:

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

这大部分都有效。仍然有很多z-fighting正在进行,阴影有四种不同的颜色。至于颜色,停止在drawRobot()中调用glColor3f(),对于z-fighting,请使用:

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

// draw shadow

glDisable(GL_POLYGON_OFFSET_FILL);
// afterwards

这使得一个漂亮的平面阴影演示:)。干杯......

SW。