当前位置:文档之家› 第五章_OpenGL光照与材质(一)

第五章_OpenGL光照与材质(一)

第五章_OpenGL光照与材质(一)
第五章_OpenGL光照与材质(一)

第五章光照与材质

本章开始,将逐步介绍如何运用OpenGL技术进行真实感图形的绘制,充分展示三维图形虚拟世界的魅力!

OpenGL光照是计算机真实感图形绘制的非常重要的内容之一,没有光照,虚拟世界便没有了立体感、层次感和斑斓的色彩(如图5-1所示)。本章在建模、图形变换的基础上,将着重讲述隐藏面的消除、光照模型、明暗处理、光源设置、材质定义和相关的的计算机图形学概念等。

图5-1 经过光照计算的球和没有光照的球

考虑到真实感图形绘制的难度,只会讲述最基本的图形学概念和原理,大部分篇幅会从实践角度进行光照编程,使初学者顺利理解基本的OpenGL光照、材质等函数的应用方法,掌握最基本的真实感图形编程方法,引导读者快速进入OpenGL三维图形世界。

5.1 真实感图形基本概念

真实感图形绘制是计算机图形学的一个重要组成部分,它综合利用数学、物理学、计算机科学和其它科学知识在计算机图形设备上生成象彩色照片那样的具有真实感的图形。一般说来,用计算机在图形设备上生成真实感图形必须完成以下四个步骤:一是用建模,即用一定的数学方法建立所需三维场景的几何描述,场景的几何描述直接影响图形的复杂性和图形绘制的计算耗费;二是将三维几何模型经过一定变换转为二维平面透视投影图;三是确定场景中所有可见面,运用隐藏面消隐算法将视域外或被遮挡住的不可见面消去;四是计算场景中可见面的颜色,即根据基于光学物理的光照模型计算可见面投射到观察者眼中的光亮度大小和颜色分量,并将它转换成适合图形设备的颜色值,从而确定投影画面上每一象素的颜色,最终生成图形。

由于真实感图形是通过景物表面的颜色和明暗色调来表现景物的几何形状、空间位置以及表面材料的,而一个物体表面所呈现的颜色是由表面向视线方向辐射的光能决定的。在计算机图形学中,常采用一个既能表示光能大小又能表示其颜色组成的物理量即光亮度(luminance)或光强(intensity of light)来描述物体表面朝某方向辐射光能的颜色。采用这个物理量可以正确描述光在物体表面的反射、透射和吸收现象。

物体表面向空间给定方向辐射的光强可应用光照模型进行计算。简单的光照模型通常假定物体表面是光滑的且由理想材料构成,因此只考虑光源照射在物体表面产生的反射光,所生成的图形可以模拟不透明物体表面的明暗过渡,具有一定的真实感效果。复杂的光照模型除了考虑上述因素外,还要考虑周围环境的光对物体表面的影响。如光亮平滑的物体表面会将环境中其它物体映像在表面上,而通过透明物体也可看到其后的环境景象。这类光照模型称为整体光照模型,它能模拟出镜面映像、透明等较精致的光照效果。为了更真实的绘制图

形,还要考虑物体表面的细节纹理,这通常使用一种称为“纹理映射”(texture mapping )的技术把已有的平面花纹图案映射到物体表面上,并在应用光照模型时将这些花纹的颜色考虑进去,物体表面细节的模拟使绘制的图形更接近自然景物。 5.2 隐藏面的消除

从视点方向看,近的物体会遮掩远的物体,在三维世界中,被遮掩物体(或物体的一部分)是不可见的。将实体被遮掩的部分消除掉不显示称为隐藏面的消除。

在OpenGL 中,完成隐藏面的消除需要对程序作如下的调整。

首先,修改显示模式。把“auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA);”改为“auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA|| AUX_DEPTH);”。 其次,启动深度测试。即执行:glEnable(GL_DEPTH_TEST); 5.3 光照明模型

物体表面所呈现的颜色是由表面向视线方向辐射进入人眼中光决定的。建立数学模型模拟物体表面的光照明物理现象,按照数学模型计算物体表面向视线方向辐射进入人眼中的光亮度,即可获得像素所对应的物体上的可见点的颜色,这样绘制出来的图形具有较强的真实感,如图5-1。这些数学模型就称为明暗效应模型或者光照明模型。

当光照射到物体表面时,光可能被吸收、反射和透射,被物体吸收的部分转化为热,只有反射光、透射光能够进入人眼产生视觉效果,它们决定了物体所呈现的颜色。如果物体是不透明的,则透射光不存在,物体的颜色仅由反射光决定。这种情形正是简单光照模型需要考虑的,简单光照模型只考察光源直接照射下物体表面的反射情况。

OpenGL 只考虑简单光照明模型。 5.3.1 光学反射模型

通常物体表面的反射光可以认为包含三个分量:对环境光的反射、对特定光源的漫反射和镜面反射。 1、环境光的反射

环境光(ambient light)来自周围环境(如墙面)散射的光,在空间近似均匀分布,入射至物体表面后向空间各个方向均匀反射出去。物体对环境光的反射分量可表示为

a a I K I =, 10≤≤a K

其中Ia 是入射的环境光亮度,Ka 是环境光漫反射系数,它与物体表面性质有关。如果简单光照模型中仅考虑环境光的反射分量,则物体表面的亮度是一个恒定值,没有明暗的自然过渡。

