回 帖 发 新 帖 刷新版面

主题:[讨论]OpenGL阴影贴图问题,急!!!(牛仔请进!)

我按照eastcowboy的教程,绘制了一个动画场景,太阳地球月亮,外加三个平面。

遇到了这个的问题:不知道如何产生shadow ,就是地球和月亮的阴影,我是初学者,请您多指教!万分感激!
以下是源代码:

#include <GL/glut.h>
#include <GL/glaux.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>
#pragma comment(lib, "glaux.lib")

// sun,earth and moon
// assume that each month contains 30 days 
// 12 months make up a year

static int day=0; //day varies from 0 to 359
GLUquadricObj* qobj[2];//quadric object
GLuint texID[2];//texture object


GLfloat light_pos[] = {0.0f, 0.0f, 0.0f, 1.0f};

void init()
 {
    qobj[0]=qobj[1]=gluNewQuadric(); //create quadric object
    AUX_RGBImageRec *TextureImage[2];

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

    //texture of earth
    TextureImage[0]=auxDIBImageLoad("earth_map.bmp");
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glGenTextures(1,&texID[0]);
    glBindTexture(GL_TEXTURE_2D,texID[0]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, TextureImage[0]->sizeX, TextureImage[0]->sizeY,0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

    //texture of moon
    TextureImage[1]=auxDIBImageLoad("moon_map.bmp");
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glGenTextures(1,&texID[1]);
    glBindTexture(GL_TEXTURE_2D,texID[1]);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, TextureImage[1]->sizeX, TextureImage[1]->sizeY,0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[1]->data);
 }

 void light_source()
 {// define light source (white)
    {
    //light_position[] = {0.0f, 59600000.0f, 0.0f, 1.0f};
    GLfloat light_ambient[]  = {0.5f, 0.5f, 0.5f, 1.0f};
    GLfloat light_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
    GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);//choose the light model:both sides receive light
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    } 
 }

 void draw_sun()
 { // define the material of sun and draw sun
    {
        GLfloat sun_mat_ambient[]  = {1.0f, 0.0f, 0.0f, 1.0f};
        GLfloat sun_mat_diffuse[]  = {1.0f, 0.0f, 0.0f, 1.0f};
        GLfloat sun_mat_specular[] = {1.0f, 0.0f, 0.0f, 1.0f};
        GLfloat sun_mat_emission[] = {1.0f, 0.0f, 0.0f, 1.0f};// sun launches red light
        GLfloat sun_mat_shininess  = 0.0f;
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   sun_mat_ambient);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   sun_mat_diffuse);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  sun_mat_specular);
        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  sun_mat_emission);
        glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, sun_mat_shininess);
    }
    //glRotatef(day/360.0*360.0, 0.0, 1.0, 0.0);
    glutSolidSphere(49600000,60, 60);
 }

 void draw_earth()
 {// define th material of earth and draw earth
    {
        GLfloat earth_mat_ambient[]  = {0.4f, 0.4f, 0.8f, 1.0f};
        GLfloat earth_mat_diffuse[]  = {0.4f, 0.4f, 0.8f, 1.0f};
        GLfloat earth_mat_specular[] = {0.4f, 0.4f, 0.8f, 1.0f};
        GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
        GLfloat earth_mat_shininess  = 30.0f;
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   earth_mat_ambient);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   earth_mat_diffuse);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  earth_mat_specular);
        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  earth_mat_emission);
        glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, earth_mat_shininess);
    }
    glEnable(GL_TEXTURE_2D);
    //glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_ADD);//replace the color by texture color
    glBindTexture(GL_TEXTURE_2D,texID[0]);
    gluQuadricTexture(qobj[0],GL_TRUE);//generate the texture coordinates for the quadric surface

    glRotatef(day/360.0*360.0, 0.0, 1.0, 0.0);//earth revolution
    glTranslatef(150000000, 0.0, 0.0);// earth revolution radius
    glPushMatrix();
        glRotatef(day/360.0*360.0, 0.0, 1.0, 0.0);//earth rotation
        gluSphere(qobj[0],25945000, 60, 60);//draw earth
    glPopMatrix();
    
    
    glDisable(GL_TEXTURE_2D);
 }

  void draw_moon()
 {// define the material of moon and draw moon
    {
        GLfloat moon_mat_ambient[]  = {1.0f, 1.0f, 1.0f, 1.0f};
        GLfloat moon_mat_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
        GLfloat moon_mat_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
        GLfloat moon_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
        GLfloat moon_mat_shininess  = 60.0f;
        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   moon_mat_ambient);
        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   moon_mat_diffuse);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  moon_mat_specular);
        glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  moon_mat_emission);
        glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, moon_mat_shininess);
    }
    glEnable(GL_TEXTURE_2D);
    //glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
    glBindTexture(GL_TEXTURE_2D,texID[1]);
    gluQuadricTexture(qobj[1],GL_TRUE);

    glRotatef(day/30.0*360.0, 0.0, 1.0, 0.0);//moon rotates around the earth
    glTranslatef(48000000, 0.0, 0.0);//moon revolution radius

    gluSphere(qobj[1],8345000, 20, 20);//draw moon
    glDisable(GL_TEXTURE_2D);
 }

