• 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;
    }

    作者:


  • 相关阅读:
    控制流测试与条件测试
    12306的“短信公众号”到底是个啥?
    ISTQB名词辨析
    ISTQB TA
    启动Chrome时自动开启开发者模式
    LoadRunner Community Edition 12.60 无法获取Community License
    用言的活用声调变化规则
    ISTQB TTA大纲中提到的参考书目
    Java调用方法参数究竟是传值还是传址?
    Java中的Lambda表达式简介及应用
  • 原文地址:https://www.cnblogs.com/xieyuan/p/3787305.html
Copyright © 2020-2023  润新知