2、散射(diffuse reflection): 光线的散射又称为漫反射,表示特定光源在物体表面的反射光中那些向空间各个方向均匀反射出去的光。兰伯特(Lambert)余弦定律指出:当点光源照射到一个散射体时,其表面反射光亮度和光源入射角(入射光线和表面法矢量的夹角)的余弦成正比,即

)cos(θl d I K I =,2

θ≤

≤,10≤≤d K

图5-2 漫反射模型示意图 图5-3 镜面反射模型示意图

其中I l 是入射的环境光亮度,Kd 是环境光漫反射系数,它与物体表面性质有关。

从上面的公式和图示可以看出,入射光与表面法向量的夹角越大,向外均匀散发的光线强度就越小,入射光与表面法向量的夹角越小,向外均匀散发的光线强度就越大,夹角为0时,散射光达到最大值。

3、镜面反射(specular reflection):

表示特定光源在物体表面的反射光中那些遵循反射定律的光。对于纯镜面,反射光和入射光对称地分布在表面法向的两侧(如图5-3所示)。对于一般光滑表面,可理解为由许多朝向不同的微小平面构成,入射光经许多微小平面反射后形成的反射光不再是单向的,而是分布于理想镜面反射方向的周围。通常采用余弦函数的幂次来模拟一般光滑表面的镜面反射光的空间分布。 镜面反射光的计算公式为

)(cos αn l s I K I =, 2

α≤

I l 是入射光亮度。Ks 是物体表面镜面反射系数,α为理想镜面反射方向与视线方向的夹角,n 为镜面反射光的会聚指数。 5.3.2 兰伯特反射光照模型

只考虑对环境光的反射分量和对特定光源的散射分量,则物体表面的反射光亮度为 :

)cos(θl d a a I K I K I +=,2

θ≤

≤,10≤+≤d a K K

适用于粗糙、无光泽的物体,如粉笔、黑板。对于擦亮的金属、光滑的塑料等光亮物体不能模拟(缺少镜面反射)。 5.3.3 Phong 光照模型

综合考虑环境光、散射光和镜面反射光,则物体表面的反射光亮度为

)(cos )cos(αθn l s l d a a I K I K I K I ++=

实际上光的亮度与传播距离的平方成反比,Il 为光源处的光亮度,光线抵达物体表面以及从物体表面反射进入观察者眼睛的过程中存在衰减的问题。漫反射分量和镜面反射分量应该乘以一个衰减因子,以取得远的物体看起来暗些的效果。当场景的投影变换采用透视投影时,Warnock 提出线性衰减因子1/d ,而Rommey 提出衰减因子1/dp 可以取得比较真实的效果。此时Phong 光照模型可以进一步描述为

[]

)(cos )cos(αθn

s d p

l a a K K K

d I I K I +++

= 其中d 是物体上当前考察点到视点的距离,K 是一个任意的常量,0=< P <=2。

计算物体上可见点光亮度时通常是将光亮度转换成为光栅图形显示器采用的RGB 三基色,这时计算需要在三个基色上分别进行。如果存在多个光源,则将效果线性相加。此时光照模型可以描述为

=+++=m

j j n s j d p l a a K K K

d I I K I j 1

)cos cos (αθ

∑=??

????

??????+++????

?

?????=m j l l l j n

s j d p a a a a j j j

b g r K K K

d b g r K 1)cos cos (1αθ

建立了光照模型后,就可以用于消隐算法中计算像素所对应的物体上可见点的亮度。

5.4 明暗处理

光照计算时需要用到多边形上点的法矢量,如果多边形上点的法矢量总是取多边形的面法矢,则由于不同平面片之间法矢量不连续,最终绘制出来的图像看起来呈多面体状(图5-4(a))。

(a)用不连续的面法矢量绘制结果(b)用取平均的点法矢量绘制结果

图5-4 漫反射模型示意图

解决的方法是:首先多边形的顶点法矢量不再简单的取为其所在多边形的面法矢,而是取为共享该顶点的所有多边形的面法矢的平均值;其次多边形内部点的法矢量也不再简单地取为多边形的面法矢,而是利用多边形顶点的法矢量通过双线性插值计算出。使用这种方法绘制的结果如图5-4(b)所示。

明暗处理有两种方法:一种是Phong明暗处理(插值法矢),一种是Gouraud明暗处理(插值颜色)。

5.4.1 Phong明暗处理(插值法矢)

如图5-5所示,P1、P2、P3是多边形顶点,其法矢量视为共该点的所有多边形法矢量的平均值。由P1、P2的法矢量可以线性插值计算出A点的法矢量,由P1、P3的法矢量可以线性插值计算出B点的法矢量,于是P点的法矢量可以由A、B点处的法矢量线性插值计算出,计算出P的法矢量后应用简单光照模型可以计算出P点的光亮度。

图5-5 P点法矢量的双线性插值

5.4.2 Gouraud明暗处理(插值颜色)

由于每个像素点都需要法向量插值和光照计算,Phong明暗处理计算量较大,一种简化的处理方法是先利用光照模型计算出多边形顶点处亮度,然后对亮度进行双线性插值,直接获得像素的颜色,如图5-5,P1、P2、P3是多边形顶点,其亮度已经计算出。A点的亮度可

以由P1、P2点的亮度线性插值计算出,B点的亮度可以由P1、P3点的亮度线性插值计算出,于是P点的亮度可以由A、B点的亮度线性插值计算出。

Phong明暗处理计算量远大于Gouraud明暗处理,但效果好。

5.5 OpenGL中的光照

在OpenGL简单光照模型中的几种光分为:辐射光(Emitted Light)、环境光(Ambient Light)、漫反射光(Diffuse Light,也称为散射光)、镜面光(Specular Light)。

辐射光,即发射光,直接从物体本身发出并且不受任何光源影响。

环境光是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向。一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同方向照射,而且在户外很少有其他物体反射的光。当环境光照到曲面上时,它在各个方向上均等地发散(类似于无影灯光)。

漫反射光,即散射光,来自一个方向,它垂直于物体时比倾斜时更明亮。一旦照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。

镜面光来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射。光亮的金属和塑料制品有很高非反射成分,而象粉笔和地毯等几乎没有反射成分。

5.5.1创建光源

光源有许多特性,如颜色、位置、方向等。选择不同的特性值,则对应的光源作用在物体上的效果也不一样,下面详细讲述定义光源特性的函数glLight*():

void glLight{if}[v](GLenum light , GLenum pname, TYPE param)

创建具有某种特性的光源。其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。共可指定最多八个光源。第二个参数pname指定光源特性,这个参数的辅助信息见表5-1所示。最后一个参数设置相应的光源特性值。

表5-1 函数glLight的参数说明

5.5.2 起动光源

在OpenGL中,必须明确指出光照是否有效或无效。如果光照无效,则只是简单地将当前颜色映射到当前顶点上去,不进行法向、光源、材质等复杂计算,那么显示的图形就没有真实感。要使光照有效,首先得启动光照计算,即:

glEnable(GL_LIGHTING);

若使光照无效,则调用gDisable(GL_LIGHTING)可关闭当前光照。然后,必须使所定义的每个光源有效,即:

glEnable(GL_LIGHT0);

其它光源类似,只是光源号不同而已。

5.6 定义法线

从前的论述中可知,物体的面或顶点必须有法线,这样才能正确光照。

为顶点指定法向量:

glNormal3fv(n0);

glVertex3fv(v0);

5.7 光照示例

5.7.1 一个简单的光照程序

【综合示例EP5-1】场景中绘制一个球体,然后加入一个简单的光照。

本例中,增加了对光源属性的设置。光源的位置作了显式设置,光源的其它属性均使用默认值。

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

1、定义光源位置

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

默认值是多少,参见表5-1。表5-1中的默认值只适用于光源1即GL_LIGHT0,其它光源的属性要分别设定。

#include "stdafx.h"

int nAngleY=0; // 沿Y轴旋转的角度

int nAngleX=0; // 沿X轴旋转的角度

int nAngleZ=0; // 沿Z轴旋转的角度

void CALLBACK ClockwiseRotateByX()

{

nAngleX--;

}

void CALLBACK CounterClockwiseRotateByX()

{

nAngleX++;

}

void CALLBACK ClockwiseRotateByZ()

{

nAngleZ--;

}

void CALLBACK CounterClockwiseRotateByZ()

{

nAngleZ++;

}

void CALLBACK ClockwiseRotateByY()

{

nAngleY--;

}

void CALLBACK CounterClockwiseRotateByY()

{

nAngleY++;

}

void myinit (void)

{

/* 将背景清为白色*/

glClearColor (0.0, 0.0,0.0, 1.0);

glShadeModel (GL_SMOOTH);

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

glDepthFunc(GL_LESS);

}

void CALLBACK reshape(GLsizei w, GLsizei h)

{

if (!h) return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-500.0, 500.0, -500.0*(GLfloat)h/(GLfloat)w,

500.0*(GLfloat)h/(GLfloat)w, -500, 500);

else

glOrtho (-500.0*(GLfloat)w/(GLfloat)h,

500.0*(GLfloat)w/(GLfloat)h, -500.0, 500.0, -500, 500);

glMatrixMode(GL_MODELVIEW);

}

