发信人: yxy (田丝丝#小肥鹰春眠不觉晓), 信区: GAME_Designer 
标  题: OPENGL(15) 
发信站: BBS 水木清华站 (Tue Feb 17 21:40:18 1998) 
 
为什么3D作图常常能产生另人震惊的效果?因为利用3D作图,你可以生成一些 
现实中难得实现的真实的感受。特别是一些特殊的光影效果。 
其实光源前面已经讲的很全面了,只是缺少一些专门的例子。这里我们来稍微 
加深一下认识,我们将在例子中看到一个地方的光源对不同物体发出不同的光 
这在现实中是少见的吧? 
 
1.双面光照: 
void glLightModeli(LIGHT_MODEL_TWO_SIDE,GL_TRUE); 
光照计算通常是对多边形进行的。一般设置光照的条件总是对正面的多边形,而 
不考虑背面,但是如果考虑一个物体被劈开,光源的个数又会影响可见性,那么 
有必要对多边形双面都进行计算,这就是上面函数的功能;取消这一功能只须把 
第三个参数改为GL_FALSE。 
 
2.聚光源 
定义聚光源的函数仍是利用glLightfv(),需要设定的参数包括:光源位置、光源 
发散半角和光源聚光方向。 
 
具体实现可以看下面例子: 
////////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
void initlights(void) 

//定义物体材质特性的数值 
        GLfloat mat_ambient[]={0.2,0.2,0.2,1.0}; 
        GLfloat mat_diffuse[]={0.8,0.8,0.8,1.0}; 
        GLfloat mat_specular[]={1.0,1.0,1.0,1.0}; 
        GLfloat mat_shininess[]={80.0}; 
 
//定义第0个光源的属性(这是平行的环境光,没有聚光效果)     
        GLfloat light0_diffuse[]={0.0,0.0,1.0,1.0}; 
        GLfloat light0_position[]={1.0,1.0,1.0,0.0}; 
//定义第一个光源的属性(聚光灯一) 
        GLfloat light1_ambient[]={0.2,0.2,0.2,1.0}; 
        GLfloat light1_diffuse[]={1.0,0.0,0.0,1.0}; 
        GLfloat light1_specular[]={1.0,0.6,0.6,1.0}; 
        GLfloat light1_position[]={-3.0,-3.0,3.0,1.0}; 
        GLfloat spot_direction[]={1.0,1.0,-1.0}; 
 
//定义第二个光源的属性(聚光灯二) 
        GLfloat light2_ambient[]={0.2,0.6,0.2,1.0}; 
        GLfloat light2_diffuse[]={0.0,1.0,0.0,1.0}; 
        GLfloat light2_specular[]={0.0,1.0,0.0,1.0}; 
        GLfloat light2_position[]={-3.0,-3.0,3.0,1.0}; 
        GLfloat spot2_direction[]={1.0,1.0,-1.0}; 
//!!!我们看到第一和第二个聚光源除了在颜色的定义上一个偏红,一个偏绿 
//其他没有任何不同,所以如果象我们后面作的,对一个物体开启一个光源,对 
//另一个物体开启另一个光源,就会产生一个点光源对不同物体发出不同光的效果 
 
//将前面的属性定义加以应用 
        glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_diffuse); 
        glLightfv(GL_LIGHT0,GL_POSITION,light0_position); 
 
        glLightfv(GL_LIGHT1,GL_AMBIENT,light1_ambient); 
        glLightfv(GL_LIGHT1,GL_DIFFUSE,light1_diffuse); 
        glLightfv(GL_LIGHT1,GL_SPECULAR,light1_specular); 
        glLightfv(GL_LIGHT1,GL_POSITION,light1_position); 
//定义聚光灯发散角 
        glLightf(GL_LIGHT1,GL_SPOT_CUTOFF,30.0); 
//定义聚光灯发射方向的向量 
        glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,spot_direction); 
 
        glLightfv(GL_LIGHT2,GL_AMBIENT,light2_ambient); 
        glLightfv(GL_LIGHT2,GL_DIFFUSE,light2_diffuse); 
        glLightfv(GL_LIGHT2,GL_SPECULAR,light2_specular); 
        glLightfv(GL_LIGHT2,GL_POSITION,light2_position); 
 
        glLightf(GL_LIGHT2,GL_SPOT_CUTOFF,30.0); 
        glLightfv(GL_LIGHT2,GL_SPOT_DIRECTION,spot2_direction); 
 
        glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); 
        glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); 
        glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); 
        glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); 
 
        glEnable(GL_LIGHTING); 
        glEnable(GL_LIGHT0); 
        glEnable(GL_LIGHT1); 
        glEnable(GL_LIGHT2); 
 

 
void myinit(void) 

 
        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
        glDepthFunc(GL_LESS); 
        glEnable(GL_DEPTH_TEST); 
        initlights(); 
//      glShadeModel(GL_FLAT); 

 
void CALLBACK reshape(GLsizei w,GLsizei h) 

 
glViewport(0,0,w,h); 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
 
if(w<=h) 
 glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0); 
