在这一课当中,我将会学到如何使用光照,如何使用键盘控制,其次还增加两种纹理映射的滤波方式.而主要内容将会放在光照上.
为了在场景中增加光照,需要执行下面的这些步骤:
1. 定义每个物体的每个顶点的法线向量.这些法线决定了物体相对于光源的方向
glNormal3f() //这是这节课当中必须用得到的 指定方向方向
2. 创建或选择一个或多个光源,并设置他们的位置
glLightfv() //这个函数将会创建某号光源,并设置它的一些属性,如环境光强度,漫反射光强度,及位置等.
光强度其实也是类似颜色值的四个分量组成的...R G B A
3. 创建或选择一种光照模型,它定义了全局环境光的层次以及观察点的有效位置(便于进行光照计算).
而该Lesson当初我们并为用到这个函数 glLightModelfv() .因为在opengl当中其实许多值都是具有默认值的.
4. 定义场景中的物体的材料属性
glMaterialfv() //这课当中我们也没有用到.
5. 启用创建的光源,启用光照..
glEnable(光源号)
glEnable(GL_LIGHTING) //这个则是关键.只有启用它才能达到启用光照的效果.
glut 当中负责处理键盘事件注册的有两个函数glutSpecialFunc() 负责处理特殊按键,glKeyboardFunc() 负责处理普通按键.故而在键盘处理事件当中我们只需在这些事情函数中写入相关代码就行.
而其他的内容我只是全部在将在代码注释当中给出
Code
#include "openglglut.h"
/**//**
** NEHE lesson_7
** 1.纹理映射的学习(三种滤波方式)
** 2.键盘控制的学习
** 3.光照配置的学习(环境光 点光源)
*/
GLfloat xRot=0; /**//** 正方体绕x轴旋转角度*/
GLfloat yRot=0; /**//** 正方体绕y轴旋转角度*/
GLfloat z=-6.0;
static GLuint texnum[3]; /**//** 定义存储纹理*/
bool light=false;
int filter=0; /**//** 定义选择的滤波方式*/
GLfloat light_ambient[]={0.5,0.5,0.5,1.0}; /**//** 定义环境光强度*/
GLfloat light_diffuse[]={1.0,1.0,1.0,1.0}; /**//** 定义漫反射光强度*/
GLfloat light_position[]={0.0,0.0,5.0,1.0}; /**//** 定义光源的位置*/
/**//** 这是一个通过WIN API 载入一张bmp格式图片的方法*/
bool LoadBmpTexture(LPTSTR filename)
{
HBITMAP bBmp; /**//** 位图文件的句柄*/
BITMAP bmp; /**//** 位图的结构*/
/**//** 通过API LoadImage 读入bmp文件,获得句柄*/
bBmp=(HBITMAP)LoadImage(GetModuleHandle(NULL),filename,IMAGE_BITMAP,0,0,
LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if(!bBmp)
return false;
/**//** 获得图像数据对象*/
GetObject(bBmp,sizeof(bmp),&bmp);
glPixelStorei(GL_UNPACK_ALIGNMENT,4); /**//** ? */
glGenTextures(3,&texnum[0]); /**//** 创建三个纹理 分别存储于texnum[0],texnum[1],texnum[2]*/
/**//** Nearest滤波*/
glBindTexture(GL_TEXTURE_2D,texnum[0]); /**//** 为它指定第一个纹理 设置纹理滤波方式*/
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); /**//** 线性滤波 */
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); /**//** 线性滤波 */
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);
/**//** 线性滤波*/
glBindTexture(GL_TEXTURE_2D,texnum[1]); /**//** 为它指定第一个纹理 设置纹理滤波方式*/
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);
/**//** MipMapped 滤波*/
glBindTexture(GL_TEXTURE_2D,texnum[2]); /**//** 为它指定第一个纹理 设置纹理滤波方式*/
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,bmp.bmWidth,bmp.bmHeight
,GL_BGR_EXT,GL_UNSIGNED_BYTE,bmp.bmBits);
DeleteObject(bBmp); /**//** 删除对象,释放内存*/
return true;
}
int main(int argc,char** argv)
{
createWindow("opengl lesson_7",&argc,argv); /**//** 初始化并创建窗口*/
glutDisplayFunc(glutDisplay); /**//** 注册重绘函数*/
glutIdleFunc(glutIdle); /**//** 注册空闲回调函数*/
glutReshapeFunc(glutResize); /**//** 注册窗口调整函数*/
glutSpecialFunc(glutSpecial); /**//** 注册特殊按键窗口*/
glutKeyboardFunc(glutKeyboard); /**//** 注册键盘处理函数*/
InitOpenGL(); /**//** 初始化opengl*/
InitTexture(); /**//** 初始化启用纹理映射并加载纹理*/
InitLight(); /**//** 初始化光照*/
glutMainLoop(); /**//** 仿真循环*/
}
void InitTexture(void)
{
/**//** 读入工程目录下data文件中的bmp文件*/
if(!LoadBmpTexture(L"..\\Data\\image.bmp"))
{
printf("load texture error!\n");
exit(0);
}
/**//** 若载入纹理成功 则启用纹理映射*/
glEnable(GL_TEXTURE_2D);
}
void InitLight(void)
{
/**//** 创建并启用1号光源*/
glLightfv(GL_LIGHT1,GL_AMBIENT,light_ambient); /** 初始化光源1环境光*/
glLightfv(GL_LIGHT1,GL_DIFFUSE,light_diffuse); /**//** 初始化光源1散射光*/
glLightfv(GL_LIGHT1,GL_POSITION,light_position); /**//** 初始化光源1位置*/
/**//** liggt_position 包含(x,y,z,w) w为0 表示方向性光源,w非0表示位置性光源*/
glEnable(GL_LIGHT1);
}
void glutIdle(void)
{
glutPostRedisplay();
}
void glutDisplay(void) /**//** 重绘函数*/
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);/**//** 清除颜色缓存和深度缓存*/
glLoadIdentity(); /**//** 初始化当前矩阵为单位矩阵*/
glPushMatrix(); /**//** 保存当前矩阵*/
glTranslatef(0.0,0.0,z); /**//** 往左移动和往屏幕内部移动,绘制正方体*/
glRotatef(xRot,1.0,0.0,0.0); /**//** 正方体绕x轴旋转xRot角度*/
glRotatef(yRot,0.0,1.0,0.0); /**//** 正方体绕y轴旋转yRot角度*/
glBindTexture(GL_TEXTURE_2D,texnum[filter]); /**//** 选择一个纹理*/
glBegin(GL_QUADS); /**//** 通过绘制六个正方形组成正方体,并为每一面都贴上纹理*/
// 前侧面
glNormal3f( 0.0f, 0.0f, 1.0f); // 法线指向观察者
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 后侧面
glNormal3f( 0.0f, 0.0f,-1.0f); // 法线背向观察者
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 顶面
glNormal3f( 0.0f, 1.0f, 0.0f); // 法线向上
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 底面
glNormal3f( 0.0f,-1.0f, 0.0f); // 法线朝下
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右侧面
glNormal3f( 1.0f, 0.0f, 0.0f); // 法线朝右
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左侧面
glNormal3f(-1.0f, 0.0f, 0.0f); // 法线朝左
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd(); // 四边形绘制结束
glutSwapBuffers();
}
void glutKeyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 27: /**//** Esc按键按下后退出程序 */
exit(0);
break;
case 'l': /**//** 按键L 光源开关*/
light=!light;
light?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING);
break;
case 'f': /**//** 选择滤波方式*/
filter+=1;
filter%=2;
break;
case 'a':
yRot-=1.0; /**//** 绕y旋转角度递减*/
break;
case 'd':
yRot+=1.0; /**//** 绕y旋转角度递增*/
break;
case 's':
xRot+=1.0; /**//** 绕x旋转角度递增*/
break;
case 'w':
xRot-=1.0; /**//** 绕y旋转角度递增*/
case 'z':
z-=0.02; /**//** z轴移动位置递减,即向屏幕外移动*/
break;
case 'x': /**//** z轴移动位置递增,即向屏幕内移动*/
z+=0.02;
break;
default:
break;
}
}
最后实现的效果图如下所示:
末尾总结:
熟悉了光照的配置,以及键盘函数处理的一些功能.其次我在读取纹理过程当中发现了以个bug..使用win API 并不能读取 8-bit的bmp格式图像..所以相对于读取文件其实也应当是个麻烦的事情..
posted on 2009-07-26 14:21
米游 阅读(465)
评论(0) 编辑 收藏 引用 所属分类:
OpenGL/OSG