void CALLBACK display(void)

{

glLoadIdentity();

glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除背景

glRotated(nAngleX,1,0,0);

glRotated(nAngleY,0,1,0);

glRotated(nAngleZ,0,0,1);

glLineStipple(1, 0x3F07); // 指定点划格式

glEnable(GL_LINE_STIPPLE); // 进入点划模式

glBegin(GL_LINES);

// X轴:红

glColor3f (1.0, 0, 0);

glVertex3d(-490,0,0);

glVertex3d(490,0,0);

// Y轴:绿

glColor3f (0.0, 1.0, 0);

glVertex3d(0,-490,0);

glVertex3d(0,490,0);

// Z轴:蓝

glColor3f (0.0, 0.0, 1);

glVertex3d(0,0,-490);

glVertex3d(0,0,490);

glEnd();

glDisable(GL_LINE_STIPPLE);//离开点划模式

glColor3f (1.0, 0.0, 0);

auxSolidSphere(300);

auxSwapBuffers();

}

int _tmain(int argc, _TCHAR* argv[])

{

auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA|AUX_DEPTH);

auxInitPosition (0, 0, 1000, 700);

auxInitWindow ("[简单的光照]");

myinit ();

auxKeyFunc (AUX_LEFT, ClockwiseRotateByY);

auxKeyFunc (AUX_RIGHT, CounterClockwiseRotateByY);

auxKeyFunc (AUX_UP, ClockwiseRotateByX);

auxKeyFunc (AUX_DOWN, CounterClockwiseRotateByX);

auxKeyFunc (AUX_D, ClockwiseRotateByZ);

auxKeyFunc (AUX_d, ClockwiseRotateByZ);

auxKeyFunc (AUX_U, CounterClockwiseRotateByZ);

auxKeyFunc (AUX_u, CounterClockwiseRotateByZ);

auxReshapeFunc(reshape);//回调函数

auxMainLoop(display);

return 0;

}

【综合示例EP5-2】场景中绘制一个球体,然后加入一个简单的光照,坐标轴不参与光照。#include "stdafx.h"

int nAngleY=0; // 沿Y轴旋转的角度

int nAngleX=0; // 沿X轴旋转的角度

int nAngleZ=0; // 沿Z轴旋转的角度

void CALLBACK ClockwiseRotateByX()

{

nAngleX--;

}

void CALLBACK CounterClockwiseRotateByX()

{

nAngleX++;

}

void CALLBACK ClockwiseRotateByZ()

{

nAngleZ--;

}

void CALLBACK CounterClockwiseRotateByZ()

{

nAngleZ++;

}

void CALLBACK ClockwiseRotateByY()

{

nAngleY--;

}

void CALLBACK CounterClockwiseRotateByY()

{

nAngleY++;

}

void myinit (void)

{

/* 将背景清为白色*/

glClearColor (0.0, 0.0,0.0, 1.0);

glShadeModel (GL_SMOOTH);

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

glDepthFunc(GL_LESS);

}

void CALLBACK reshape(GLsizei w, GLsizei h)

{

if (!h) return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-500.0, 500.0, -500.0*(GLfloat)h/(GLfloat)w, 500.0*(GLfloat)h/(GLfloat)w, -500, 500);

else

glOrtho (-500.0*(GLfloat)w/(GLfloat)h,

500.0*(GLfloat)w/(GLfloat)h, -500.0, 500.0, -500, 500);

glMatrixMode(GL_MODELVIEW);

}

void CALLBACK display(void)

{

glLoadIdentity();

glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除背景

glRotated(nAngleX,1,0,0);

glRotated(nAngleY,0,1,0);

glRotated(nAngleZ,0,0,1);

glDisable(GL_LIGHTING);

glDisable(GL_LIGHT0);

glLineStipple(1, 0x3F07); // 指定点划格式

glEnable(GL_LINE_STIPPLE); // 进入点划模式

glBegin(GL_LINES);

// X轴:红

glColor3f (1.0, 0, 0);

glVertex3d(-490,0,0);

glVertex3d(490,0,0);

// Y轴:绿

glColor3f (0.0, 1.0, 0);

glVertex3d(0,-490,0);

glVertex3d(0,490,0);

// Z轴:蓝

glColor3f (0.0, 0.0, 1);

glVertex3d(0,0,-490);

glVertex3d(0,0,490);

glEnd();

glDisable(GL_LINE_STIPPLE);//离开点划模式

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glColor3f (1.0, 0.0, 0);

auxSolidSphere(300);

auxSwapBuffers();

}

int _tmain(int argc, _TCHAR* argv[])

{

auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA|AUX_DEPTH);

auxInitPosition (0, 0, 1000, 700);

auxInitWindow ("[简单的光照]");

myinit ();

auxKeyFunc (AUX_LEFT, ClockwiseRotateByY);

auxKeyFunc (AUX_RIGHT, CounterClockwiseRotateByY);

auxKeyFunc (AUX_UP, ClockwiseRotateByX);

auxKeyFunc (AUX_DOWN, CounterClockwiseRotateByX);

auxKeyFunc (AUX_D, ClockwiseRotateByZ);

auxKeyFunc (AUX_d, ClockwiseRotateByZ);

auxKeyFunc (AUX_U, CounterClockwiseRotateByZ);

auxKeyFunc (AUX_u, CounterClockwiseRotateByZ);

