按下b,然后同时按下down和right方向键
#include "stdafx.h"
#include <iostream>
#define GLUT_DISABLE_ATEXIT_HACK
#include "glut.h"
#include "glaux.h"
using namespace std;
bool g_bBlend;// 是否混合?
bool g_bKeyB = false;// B 键按下了么?
bool g_bLight =false;// 光源的开/ 关
bool g_bKeyL =false;// L键按下了么?
bool g_bKeyF =false;// F键按下了么?
GLfloat g_fXrot =5; // X 旋转
GLfloat g_fYrot =5;// Y 旋转
GLfloat g_fXSpeed =0;// X 旋转速度
GLfloat g_fYSpeed =0;// Y 旋转速度
GLfloat g_fZ =-5.0f;// 深入屏幕的距
// 接着设置用来创建光源的数组。我们将使用两种不同的光。第一种称为环境光。环境光来自于四面
// 八方。所有场景中的对象都处于环境光的照射中。第二种类型的光源叫做漫射光。漫射光由特定的
// 光源产生,并在您的场景中的对象表面上产生反射。处于漫射光直接照射下的任何对象表面都变得
// 很亮,而几乎未被照射到的区域就显得要暗一些。这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。
// 创建光源的过程和颜色的创建完全一致。前三个参数分别是RGB三色分量,最后一个是alpha通道参数。
// 因此,下面的代码我们得到的是半亮(0.5f)的白色环境光。如果没有环境光,未被漫射光照到的地方会变得十分黑暗。
GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };// 环境光参数
//下一行代码我们生成最亮的漫射光。所有的参数值都取成最大值1.0f 。它将照在我们木板箱的前面,看起来挺好。
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };// 漫射光参数
// 最后我们保存光源的位置。前三个参数和glTranslate中的一样。依次分别是XYZ轴上的位移。由于
// 我们想要光线直接照射在木箱的正面,所以XY轴上的位移都是0.0f 。第三个值是Z 轴上的位移。为
// 了保证光线总在木箱的前面,所以我们将光源的位置朝着观察者( 就是您哪。) 挪出屏幕。我们通常
// 将屏幕也就是显示器的屏幕玻璃所处的位置称作Z 轴的0.0f 点。所以Z 轴上的位移最后定为2.0f 。假
// 如您能够看见光源的话,它就浮在您显示器的前方。当然,如果木箱不在显示器的屏幕玻璃后面的
// 话,您也无法看见箱子。
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };// 光源位置
// filter 变量跟踪显示时所采用的纹理类型。
//第一种纹理(texture[0])使用gl_nearest(不光滑) 滤波方式构建。
//第二种纹理 (texture[1])使用gl_linear(线性滤波)方式,离屏幕越近的图像看起来就越光滑。
//第三种纹理 (texture[2])使用mipmapped滤波方式,这将创建一个外观十分优秀的纹理。
//根据我们的使用类型,filter 变量的值分别等于0,1或2。下面我们从第一种纹理开始。
//GLuint texture[3] 为三种不同纹理分配储存空间。它们分别位于在 texture[0], texture[1]和texture[2] 中。
GLuint filter; // 滤波类型
GLuint texture[3]; // 3种纹理的储存空间
//现在载入一个位图,并用它创建三种不同的纹理。这一课使用glaux辅助库来载入位图,因此在编译
//时您应该确认是否包含了glaux库。我知道Delphi 和VC++都包含了glaux库,但别的语言不能保证都
//有。『译者注:glaux是OpenGL辅助库,根据OpenGL的跨平台特性,所有平台上的代码都应通用。
//但辅助库不是正式的OpenGL标准库,没有出现在所有的平台上。但正好在Win32平台上可用。
AUX_RGBImageRec *TextureImage=new AUX_RGBImageRec;
//辅助函数
AUX_RGBImageRec *LoadBMP(char* FileName)
{
FILE *file = 0;
if(!FileName)
return 0;
file = fopen(FileName,"r");
if(file)
{
fclose(file);
cout<<"start open!";
return auxDIBImageLoad(FileName);
//如果此处出现Fail to open DIB是字符串的问题
//修改项目配置,字符集中将Unicode改成多级字符即可
}
return 0;
}
void LoadTexture()
{
//图像的宽和高必须是2的n次方
memset(TextureImage,0,sizeof(void *)*1);
//现在载入位图,并将其转换为纹理。
TextureImage = LoadBMP("E:\\pic\\box200.bmp");
if(0 == TextureImage)
{
cout<<"error bmp"<<endl;
return;
}
//告诉OpenGL我们要创建三个纹理,它们将存放在texture[0],texture[1]和texture[2]中
glGenTextures(3,&texture[0]);
//第六课中我们使用了线性滤波的纹理贴图。这需要机器有相当高的处理能力,但它们看起来很不
//错。这一课中,我们接着要创建的第一种纹理使用 GL_NEAREST 方式。从原理上讲,这种方式没
//有真正进行滤波。它只占用很小的处理能力,看起来也很差。唯一的好处是这样我们的工程在很快
//和很慢的机器上都可以正常运行。
//您会注意到我们在 MIN 和 MAG 时都采用了GL_NEAREST,你可以混合使用 GL_NEAREST和
//GL_LINEAR。纹理看起来效果会好些,但我们更关心速度,所以全采用低质量贴
//图。MIN_FILTER在图像绘制时小于贴图的原始尺寸时采用。MAG_FILTER在图像绘制时大于贴图
//的原始尺寸时采用。
//###创建 Nearest 滤波贴图###
glBindTexture(GL_TEXTURE_2D, texture[0]); // 告诉OpenGL将纹理名字texture绑定到纹理目标上。
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
//glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
//###创建线性滤波纹理###
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
//glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
//下面是创建纹理的新方法。 Mipmapping!
//您可能会注意到当图像在屏幕上变得很小的时候,很多细节将会
//丢失。刚才还很不错的图案变得很难看。当您告诉OpenGL创建一个 mipmapped 的纹理
//后,OpenGL将尝试创建不同尺寸的高质量纹理。当您向屏幕绘制一个 mipmapped 纹理的时
//候,OpenGL将选择它已经创建的外观最佳的纹理( 带有更多细节) 来绘制,而不仅仅是缩放原先的图
//像( 这将导致细节丢失) 。
//我曾经说过有办法可以绕过OpenGL对纹理宽度和高度所加的限制——64、128、256,等等。
//办法就是 gluBuild2DMipmaps 。据我的发现,您可以使用任意的位图来创建纹理。OpenGL将自动将它缩放到正常的大小。
//因为是第三个纹理,我们将它存到texture[2] 。这样本课中的三个纹理全都创建好了。
glBindTexture(GL_TEXTURE_2D,texture[2]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
//下面一行生成 mipmapped 纹理。
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
//释放前面用来存放位图数据的内存
if(TextureImage)
{
if(TextureImage->data)
{
free(TextureImage->data);
}
free(TextureImage);
}
}
void DrawScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除屏幕及其缓存
glLoadIdentity();//重置当前模型观察矩阵
glTranslatef(0.0f,0.0f,g_fZ); // 移入/ 移出屏幕
glRotatef(g_fXrot,1.0f,0.0f,0.0f);// 绕X轴旋转
glRotatef(g_fYrot,0.0f,1.0f,0.0f);// 绕Y轴旋转
g_fXrot += g_fXSpeed;
g_fYrot += g_fYSpeed;
// 下一行代码选择我们使用的纹理。如果您在您的场景中使用多个纹理,您应该使用来
// glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 选择要绑定的纹理。当您想改变
// 纹理时,应该绑定新的纹理。有一点值得指出的是,您不能在 glBegin() 和 glEnd() 之间绑定纹理,
// 必须在 glBegin() 之前或 glEnd() 之后绑定。注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。
glBindTexture(GL_TEXTURE_2D, texture[filter]);// 选择纹理
// 为了将纹理正确的映射到四边形上,您必须将纹理的右上角映射到四边形的右上角,纹理的左上角
// 映射到四边形的左上角,纹理的右下角映射到四边形的右下角,纹理的左下角映射到四边形的左下
// 角。如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。
glBegin(GL_QUADS);
//glNormal3f 是这一课的新东西。Normal就是法线的意思,所谓法线是指经过面( 多边形)上的一点且
//垂直于这个面多边形的直线。使用光源的时候必须指定一条法线。法线告诉 这个多边形的
//朝向,并指明多边形的正面和背面。如果没有指定法线,什么怪事情都可能发生:不该照亮的面被
//照亮了,多边形的背面也被照亮....。对了,法线应该指向多边形的外侧。
//
//看着木箱的前面您会注意到法线与Z 轴正向同向。这意味着法线正指向观察者-您自己。这正是我
//们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观察者。如果立方体沿着X 或Y 轴
//转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不
//管是哪个面,只要它朝着观察者这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线
//对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到
//立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当
//然是一片漆黑。
//前侧面
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();///
glFlush();
}
void ReSizeFunc(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,width/height,0.1,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void KeyBoardFunc(unsigned char key, int x, int y)
{
cout<<"curren key"<<(int)key<<" what:"<<key<<endl;
if(VK_ESCAPE == key)
{
exit(0);
}
if((key == 'l') && !g_bKeyL)
{
g_bKeyL = true;
g_bLight = !g_bLight;
if(!g_bLight)
{
glDisable(GL_LIGHTING);// 禁用光源
cout<<"禁用光源"<<endl;
}
else
{
glEnable(GL_LIGHTING);// 启用光源
cout<<"启用光源"<<endl;
}
}
//下面的代码查看是否松开了"L" 键。如果松开,变量lp 将设为false 。这意味着"L" 键没有按下。如果
//不作此检查,光源第一次打开之后,就无法再关掉了。计算机会以为"L" 键一直按着呢。
if(key != 'l')
{
g_bKeyL = false;
}
if((key == 'f') && !g_bKeyF)
{
g_bKeyF = true;
filter += 1;
if(filter>2)
{
filter = 0;
}
cout<<"filter="<<filter<<endl;
}
if(key != 'f')
{
g_bKeyF = false;
}
if(('b' == key)&&!g_bKeyB)// B 健按下且bp为 FALSE 么?
{
g_bKeyB = true;// 若是, bp 设为 TRUE
g_bBlend = !g_bBlend;// 切换混合选项的 TRUE / FALSE
if(g_bBlend)// 混合打开了么?
{
glEnable(GL_BLEND);// 打开混合
glDisable(GL_DEPTH_TEST);// 关闭深度测试
}
else
{
glDisable(GL_BLEND);// 关闭混合
glEnable(GL_DEPTH_TEST);// 关闭混合
}
}
if('b'!=key)// B 键松开了么?
{
g_bKeyB = false;// 若是, bp 设为 FALSE
}
DrawScene();
}
void SpecialKeys(int key, int x, int y)
{
cout<<"curren special key"<<(int)key<<" what:"<<key<<endl;
//现在检查方向键。按下左右方向键xspeed 相应减少或增加。按下上下方向键yspeed 相应减少或增
//加。记住在以后的教程中如果xspeed 、yspeed 的值增加的话,立方体就转的更快。如果一直按着某
//个方向键,立方体会在那个方向上转的越快。
if(GLUT_KEY_UP == key)
{
g_fXSpeed -= 0.01;
}
if(GLUT_KEY_DOWN == key)
{
g_fXSpeed += 0.01;
}
if(GLUT_KEY_LEFT == key)
{
g_fYSpeed -= 0.01;
}
if(GLUT_KEY_RIGHT == key)
{
g_fYSpeed += 0.01;
}
//接着四行检查PageDown键是否按下,若是的话,增加z 变量的值。这样DrawGLScene 函数中包含
//的glTranslatef(0.0f,0.0f,z) 调用将使木箱向着观察者移近一点。
if(GLUT_KEY_PAGE_DOWN == key)
{
g_fZ+=0.02;
}
DrawScene();
}
int Init()
{
LoadTexture();
glEnable(GL_TEXTURE_2D);// 启用纹理映射
glShadeModel(GL_SMOOTH);// 启用阴影平滑
glClearColor(0,0,0,0); // 黑色背景
glClearDepth(1); // 设置深度缓存
glEnable(GL_DEPTH_TEST);// 启用深度测试
glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);// 真正精细的透视修正
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫射光
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 设置光源位置
//我们启用一号光源。我们还没有启用GL_LIGHTING,所以您看不见任何光线。记住:只对
//光源进行设置、定位、甚至启用,光源都不会工作。除非我们启用GL_LIGHTING。
glEnable(GL_LIGHT1);
//第一行以全亮度绘制此物体,并对其进行50% 的alpha混合( 半透
// 明) 。当混合选项打开时,此物体将会产生50% 的透明效果。第二行设置所采用的混合类型。
// Rui Martins 的补充: alpha 通道的值为 0.0 意味着物体材质是完全透明的。1.0 则意味着完全不透明。
glColor4f(1,1,1,0.5);// 全亮度, 50% Alpha 混合
glBlendFunc(GL_SRC_ALPHA,GL_ONE);// 基于源象素alpha通道值的半透明混合函数
return 0;
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("第八个OpenGL程序");
glutReshapeFunc(ReSizeFunc);
glutDisplayFunc(DrawScene);
glutKeyboardFunc(KeyBoardFunc);
glutSpecialFunc(SpecialKeys);
Init();
glutMainLoop();
return 0;
}
- 该日志由 guoming0000 于7月前发表在OpenGL分类下,最后更新于 2013年07月02日.
- 转载请注明: NeHe_OpenGL_混合 | 52 Coding +复制链接
- 关键字: OpenGL