OpenGl制作3D效果

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

#pragma comment(lib, "OpenGl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#pragma warning(disable : 4244)		// MIPS
#pragma warning(disable : 4136)		// X86
#pragma warning(disable : 4051)		// ALPHA
 
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 <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>

#pragma comment(lib, "OpenGl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#pragma warning(disable : 4244)		// MIPS
#pragma warning(disable : 4136)		// X86
#pragma warning(disable : 4051)		// ALPHA

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 
/ 
在例子中,黄色的小球表示当前光源的位置,它的旋转导致了环状体表面受光照部分的光影的变化,每按下鼠标左键一下,光源就会作响应的旋转。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值