auxReshapeFunc(reshape);//回调函数

auxMainLoop(display);

return 0;

}

【综合示例EP5-3】修改实验五的模型,使其从线框模型变为实体模型,简单定制一个光源,增加光照。

本例中,增加了对光源属性的设置。

GLfloat ambient[] = { 0.5, 0.0, 0.0, 1.0 };

GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat diffuse[] = { 0.5, 0.5, 0.5, 1.0 };

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);

glLightfv (GL_LIGHT0, GL_SPECULAR, specular);

glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);

1、定义光源位置

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

2、设置光源位置

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

3、定义环境光

GLfloat ambient[] = { 0.5, 0.0, 0.0, 1.0 };

4、设置环境光

glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);

5、定义散射光

GLfloat diffuse[] = { 0.5, 0.5, 0.5, 1.0 };

6、设置散射光

glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);

7、定义镜面光

GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };

8、设置镜面光

glLightfv (GL_LIGHT0, GL_SPECULAR, specular);

9、定义镜面光材质

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess[] = { 128.0 };

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); // 全部反射镜面光glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); // 镜面光斑的大小

10、激活自动法线

glEnable(GL_AUTO_NORMAL);

glEnable(GL_NORMALIZE);

详细的程序如下所示:

#include "stdafx.h"

int nAngleY=0; // 沿Y轴旋转的角度

int nAngleX=0; // 沿X轴旋转的角度

int nAngleZ=0; // 沿Z轴旋转的角度

void CALLBACK ClockwiseRotateByX()

{

nAngleX--;

}

void CALLBACK CounterClockwiseRotateByX()

{

nAngleX++;

}

void CALLBACK ClockwiseRotateByZ()

{

nAngleZ--;

}

void CALLBACK CounterClockwiseRotateByZ()

{

nAngleZ++;

}

void CALLBACK ClockwiseRotateByY()

{

nAngleY--;

}

void CALLBACK CounterClockwiseRotateByY()

{

nAngleY++;

}

void myinit (void)

{

/* 将背景清为白色*/

glClearColor (0.0, 0.0,0.0, 1.0);

glShadeModel (GL_SMOOTH);

GLfloat ambient[] = { 0.5, 0.0, 0.0, 1.0 };

GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat diffuse[] = { 0.5, 0.5, 0.5, 1.0 };

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess[] = { 128.0 };

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);

glLightfv (GL_LIGHT0, GL_SPECULAR, specular);

glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glDepthFunc(GL_LEQUAL);

glEnable(GL_DEPTH_TEST);

glEnable(GL_AUTO_NORMAL);

glEnable(GL_NORMALIZE);

}

void CALLBACK reshape(GLsizei w, GLsizei h)

{

if (!h) return;

glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-500.0, 500.0, -500.0*(GLfloat)h/(GLfloat)w,

500.0*(GLfloat)h/(GLfloat)w, -500, 500);

else

glOrtho (-500.0*(GLfloat)w/(GLfloat)h,

500.0*(GLfloat)w/(GLfloat)h, -500.0, 500.0, -500, 500);

glMatrixMode(GL_MODELVIEW);

}

void CALLBACK display(void)

{

glLoadIdentity();

glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除背景

glRotated(nAngleX,1,0,0);

glRotated(nAngleY,0,1,0);

glRotated(nAngleZ,0,0,1);

glLineStipple(1, 0x3F07); // 指定点划格式

glEnable(GL_LINE_STIPPLE); // 进入点划模式

glBegin(GL_LINES);

// X轴:红

glColor3f (1.0, 0, 0);

glVertex3d(-490,0,0);

glVertex3d(490,0,0);

// Y轴:绿

glColor3f (0.0, 1.0, 0);

glVertex3d(0,-490,0);

glVertex3d(0,490,0);

// Z轴:蓝

glColor3f (0.0, 0.0, 1);

glVertex3d(0,0,-490);

glVertex3d(0,0,490);

glEnd();

glDisable(GL_LINE_STIPPLE);//离开点划模式

glColor3f (1.0, 0.0, 0);

glPushMatrix(); // 车体

glTranslatef(0,210,0);

auxSolidBox(600, 20, 400);

glPopMatrix();

glPushMatrix(); // 左前腿

glTranslatef(-260,100,180);

auxSolidBox(25, 200, 25);

glPopMatrix();

glPushMatrix(); // 左后腿

glTranslatef(-260,100,-180);

auxSolidBox(25, 200, 25);

glPopMatrix();

glPushMatrix(); // 右前腿

glTranslatef(260,100,180);

auxSolidBox(25, 200, 25);

glPopMatrix();

glPushMatrix(); // 右后腿

glTranslatef(260,100,-180);

auxSolidBox(25, 200, 25);

glPopMatrix();

glPushMatrix(); // 球

glTranslatef(-200,260,0);

auxSolidSphere(40);

glPopMatrix();

glPushMatrix(); // 八面体

glTranslatef(-200,260,160);

auxSolidOctahedron(40);

glPopMatrix();

glPushMatrix(); // 圆锥体

glTranslatef(-60,220,120);

glRotatef(-90,1,0,0);

auxSolidCone(60, 100);

glPopMatrix();

glPushMatrix(); //

glTranslatef(60,270,0);

glRotatef(40,0,1,0);

auxSolidTeapot(70);

glPopMatrix();

glPushMatrix(); //

glTranslatef(240,360,0);

auxSolidCylinder(40,140);

glPopMatrix();

auxSwapBuffers();

}

int _tmain(int argc, _TCHAR* argv[])

{

auxInitDisplayMode (AUX_DOUBLE | AUX_RGBA);

auxInitPosition (0, 0, 1000, 700);

auxInitWindow ("OpenGL多景物光照");

myinit ();

auxKeyFunc (AUX_LEFT, ClockwiseRotateByY);

auxKeyFunc (AUX_RIGHT, CounterClockwiseRotateByY);

auxKeyFunc (AUX_UP, ClockwiseRotateByX);

auxKeyFunc (AUX_DOWN, CounterClockwiseRotateByX);

auxKeyFunc (AUX_D, ClockwiseRotateByZ);

auxKeyFunc (AUX_d, ClockwiseRotateByZ);

auxKeyFunc (AUX_U, CounterClockwiseRotateByZ);

auxKeyFunc (AUX_u, CounterClockwiseRotateByZ);

auxReshapeFunc(reshape);//回调函数

auxMainLoop(display);

return 0;

}

【综合示例EP5-4】按正确的顶点顺序定义四边形,为其中的每个四边形的顶点指定法线。创建光源,增加光照。

关键代码如下:

