现在的位置: 首页 > 综合 > 正文

ArchieOpenGL第十课:3D世界漫游

2013年09月01日 ⁄ 综合 ⁄ 共 5140字 ⁄ 字号 评论关闭

参考:nehe中文第十课

在第九课基础上继续

------------------------------------------------

数据结构
当您想要使用一系列的数字来完美的表达3D环境时,随着环境复杂度的上升,这个工作的难度也会随之上升。出于这个原因,我们必须将数据归类,使其具有更多的可操作性风格。在程序清单头部出现了sector(区段)的定义。每个3D世界基本上可以看作是sector(区段)的集合。一个sector(区段)可以是一个房间、一个立方体、或者任意一个闭合的区间。

Nehe教程定义了区段,这里我们先省略这一步,数据结构比基本的漫游更复杂,我觉得放在后面更加合适。我们已经有了带纹理的立方体,首先让我们来做漫游吧,这应该很cool。

-----------------------------------------------------------------

本课源代码

显示世界
现在几何模型已经载入内存,我们下一步要在屏幕上显示它。到目前为止,我们所作过的都是些简单的旋转和平移。但我们的镜头始终位于原点(0,0,0)处。任何一个不错的3D引擎都会允许用户在这个世界中游走和遍历,我们的这个也一样。实现这个功能的一种途径是直接移动镜头(gluLookAt)并绘制以镜头为中心的3D环境。这样做会很慢并且不易用代码实现。我们的解决方法如下:

  • 根据用户的指令旋转并变换镜头位置。
  • 围绕原点(镜头在原点),以与镜头相反的旋转方向来旋转世界。(让人产生镜头旋转的错觉)
  • 以与镜头平移方式相反的方式来平移世界(让人产生镜头移动的错觉)。

这样实现起来就很简单.
下面从第一步开始吧(平移并旋转镜头)。

因为用到数学函数,添加

在view.cpp中添加

#include <math.h>
#ifndef PIOVER180
#define PIOVER180 0.0174532925f
#else
#endif
//////////////////////////////////////////////////////////////////////////
	//第十课3D漫游
 
	float m_fHeading;
	float m_xPos;
	float m_zPos;
	

	GLfloat walkbias ;
	GLfloat walkbiasangle ;
	GLfloat lookupdown f;
//////////////////////////////////////////////////////////////////////////

初始化

	m_fHeading=0;
	m_xPos=0;
	m_zPos=0;
	
	walkbias = 0;
	walkbiasangle = 0;
	lookupdown = 0.0f;

void COpenglbaseView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{

	switch(nChar)
	{
	case VK_ESCAPE:
		{
			
			//获取主框架窗口指针(app文件openbase.cpp包含了mainfrm.h)
			CMainFrame * pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;
			//调用主窗口类的自定义函数EndFullScreen,退出全屏显示状态
			pFrame->EndFullScreen();
			Invalidate(FALSE);
			break;
		}
		//灯光控制
	case 'L':
		{
			m_bLight=!m_bLight;
			Invalidate(FALSE);
			break;
		}
		//滤波方式
	case 'F':
		{
			m_nFilter++;
			if (m_nFilter>2)
			{
				m_nFilter=0;
			}
			Invalidate(FALSE);
			break;
		}
	case VK_PRIOR:			// PageUp按下了?
		{
			m_fZ-=0.02f;				// 若按下,将木箱移向屏幕内部
		}
		Invalidate(FALSE);
		break;
		
		//接着四行检查PageDown键是否按下,若是的话,增加z变量的值。
		
	case VK_NEXT:				// PageDown按下了么
		{
			m_fZ+=0.02f;				// 若按下的话,将木箱移向观察者
		}
		Invalidate(FALSE);
		break;
		
		
	//现在检查方向键。
		
	case 		VK_UP:		// Up方向键按下了么?
		m_xPos -= (float)sin(m_fHeading*PIOVER180) * 0.05f;			// 沿游戏者所在的X平面移动 世界向相反移动
		m_zPos -= (float)cos(m_fHeading*PIOVER180) * 0.05f;			// 沿游戏者所在的Z平面移动
		if (walkbiasangle >= 359.0f)					// 如果walkbiasangle大于359度
		{
			walkbiasangle = 0.0f;					// 将 walkbiasangle 设为0
		}
		else								// 否则
		{
			walkbiasangle+= 10;					// 如果 walkbiasangle < 359 ,则增加 10
		}
		walkbias = (float)sin(walkbiasangle * PIOVER180)/20.0f;		// 使游戏者产生跳跃感
		Invalidate(FALSE);
		break;
	case VK_DOWN:				// Down方向键按下了么?
		m_xPos += (float)sin(m_fHeading*PIOVER180) * 0.05f;			// 沿游戏者所在的X平面移动
		m_zPos += (float)cos(m_fHeading*PIOVER180) * 0.05f;			// 沿游戏者所在的Z平面移动
		if (walkbiasangle <= 1.0f)					// 如果walkbiasangle小于1度
		{
			walkbiasangle = 359.0f;					// 使 walkbiasangle 等于 359
		}
		else								// 否则
		{
			walkbiasangle-= 10;					// 如果 walkbiasangle > 1 减去 10
		}
		walkbias = (float)sin(walkbiasangle * PIOVER180)/20.0f;		// 使游戏者产生跳跃感

		Invalidate(FALSE);
		break;
	case VK_RIGHT:			// Right方向键按下了么?
		m_fYRot -= 1.5f;							// 镜头向右旋转则可以看做向左旋转场景
		Invalidate(FALSE);
		break;
	case VK_LEFT:			// Left方向键按下了么?
		m_fYRot += 1.5f;							// 眼睛(镜头)向左旋转则可以看做向右旋转场景
		Invalidate(FALSE);
		break;
	}
	
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

渲染部分

BOOL COpenglbaseView::RenderScene()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);			// 清除屏幕及深度缓存
	glLoadIdentity();
//////////////////////////////////////////////////////////////////////////
	//第10课3D漫游
	GLfloat xtrans = -m_xPos;						// 用于游戏者沿X轴平移时的大小
	GLfloat ztrans = -m_zPos;						// 用于游戏者沿Z轴平移时的大小
	GLfloat ytrans = -walkbias-0.25f;				// 用于头部的上下摆动
	GLfloat sceneroty = 360.0f - m_fYRot;				// 位于游戏者方向的360度角
	

	glRotatef(lookupdown,1.0f,0,0);					// 上下旋转
	glRotatef(sceneroty,0,1.0f,0);					// 根据游戏者正面所对方向所作的旋转
	glTranslatef(xtrans, ytrans, ztrans);				// 以游戏者为中心的平移场景
//////////////////////////////////////////////////////////////////////////

	glBindTexture(GL_TEXTURE_2D, texture[m_nFilter]);				// 选择纹理
	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();


	return TRUE;						// 继续运行

}

抱歉!评论已关闭.