荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: OPENGL(15)
发信站: BBS 荔园晨风站 (Fri Jan 22 08:21:51 1999), 转信


为什么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.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店