glBegin(GL_QUADS);

glNormal3f(0,1,0);

glVertex3d (-1,1,1);

glVertex3d (1,1,1);

glVertex3d (1,1,-1);

glVertex3d (-1,1,-1);

glNormal3f(0,-1,0);

glVertex3d (-1,-1,1);

glVertex3d (1,-1,1);

glVertex3d (1,-1,-1);

glVertex3d (-1,-1,-1);

glNormal3f(0,0,1);

glVertex3d (-1,1,1);

glVertex3d (-1,-1,1);

glVertex3d (1,-1,1);

glVertex3d (1,1,1);

glNormal3f(0,0,-1);

glVertex3d (-1,1,-1);

glVertex3d (-1,-1,-1);

glVertex3d (1,-1,-1);

glVertex3d (1,1,-1); glEnd();

OpenGL入门学习之七——使用光照来表现立体感

OpenGL入门学习之七——使用光照来表现立体感 2009-01-07 11:49 从生理学的角度上讲,眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱的变化的反应,比对于颜色变化的反应来得灵敏。因此对于人类而言,光线很大程度上表现了物体的立体感。 请看图1,图中绘制了两个大小相同的白色球体。其中右边的一个是没有使用任何光照效果的,它看起来就像是一个二维的圆盘,没有立体的感觉。左边的一个是使用了简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体。 图1 OpenGL对于光照效果提供了直接的支持,只需要调用某些函数,便可以实现简单的光照效果。但是在这之前,我们有必要了解一些基础知识。 一、建立光照模型 在现实生活中,某些物体本身就会发光,例如太阳、电灯等,而其它物体虽然不会发光,但可以反射来自其它物体的光。这些光通过各种方式传播,最后进入我们的眼睛——于是一幅画面就在我们的眼中形成了。 就目前的计算机而言,要准确模拟各种光线的传播,这是无法做到的事情。比如一个四面都是粗糙墙壁的房间,一盏电灯所发出的光线在很短的时间内就会经过非常多次的反射,最终几乎布满了房间的每一个角落,这一过程即使使用目前运算速度最快的计算机,也无法精确模拟。不过,我们并不需要精确的模拟各种光线,只需要找到一种近似的计算方式,使它的最终结果让我们的眼睛认为它是真实的,这就可以了。 OpenGL在处理光照时采用这样一种近似:把光照系统分为三部分,分别是光源、材质和光照环境。光源就是光的来源,可以是前面所说的太阳或者电灯等。材质是指接受光照的各种物体的表面,由于物体如何反射光线只由物体表面决定(OpenGL中没有考虑光的折射),材质特点就决定了物体反射光线的特点。光照环境是指一些额外的参数,它们将影响最终的光照画面,比如一些光线经过多次反射后,已经无法分清它究竟是由哪个光源发出,这时,指定一个“环境亮度”参数,可以使最后形成的画面更接近于真实情况。

实验7 OpenGL光照

实验7 OpenGL光照 一、实验目的 了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。 二、实验内容 (1)下载并运行Nate Robin教学程序包中的lightmaterial 程序,试验不同的光照与材质系数; (2)运行示范代码1,了解光照与材质函数使用。 三、实验原理 为在场景中增加光照,需要执行以下步骤: (1)设置一个或多个光源,设定它的有关属性; (2)选择一种光照模型; (3)设置物体的材料属性。 具体见教材第8章8.6节用OpenGL生成真实感图形的相关内容。 四、实验代码 #include #include static int year =0,day=0; void init(void){ GLfloat mat_specular[]={1.0,1.0,1.0,1.0}; GLfloat mat_shininess[]={50.0}; GLfloat light_position[]={1.0,1.0,1.0,0.0};

GLfloat white_light[]={1.0,1.0,1.0,1.0}; GLfloat Light_Model_Ambient[]={0.2,0.2,0.2,1.0}; glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_SMOOTH); //glMaterialfv(材质指定,单值材质参数,具体指针); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);//镜面反射光的反射系数 glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);//镜面反射指数 //glLightfv(光源,属性名,属性值); glLightfv(GL_LIGHT0, GL_POSITION, light_position); //光源位置 glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light); //漫放射光分量强度 glLightfv(GL_LIGHT0, GL_SPECULAR, white_light); //折射光强度 glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Light_Model_Ambient); //光源2 GL_LIGHT1 GLfloat mat_specular1[]={1.0,1.0,1.0,1.0}; GLfloat mat_shininess1[]={50.0}; GLfloat light_position1[]={0.0,0.0,0.0,0.0}; GLfloat red_light[]={1.0,0.0,0.0,1.0}; GLfloat Light_Model_Ambient1[]={0.2,0.2,0.2,1.0}; glLightfv(GL_LIGHT1, GL_POSITION, light_position1); //光源位置 glLightfv(GL_LIGHT1, GL_DIFFUSE, red_light); //漫放射光分量强度 glLightfv(GL_LIGHT1, GL_SPECULAR, red_light); //折射光强度 glLightModelfv(GL_LIGHT_MODEL_AMBIENT,Light_Model_Ambient1); //开启灯光

第三章光照模型纹理映射

第三章光照模型及纹理映射 基本光照模型 1.在现实生活中,当光照在非透明物体上时,部分光线被物体吸收,剩余的部分光线被反射。人眼依靠这种反射光来感知物体的形状、颜色和其他细节。从光源投向物体的光称为入射光,从物体表面反射回的光称为反射光。 1.1光照模型概述 当光照射到物体表面上时,将出现3种情况: ●光从物体表面反射,形成反射光 ●光穿透物体,形成透射光 ●光被物体吸收,转化成为物体的内能 在上述三种情形的光线中,通常只有前2种情形的光线会对人眼产生视觉效果,使人察觉到物体的色彩变化。 OpenGL用一种近似的光照模型模拟现实世界的光照效果。在该模型中,仅当物体表面吸收和反射光线时,光源才会起做作用。每一个物体表面都假定是由某种特性的材料构成的。一种材料可能发出自己的光线,也可能在各个方向上发散一些射入的光线,还有可能像镜子一样在某个方向强烈地反射入射光。 1.2光照分量 在OpenGL的简化光照模型中,将光照分为4个独立的组成部分:辐射光、环境光、漫反射光和镜面反射光。 1)辐射光

