Проблемы при освещении и затенении в opengl - PullRequest
3 голосов
/ 03 апреля 2011

Я пытаюсь наложить свет, материалы и тени на мою руку робота, но, к сожалению, происходит что-то странное (пожалуйста, скомпилируйте или посмотрите рисунок ниже), но теперь я все еще 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 Ответ

1 голос
/ 18 января 2012

ваш экран мигает, потому что вы вызываете glutSwapBuffers () в drawRobot ().Это заставляет ваш экран перекрашиваться два раза, один раз, когда вы рисуете робота, и еще раз, когда вы рисуете тень.Кроме того, вам не хватает glPushMatrix () в начале drawRobot () и 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;

    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 вокруг тени, чтобы избежать глубинного боя.Это более или менее исправляет это технически.

Но все же - позиция тени рассчитывается неправильно.Давайте попробуем взглянуть на проекционные тени .

Итак, во-первых, нам нужно иметь положение для плоскости земли и для света:

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

Это уравнение плоскостии однородное положение освещения (нормальное трехмерное положение, дополненное «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-боев, и тень имеет четыре разных цвета.Что касается цветов, прекратите вызывать glColor3f () в drawRobot (), что касается z-боя, используйте это:

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

// draw shadow

glDisable(GL_POLYGON_OFFSET_FILL);
// afterwards

И это делает одну симпатичную демонстрацию плоских теней :).Ура ...

sw.

...