else 
  glOrtho(-5.0*(GLfloat)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

 
 
void CALLBACK display(void) 

  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
//首先标出聚光源一、二的位置(同一位置) 
  glPushMatrix(); 
  glTranslated(-3.0,-3.0,3.0); 
  glDisable(GL_LIGHTING); 
  glColor3f(1.0,0.0,0.0); 
  auxWireCube(0.1); 
  glEnable(GL_LIGHTING); 
  glPopMatrix(); 
 
//关掉第二个光源,只启用第一个光源(红),绘制球体一 
  glPushMatrix(); 
  glDisable(GL_LIGHT2);  
  glTranslated(0.0,2.0,0.0); 
  auxSolidSphere(2.0); 
  glPopMatrix(); 
   
//关掉第一个光源,只启用第二个光源(绿),绘制球体二 
  glPushMatrix(); 
  glDisable(GL_LIGHT1); 
  glEnable(GL_LIGHT2); 
  glTranslated(0.0,-2.0,0.0); 
  auxSolidSphere(2.0); 
  glPopMatrix(); 
 
  glFlush(); 

void main(void) 

    myinit(); 
     
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
/////////////////////////////////////////////////////////////// 
一个现实中难以见到的情景出现了。还不快试试? 
 
结束光源之前,再给出一个光源移动的例子,其中用到了鼠标消息的响应,实现 
非常简单,以OPENGL的辅助库提供的方式调用一个CALLBACK函数即可,和以前讲 
的响应键盘输入的方法完全一样。 
////////////////////////////////////////////////////////////// 
//sample.cpp 
#include "glos.h" 
#include <GL/gl.h> 
#include <GL/glaux.h> 
#include "windows.h" 
void myinit(void); 
void CALLBACK  display(void); 
void CALLBACK  reshape(GLsizei w,GLsizei h); 
 
//控制光源移动的变量 
static int step=0; 
 
//鼠标响应的CALLBACK函数 
void CALLBACK movelight(AUX_EVENTREC *event) 

step=(step+15)%360; 

 
void initlights(void) 

        GLfloat mat_ambient[]={0.2,0.2,0.2,1.0}; 
        GLfloat mat_diffuse[]={0.8,0.8,0.8,1.0}; 
        GLfloat mat_specular[]={1.0,1.0,1.0,1.0}; 
        GLfloat mat_shininess[]={80.0}; 
     
        GLfloat light0_diffuse[]={0.0,0.0,1.0,1.0}; 
        GLfloat light0_ambient[]={0.2,0.5,0.5,1.0}; 
 
 
 
        glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_diffuse); 
        glLightfv(GL_LIGHT0,GL_AMBIENT,light0_ambient); 
 
 
 
        glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); 
        glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); 
        glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); 
        glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); 
 
        glEnable(GL_LIGHTING); 
        glEnable(GL_LIGHT0); 
 

 
void myinit(void) 

 
        auxInitDisplayMode(AUX_SINGLE|AUX_RGBA); 
        auxInitPosition(0,0,500,500); 
        auxInitWindow("sample1"); 
        glClearColor(0.0,0.0,0.0,0.0); 
        glClear(GL_COLOR_BUFFER_BIT); 
 
        glDepthFunc(GL_LESS); 
        glEnable(GL_DEPTH_TEST); 
        initlights(); 
//      glShadeModel(GL_FLAT); 

 
void CALLBACK reshape(GLsizei w,GLsizei h) 

 
glViewport(0,0,w,h); 
glMatrixMode(GL_PROJECTION); 
glLoadIdentity(); 
 
if(w<=h) 
 glOrtho(-5.0,5.0,-5.0*(GLfloat)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0); 
else 
  glOrtho(-5.0*(GLfloat)h/(GLfloat)w, 
         5.0*(GLfloat)h/(GLfloat)w,-5.0,5.0,-5.0,5.0); 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity(); 

 
 
void CALLBACK display(void) 

  GLfloat position[]={0.0,0.0,1.5,1.0}; 
 
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
   
  glPushMatrix(); 
  glTranslatef(0.0,0.0,-5.0); 
  glPushMatrix(); 
 
//光源的位置只由旋转变量step决定,每按下鼠标左键一下,step的值便会改变 
//导致光源位置的改变 
  glRotated((GLdouble)step,-1.0,1.0,1.0); 
  glLightfv(GL_LIGHT0,GL_POSITION,position); 
  glTranslated(0.0,0.0,1.5); 
 
  glDisable(GL_LIGHTING); 
  glColor3f(1.0,1.0,0.0); 
  auxWireSphere(0.25); 
  glEnable(GL_LIGHTING); 
 
  glPopMatrix(); 
  auxSolidTorus(0.5,2.5); 
  glPopMatrix(); 
 
  glFlush(); 
 
 

void main(void) 

    myinit(); 
     
    auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,movelight); 
    auxReshapeFunc(reshape); 
    auxMainLoop(display); 

//end of sample 
///////////////////////////////////////////////////////////// 
在例子中,黄色的小球表示当前光源的位置,它的旋转导致了环状体表面受 
光照部分的光影的变化,每按下鼠标左键一下,光源就会作响应的旋转。 
 
-- 
※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 166.111.74.90]