OpenGL_混合

按下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;
}

作者:


原文地址:https://www.cnblogs.com/xieyuan/p/3787305.html