void draw_plane()
{
    {// define material of plane and draw bottom plane:
        {
            GLfloat plane_mat_ambient[]  = {0.0f, 0.4f, 0.6f, 1.0f};
            GLfloat plane_mat_diffuse[]  = {0.0f, 0.4f, 0.6f, 1.0f};
            GLfloat plane_mat_specular[] = {0.0f, 0.4f, 0.6f, 1.0f};
            GLfloat plane_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};//does not shine
            GLfloat plane_mat_shininess  = 0.0f;
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   plane_mat_ambient);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   plane_mat_diffuse);
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  plane_mat_specular);
            glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  plane_mat_emission);
            glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, plane_mat_shininess);
        }
        glBegin(GL_QUADS);
            glVertex3f(320000000,-89600000,-320000000);
            glVertex3f(-320000000,-89600000,-320000000);
            glVertex3f(-320000000,-89600000,320000000);
            glVertex3f(320000000,-89600000,320000000);
        glEnd();
    }

    {// define material of plane and draw front plane:
        {
            GLfloat plane_mat_ambient[]  = {0.0f, 1.0f, 0.0f, 1.0f};
            GLfloat plane_mat_diffuse[]  = {0.0f, 1.0f, 0.0f, 1.0f};
            GLfloat plane_mat_specular[] = {0.0f, 1.0f, 0.0f, 1.0f};
            GLfloat plane_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};//does not shine
            GLfloat plane_mat_shininess  = 0.0f;
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   plane_mat_ambient);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   plane_mat_diffuse);
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  plane_mat_specular);
            glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  plane_mat_emission);
            glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, plane_mat_shininess);
        }
        glBegin(GL_QUADS);
            glVertex3f(320000000,-89600000,-320000000);
            glVertex3f(-320000000,-89600000,-320000000);
            glVertex3f(-320000000,89600000,-320000000);
            glVertex3f(320000000,89600000,-320000000);
        glEnd();
    }

    {//define material of plane and draw left plane:
        {
            GLfloat plane_mat_ambient[]  = {1.0f, 1.0f, 1.0f, 1.0f};
            GLfloat plane_mat_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
            GLfloat plane_mat_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
            GLfloat plane_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};//does not shine
            GLfloat plane_mat_shininess  = 0.0f;
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   plane_mat_ambient);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   plane_mat_diffuse);
            glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  plane_mat_specular);
            glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  plane_mat_emission);
            glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, plane_mat_shininess);
        }
        glBegin(GL_QUADS);
            glVertex3f(-320000000,-89600000,-320000000);
            glVertex3f(-320000000,-89600000,320000000);
            glVertex3f(-320000000,89600000,320000000);
            glVertex3f(-320000000,89600000,-320000000);
        glEnd();
    }
}


void myDisplay(void)
{    
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);//projection transform
    glLoadIdentity();
    gluPerspective(70, 1, 0, 400000000);//perspective projection
    //fovy=70°,aspect=width/height=1.0,znear=0.0,zfar=200000000*2=400000000

    glMatrixMode(GL_MODELVIEW);//model view transform
    glLoadIdentity();
    gluLookAt(150000000, 200000000, 400000000, 0, 0, 0, 0, 1, 0);
    
    glPushMatrix();
        light_source();//enable the defined light
        draw_sun();  
        draw_earth(); 
        draw_moon(); 
    glPopMatrix();
    draw_plane();//draw three planes

    
    glutSwapBuffers();//exchange the rendering buffer and display buffer
    Sleep(100);//sleep for 80ms
    ++day;
    if(day>=360)
        day=0;
}

void main(int argc, char *argv[])
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
    glutInitWindowPosition(400,0);
    glutInitWindowSize(800,800);
    glutCreateWindow("sun earth and moon");
    init();
    glutDisplayFunc(myDisplay);
    glutIdleFunc(myDisplay);//call the function when CPU is idle
    glutMainLoop();
}

回复列表 (共3个回复)

沙发


注:请下载两幅图片,分别命名为earth.bmp和moon.bmp,放于工程目录下。。。

板凳

阴影的绘制比较复杂,方法很多,但是每种方法都可能有自己的缺点。这其中的内容我也不是太清楚。
OpenGL有一个FAQ:[url=http://www.opengl.org/resources/faq/technical/lights.htm]http://www.opengl.org/resources/faq/technical/lights.htm[/url],最后提到了阴影,并且提到了几种简单的做法。

Projection shadows are ideal if your shadow is only to lie on a planar object.
这是介绍的第一种方法。大致思路是通过一个变换矩阵,把所有的物体都缩放到一个平面上,然后涂黑,这就是阴影。这种做法的缺点就是“所有的阴影都在同一个平面”,无法把阴影绘制到不规则平面上。当然,如果多缩放几次,也可以把阴影画到多个平面上,而不是局限于唯一的一个平面。(楼主的场景可以试试这样做)

Stencil buffer shadowing is more flexible, allowing shadows to lie on any object, planar or otherwise.
这是第二种方法。大致思路是利用模板缓冲区,并且需要计算shadow volume。这个做法后来好像有不少的改进算法。(搜索一下shadow volume,应该会发现大量的资料)

Another mechanism for rendering shadows is outlined in the SIGGRAPH '92 paper Fast Shadows and Lighting Effects Using Texture Mapping, Mark Segal et al.
这是第三种方法。具体我也不是很清楚了。

图形学方面,其实我学得并不好。并且最近有较长时间没有练习,几乎是荒废了。
楼主如果有兴趣,不妨看点这方面的资料。

3 楼


谢谢牛仔的详细解答!特别感谢牛仔的及时回复!
牛仔以前的教程我也看过,写的非常好!很适合初学者快速入门!

我来回复

您尚未登录,请登录后再回复。点此登录或注册