辐射光是直接从物体或光源发出的,不受任何其他光源的影响。 2)环境光 环境光是这样一种光线,它被环境多次反射,以致于连初始 方向也难以确定。这种光线看起来就像来自于所有的方向, 当它照在一个物体表面时,它在所有的方向上等量地反射。 3)漫反射光 在被照射物体表面的反射光中,那些均匀地向各个方向反射 出去的光,称为漫反射光,如黑板反射就属于漫反射光 4)镜面反射光 镜面反射光是指超一定方向的反射光,如点光源照射光滑金 属球表面时,会在球表面形成一个特别亮的区域,呈现所谓 的高亮(Highlight>,这就是光源在该物体表面形成的镜面反射光(Specular Light>。点光源照射表面光滑的物体时,高亮区域小而亮;而点光源照射表面粗糙的物体时,高亮区域大而不亮。 1.3创建光源 光源有许多特性,如颜色、位置、方向等。不同特性的光源,作用在物体上的效果是不一样的。 1.3.1定义一个简单光源 在OpenGL中,定义一个光源是由函数glLight(>来实现的,该函数的原型为:void glLight(GLenum light,GLenum pname>; light为一个光源,pname为光源light指定一个单值的光源参数,

实验七 OPENGL光照效果

1.实验七OpenGL光照效果(选做) 1.实验七:OpenGL光照效果。 2.实验目的:通过上机编程,熟悉并掌握OpenGL中光照效果的制造方法。 3.实验要求: (1)先做实验项目:实验六“OpenGL组合图形”。 (2)每人一组,独立完成。 (3)利用OpenGL提供的颜色、光源、材质设置,对实验六“OpenGL组合图形” 中自己设计的物体设置绘制颜色和材质参数,并在场景中添加光源,形成一 定的光照明暗效果。 4.实验原理及内容: 在现实世界中,光线和物体的材质共同决定了物体在人眼中的效果。OpenGL 中则涉及到绘制颜色、物体的材质参数、场景中的光源颜色和位置,以此达到一定 的真实感光照效果。 (1)颜色: OpenGL通过指定红、绿、蓝(RGB)三个成分的各自亮度来确定颜色,有时还有第四个成分alpha:glColor*(red,green,blue[,alpha]); glColor()函数设置当前的绘图颜色,red、green和blue分别为红、绿、蓝的亮度,alpha为透明度,取值均为0.0~1.0。在该函数之后绘制的所有物体都将使用该 颜色。 (2)光线: OpenGL的光照模型中将光源分成四种: 发射光:一个物体本身就是一个发光源,如太阳、电灯等,这种光不受其它任何光源的影响。 环境光:从光源出发后光线被环境多次反射,以致没有明确的方向,或者说来自于所有的方向。被环境光照射的物体,各个表面都均等受光。 散射光:来自于某个方向,被物体表面均匀地反射,例如荧光照明、窗口射入的阳光等。 镜面光:来自于一个方向,被物体强烈地反射到另一个特定的方向。高亮

度的镜面光往往能在被照射的物体表面产生亮斑,如金属球上的高光区。 对于散射光和镜面光,入射角度、距离和衰减因子还会影响到最终的光照效果。 除了物体本身的发射光以外,通常意义上的光并不会是单纯的环境光、散射光或镜面光,而是由这三种类型的光混合组成的。 在OpenGL中,光也是采用RGBA值来定义的,分别描述光线中红绿蓝各成分的相对亮度。计算混合光的亮度时,则把相应的颜色亮度叠加即可,例如:环境光为(R1,G1,B1),散射光为(R2,G2,B2),镜面光为(R3,G3,B3),则混合后的光线为(R1+R2+R3,G1+G2+G3,B1+B2+B3)。 (3)材质: 材质是物体本身的一种属性,主要用来表征物体对不同颜色、不同类型光线的反射、吸收性能。 在OpenGL中设置材质参数,就是要指定这种材质对环境光、散射光、镜面光的反射能力,有时还需要说明该种材质是否具有发光能力。 在最终绘制每个像素时,OpenGL自行将物体材质的各分量与光线的各分量相乘再叠加,从而得到每个像素的RGB值。例如:光线为(R,G,B),材质为(MR,MG, MB),则最终绘制时颜色为(MR*R,MG*G,MB*B)。 (4)获得光照效果的一般过程为: a)使能光照:glEnable(GL_LIGHTING); b)设置一种光照模式:glLightModel*(); 如果只需要普通的无方向的环境光: GLfloat light_ambient[]={red,green,blue,alpha};//环境光的分值 //全局环境光的默认取值为(0.2,0.2,0.2,1.0) glLightModel*(GL_LIGHT_MODEL_AMBIENT,light_ambient); 如果需要在某个具体位置上放置某个光源,例如: GLfloat light_ambient[]={0.3,0.3,0.3,1.0};//环境光 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); GLfloat light_diffuse[]={0.7,0.7,0.7,1.0};//散射光 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); GLfloat light_specular[]={1.0,1.0,1.0,1.0};//镜面光 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);

OpenGL光照与材质

OpenGL---------光照的基本知识 从生理学的角度上讲,眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱的变化的反应,比对于颜色变化的反应来得灵敏。因此对于人类而言,光线很大程度上表现了物体的立体感。 请看图1,图中绘制了两个大小相同的白色球体。其中右边的一个是没有使用任何光照效果的,它看起来就像是一个二维的圆盘,没有立体的感觉。左边的一个是使用了简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体。 OpenGL对于光照效果提供了直接的支持,只需要调用某些函数,便可以实现简单的光照效果。但是在这之前,我们有必要了解一些基础知识。 一、建立光照模型 在现实生活中,某些物体本身就会发光,例如太阳、电灯等,而其它物体虽然不会发光,但可以反射来自其它物体的光。这些光通过各种方式传播,最后进入我们的眼睛——于是一幅画面就在我们的眼中形成了。 就目前的计算机而言,要准确模拟各种光线的传播,这是无法做到的事情。比如一个四面都是粗糙墙壁的房间,一盏电灯所发出的光线在很短的时间内就会经过非常多次的反射,最终几乎布满了房间的每一个角落,这一过程即使使用目前运算速度最快的计算机,也无法精确模拟。不过,我们并不需要精确的模拟各种光线,只需要找到一种近似的计算方式,使它的最终结果让我们的眼睛认为它是真实的,这就可以了。 OpenGL在处理光照时采用这样一种近似:把光照系统分为三部分,分别是光源、材质和光照环境。光源就是光的来源,可以是前面所说的太阳或者电灯等。材质是指接受光照的各种物体的表面,由于物体如何反射光线只由物体表面决定(OpenGL中没有考虑光的折射),材质特点就决定了物体反射光线的特点。光照环境是指一些额外的参数,它们将影响最终的光照画面,比如一些光线经过多次反射后,已经无法分清它究竟是由哪个光源发出,这时,指定一个“环境亮度”参数,可以使最后形成的画面更接近于真实情况。 在物理学中,光线如果射入理想的光滑平面,则反射后的光线是很规则的(这样的反射称为镜面反射)。光线如果射入粗糙的、不光滑的平面,则反射后的光线是杂乱的(这样的反射称为漫反射)。现实生活中的物体在反射光线时,并不是绝对的镜面反射或漫反射,但可以看成是这两种反射的叠加。对于光源发出的光线,可以分别设置其经过镜面反射和漫反射后的光线强度。对于被光线照射的材质,也可以分别设置光线经过镜面反射和漫反射后的光线强度。这些因素综合起来,就形成了最终的光照效果。 二、法线向量 在OpenGL中,法线的方向是用一个向量来表示。不幸的是,OpenGL并不会根据你所指定的多边形各个顶点来计算出这些多边形所构成的物体的表面的每个点的法线(这话听着有些迷糊),通常,为了实现光照效果,需要在代码中为每一个顶点指定其法线向量。 指定法线向量的方式与指定颜色的方式有雷同之处。在指定颜色时,只需要指定每一个顶点的颜色,OpenGL就可以自行计算顶点之间的其它点的颜色。并且,颜色一旦被指定,除非再指定新的颜色,否则以后指定的所有顶点都将以这一向量作为自己的颜色。在指定法线向量时,只需要指定每一个顶点的法线向量,OpenGL会自行计算顶点之间的其它点的法线向量。并且,法线向量一旦被指定,除非再指定新的法线向量,否则以后指定的所有顶点都将以这一向量作为自

OpenGL中的光照模型

OpenGL中的光照模型 一、OpenGL的光照模型 在OpenGL的简单光照模型中反射光可以分成三个分量,环境反射光(Ambient Light)、漫反射光(Diffuse Light)和镜面反射光(Specular Light): a、环境光Ambient,是由光源发出经环境多次散射而无法确定其入射方向的光,即似乎来自所有方向。当环境光照到曲面上时,它在各个方向上均等地发散(类似于无影灯光)。特征:入射方向和出射方向均为任意方向。 b、漫射光Diffuse,来自特定方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去,效果为无论视点在哪里它都一样亮。特征:入射方向唯一、出射方向为任意方向。 c、镜面光Specular,来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射。特征:入射方向和出射方向均唯一。 二、创建光源 定义光源特性的函数:glLight*(light , pname, param) 其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7;第二个参数pname指定光源特性,这个参数的辅助信息见表1所示;最 GL_LIGHT0,其他几个光源的GL_DIFFUSE和GL_SPECULAR缺省值为 (0.0,0.0,0.0,1.0)。 三、启用光源和明暗处理 如果光照无效,则只是简单地将当前颜色映射到当前顶点上去,不进行法向、光源、材质等复杂计算。要启用光照或关闭光照,调用函数:glEnable(GL_LIGHTING) 或glDisable(GL_LIGHTING)。 启用光照后必须调用函数glEnable(GL_LIGHT0) ,使所定义的光源有效。其它光

OpenGL光照

计算机图形学实验指导(三) – OpenGL光照 1.光照简介 采用光照要做的工作包括:创建光源,激活光照以及光源,以及定义物体的材质。创建光源是要定义光源的特征,物体的材质则与光源一起决定到达人眼的光的颜色。若光源颜色为(LR,LG,LB),材质颜色为(MR,MG,MB),则到达人眼的颜色为(LR*MR, LG*MG, LB*MB)。 2.简单光照模型 一般来说,反射光可以分成三个分量,即环境反射、漫反射和镜面反射。环境反射分量假定入射光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去,通常物体表面还会受到从周围环境来的反射光(如来自地面、天空、墙壁等的反射光)的照射,这些光常统称为环境光(Ambient Light);漫反射分量表示特定光源在景物表面的反射光中那些向空间各方向均匀反射出去的光,这些光常称为漫射光(Diffuse Light);镜面反射光为朝一定方向的反射光,如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光(Specular Light)。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。 3.OpenGL光源 光源有许多特性,如颜色、位置、方向等。选择不同的特性值,则对应的光源作用在物体上的效果也不一样,下面的函数定义了OpenGL的光源。 void glLightfv(GLenum light , GLenum pname, TYPE param) 其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。第二个参数pname指定光源特性,这个参数的具体信息见下表所示。最后一个参数设置相应的光源特性值。 pname 参数名说明 GL_AMBIENT RGBA模式下环境光 GL_DIFFUSE RGBA模式下漫反射光 GL_SPECULAR RGBA模式下镜面光 GL_POSITION 光源位置齐次坐标(x,y,z,w) GL_SPOT_DIRECTION 点光源聚光方向矢量(x,y,z) GL_SPOT_EXPONENT 点光源聚光指数 GL_SPOT_CUTOFF 点光源聚光截止角 例如:下面定义了一个位置在(1,1,1),没有环境光,镜面反射光和漫反射光都为白光的光源GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light_ambient [] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat light_diffuse [] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT , light_ambient ); glLightfv(GL_LIGHT0, GL_DIFFUSE , light_diffuse );

Opengl实验报告及源代码实验六 颜色与光照

南昌大学实验报告 学生姓名:学号:专业班级: 实验类型:□验证□综合□设计□创新实验日期:2018.11 实验成绩: 一、实验名称 实验六颜色与光照 二、实验内容 1.指定几何模型的绘制颜色,使用平滑着色模式用多种不同的颜色绘制多边形; 2.通过定义光源、材质和光照模型属性渲染物体的光照效果; 3.创建一个3D虚拟场景,利用定向光、点光源和聚光灯等不同光源实现3D场景的光 照效果。 三、实验目的 1.了解RGBA颜色的实现原理,掌握利用Flat和Smooth着色模式来绘制不同颜色的物 体的方法; 2.掌握OpenGL光照模型,理解光源、材质和光照模型如何综合影响物体的光照效果。 3.掌握定向光、点光源和聚光灯的不同属性及三种光源光照效果的计算方法。 四、实验步骤 1.建立立方体几何模型。定义立方体顶点的位置坐标和纹理坐标,设置不同立方体在 世界坐标系中的位置: // Set up vertex data (and buffer(s)) and attribute pointers GLfloat vertices[] = { // Positions // Normals // Texture Coords -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,

基于OpenGL的三维图形的绘制_吴爱兰

PSLIBLINGS|WS_CLIPCHILDREN;(2)OnCreate 为了使OpenGL能在绘图表面(窗口或位图)上绘制图象,必须先对绘图表面进行初始化,既通过对象素格式的描述(分配并填充PIXELFORMATDESCRIPTOR结构)、选择(通过ChoosePixelFormat函数)和设置(通过SetPixelFormat函数),规定绘图表面的某些属性。此外,只有在OpenGL环境中,OpenGL命令才能被接受并执行,所以我们必须创建OpenGL绘制环境(由函数wgCreatContext完成)。在必要的情况下,还将进一步创建调色板。我们选择视图类消息句柄OnCreate作为完成这些工作的恰当场所。 (3)OnSize 窗口大小变动时会触发消息句柄,OnSize在此函数中,我们的目的是建立3D OpenGL坐标与2D屏幕坐标之间的映射,体现为做三件事: 获取当前的绘制环境。这个使用wgMakeCurrent函数来完成,函数如下所示,BOOL bResult=wgMakeCurrent(dc.m_Hdc,m_hrc); 设置映射方式。OpenGL大量使用矩阵运算,因为场地景到屏幕的变换,以及3D图形的3D旋转、平移和缩放都是采用矩阵变换实现的。在OnSize函数中,我们使用投影栈来设置我们观察物体的方法,总共用到四个函数,如下所示, GLdouble gldAspect=(GLdouble)cx/(GLdouble)cy; GlMatrixMode(GL_PROJECTION);//指定所使用的矩阵栈 GlLoadIdentity(); //清空矩阵栈GlPerspective(45.0,gldAspect,1.0,10.0);//设定用户的可见区域 GlViewport(0,0,cx,xy); //设置在用户区上的绘制区域 激活当前绘制环境。在使用多个绘 基于OpenGL的三维图形的绘制 吴爱兰1 楼建列2 1、浙江公路机械技工学校 310014 2、浙江经济职业技术学院教育技术中心 310018 一、OpenGL的简介 目前OpenGL是工业界公认的先进而强大的三维图形编程接口(3D API)。它有着功能完备的二维和三维图形处理能力,是理想的三维应用程序开发工具。它包含将近120个绘制点、线和多边形等3D图形原语的绘制命令,及其他众多的功能函数,能处理各种图形基本元素及图形特征效果,如明暗度、纹理贴图、Z缓冲、反走样、光照模型等。 OpenGL是Visual C++中附带的SDK(Software Development Kit)。它直接使用绘制环境,间接使用设备环境,因此设备环境中的当前画笔、画刷、颜色、字体等均对OpenGL绘制无任何影响。甚至GDI映射模式都对OpenGL不起作用。所以,使用MFC开发应用程序并采用OpenGL进行绘制,必须遵循一定的规范,先建立OpenGL绘制环境,然后才能使用OpenGL命令。 二、OpenGL绘图环境的设置 2.1 准备工作 为了能够使用OpenGL命令,必须要在预编译头文件中加入两个库函数,openggl32.lib、glu32.lib,如果还需要使用辅助库中所定义的函数,则需要再加入 glaux.lib 库函数。 2.2 消息句柄 (1)PrecreateWindow 为了使用OpenGL绘制,必须先在有关窗口的客户区中进行OpenGL初始化,即需要重载消息句柄PrecreateWindow并将窗口风格规定为:cs_style|=WS_SLI 制环境的情况下,即将离开时,应调用wglMakeCurrent来激活当前绘制环境,wglMakeCurrent(NULL,NULL); (4)OnDraw 此函数真正负责绘制3D图象,包括以下步骤: 在DC中选择并实现调色板; 调用wglMakeCurrent使绘制环境成为当前的; 调用OpenGL命令绘制场景; 如果使用双缓存像素格式,交替绘制缓存; 重新为DC选择原始的调色板。经过上述一系列步骤以后,OpenGL的绘图环境就已经设置完成,下面就可以通过OpenGL的绘图命令进行图形的绘制。 三、三维图形的绘制 设置完成OpenGL的绘图环境后,就可以在VC++中使用OpenGL三维函数库进行图形的绘制。函数的使用如下: glPolygonMode函数是用来选择多边形光栅化模式的。它的原型是voidglPolygonMode(Glenum face ,Glenummode),其中,参数face用来指定mode应用的多边形,对于正面多边形,必须为GL_FRONT,对于反面多边形,必须为GL_BACK,对于正面和反面多边形,必须为GL_FRONT_AND_BACK。参数mode用来指定多边形光栅化的方式,可以选择的值为GL_POINT、GL_LINE和GL_FILL。 glBegin和glEnd函数用来限定一组或多组图原的顶点定义。OpenGL绘制的所有复杂的三维物体都是由一定数量的基本图形元素(点、线、多边形)构成。曲线和曲面分别是由一系列直线段和多边形近似得到。基本图元类型由glBegin的参数设定,它的参数只有一个变量,该

图形学第十一课--OpenGL特殊光处理

第十四章 OpenGL特殊光处理 目录 14.1 光照模型 14.2 光源位置与衰减 14.3 聚光和多光源 14.4 光源位置与方向的控制 14.5 辐射光 本章内容是基础篇第七章的补充和提高。这一章主要讲述一些特殊光效果处理,如全局环境光、双面光照、光的衰减、聚光、多光源、光源位置的改变等等。读者若有兴趣,可以按照本章例程的方法作出许多变换,则会出现意想不到的效果,充分发挥你的艺术才能。 14.1、光照模型 OpenGL光照模型的概念由一下三部分组成:1)全局泛光强度、2)视点位置在景物附近还是在无穷远处、3)物体的正面和背面是否分别进行光照计算。 14.1.1 全局环境光 正如前面基础篇中所提到的一样,每个光源都能对一个场景提供环境光。此外,还有一个环境光,它不来自任何特定的光源,即称为全局环境光。下面用参数GL_LIGHT_MODEL_AMBIENT来说明全局环境光的RGBA强度: GLfloat lmodel_ambient[]={0.2,0.2,0.2,1.0}; glLightModelfv(GLLIGHT_MODEL_AMBIENT,lmodel_ambient); 在这个例子中,lmodel_ambient所用的值为GL_LIGHT_MODEL_AMBIENT的缺省值。这些数值产生小量的白色环境光。 14.1.2 近视点与无穷远视点 视点位置能影响镜面高光的计算,也就是说,顶点的高光强度依赖于顶点法向量,从顶点到光源的方向和从顶点到视点的方向。实际上,调用光照函数并不能移动视点。但是可以对光照计算作出不同的假定,这样视点似乎移动了。对于一个无穷远视点,视点到任何顶点的方向保持固定,缺省时为无穷远视点。对于一个近视点,物体每个顶点到视点的方向是不同的,需要逐个计算,从而整体性能降低,但效果更真实。下面一句函数代码是假定为近视点: glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE); 这个调用把视点放在视点坐标系的原点处。若要切换到无穷远视点,只需将

相关主题
文本预览
相关文档 最新文档