OpenGL_8 光照和键盘

开始前需要定义全局变量,其中与光照相关的全局变量为

GLfloat LightAmbient[] = { 0.5f,0.5f,0.5f,1.0f };//环境光参数
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };// 漫射光参数
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f };// 光源位置

与纹理映射滤波有关的全局变量为

GLuint filter;         // 滤波类型
GLuint texture[3];        // 3种纹理的储存空间

接下来在LoadGLTextures()函数中载入位图并生成纹理

注意点:OpenGL载入的位图一般要求宽度和高度大小为2的整数次方,如64,128,256等,但是在图像缩小到很小时,将创建一个mipmapping纹理,这时需要用一种绕过大小限制的绑定方法:gluBlind2DMipmaps();同样要注意及时释放内存。

int LoadGLTextures()//载入位图并转换成纹理
{
	int Status = FALSE;
	AUX_RGBImageRec* TextureImage[1];//创建纹理的存储空间
	memset(TextureImage, 0, sizeof(void*) * 1);//将指针设为NULL
	if (TextureImage[0] = LoadBMP("texture.bmp"))//成功载入位图
	{
		Status = TRUE;
		glGenTextures(3, &texture[0]);//创建3个纹理

		// 创建 Nearest 滤波贴图
		glBindTexture(GL_TEXTURE_2D, texture[0]);
		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[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->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);
		glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
		// 创建 MipMapped 纹理
		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);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

	}
	if (TextureImage[0])//纹理还存在
	{
		if (TextureImage[0]->data)//纹理图形还存在
		{
			free(TextureImage[0]->data);
		}
		free(TextureImage[0]);
	}
	return Status;
}

同时,在OpenGL初始化函数中要设置光源,这里定义了光源GL_LIGHT1的环境光、漫反射光,光源位置,并启用光源

int InitGL(GLvoid)
{
	if (!LoadGLTextures())//布恩那个调用纹理载入
	{
		return FALSE;
	}
	glEnable(GL_TEXTURE_2D);//启用纹理映射
	glShadeModel(GL_SMOOTH);	//设置深度缓存
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);	//启用深度测试
	glDepthFunc(GL_LEQUAL);		//所作深度测试的类型
	glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);//设置环境光
	glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);//设置漫反射
	glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);//设置光源位置
	glEnable(GL_LIGHT1);//启用一号光源
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//反锯齿
	return TRUE;
}
在DrawGLScene()函数中,使用光源时需要使用glNormal3f()指定法线,法线需要指向立方体外侧,而不能指向内部

int DrawGLScene(GLvoid)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 清除屏幕和深度缓存
	glLoadIdentity();       // 重置当前的模型观察矩阵
	glTranslatef(0.0f, 0.0f, z);      // 移入/移出屏幕 z 个单位
	glRotatef(xrot, 1.0f, 0.0f, 0.0f);      // 绕X轴旋转
	glRotatef(yrot, 0.0f, 1.0f, 0.0f);      // 绕Y轴旋转
	glBindTexture(GL_TEXTURE_2D, texture[filter]);    // 选择由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();        // 四边形绘制结束

	xrot += xspeed;        // xrot 增加 xspeed 单位
	yrot += yspeed;        // yrot 增加 yspeed 单位
	return TRUE;

}

在WinMain()函数中定义按键的作用

在NEHE教程中,按键逻辑感觉不符合主流,下面的代码稍加了改动,PageUp定义为立方体移向观察者,PageDown定义为远离观察者,Up定义为yspeed+,Down定义为yspeed-,Left定义为xspeed-,Right定义为xspeed+.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG msg;
	BOOL done = FALSE;
	if (MessageBox(NULL, L"你想在全屏模式下运行吗", L"设置全屏模式", MB_YESNO | MB_ICONQUESTION) == IDNO)
	{
		fullscreen = FALSE;
	}
	if (!CreateGLWindow(L"OpenGL程序框架", 640, 480, 16, fullscreen))
	{
		return 0;
	}
	while (!done)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//有消息在等待吗
		{
			if (msg.message == WM_QUIT)
			{
				done = TRUE;
			}
			else
			{
				TranslateMessage(&msg);//翻译消息
				DispatchMessage(&msg);//发送消息
			}
		}
		else
		{
			if (active)
			{
				if (keys[VK_ESCAPE])//ESC按下
				{
					done = TRUE;
				}
				else
				{
					DrawGLScene();
					SwapBuffers(hDC);
				}
				if (keys['L'] && !lp)//L键按下并且未松开
				{
					lp = TRUE;
					light = !light;
					if (!light)//如果没有光源
					{
						glDisable(GL_LIGHTING);//禁用光源
					}
					else
					{
						glEnable(GL_LIGHTING);//启用光源
					}
				}
				if (!keys['L'])//L键松开了
				{
					lp = FALSE;
				}
				if (keys['F'] && !fp)//F键按下并且未松开
				{
					fp = TURE;
					filter += 1;
					if (filter > 2)
					{
						filter = 0;
					}
				}
				if (!keys['F'])
				{
					fp = FALSE;
				}
				if (keys[VK_PRIOR])//PageDown按下了
				{
					z -= 0.02f;//若按下,木箱远离观察者
				}
				if (keys[VK_UP])//PageUp按下
				{
					z += 0.02f;//若按下,木箱靠近观察者
				}
				if (keys[VK_UP])//Up方向键按下
				{
					yspeed += 0.01f;
				}
				if (keys[VK_DOWN])//Down方向键按下
				{
					yspeed -= 0.01f;
				}
				if (keys[VK_RIGHT])//Right方向键按下
				{
					xspeed += 0.01f;
				}
				if (keys[VK_LEFT])//Left方向键按下
				{
					xspeed -= 0.01f;
				}
				if (keys[VK_F1])//F1按下
				{
					keys[VK_F1] = FALSE;
					KillGLWindow();
					fullscreen = !fullscreen;
					if (!CreateGLWindow(L"OpenGL程序框架", 640, 480, 16, fullscreen))//重建OpenGL窗口
					{
						return 0;
					}
				}
			}
		}
	}

	KillGLWindow();
	return(msg.wParam);
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值