首页 > 编程语言 >OpenGL实现3D游戏编程【连载2】——了解并创建3D空间模型

OpenGL实现3D游戏编程【连载2】——了解并创建3D空间模型

时间:2024-08-05 14:52:29浏览次数:15  
标签:连载 OpenGL 0.0 函数 坐标轴 GLdouble GL 我们 3D

1、本节实现的内容

上一节我们创建一个简单的窗口,本节我们需要了解一下细节内容,同时为了方便观看,我们需要显示一个世界坐标轴,建立一个直观的三维空间。
在这里插入图片描述

2、我们的眼睛设定(gluPerspective函数)

上一节课,我们创建了一个简单的opengl窗口,并显示了一个简单的3d模型正方体,这节我们就要开始了解更多的细节内容。嗯,上一节课中,使用了视角的设置函数perspective,第一个参数表示视场角的大小,符合人眼的条件一般设置为40°~70°之间这个函数。在我理解,有点像是你眼睛展开的角度,比如说10度就有点像你能观测的范围只有10度,就像眯着眼睛看世界,那么他看到的物体就范围比较窄,如果你设置的是60度,那么它光视角就会更大一些,看到的范围更多。这一点可以在我们后期,从三维坐标转换到屏幕的二维坐标中体会到,说当前的这个角度是60度,在坐标转换中一个三维坐标点A如果在当前视角的屏幕以外,那么,它A点与当前屏幕正中间点的视线夹角肯定就超过了60度,我们在后期讲解三维坐标转换时会讲到。

void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)

fovy:视角的大小,相当于眼睛张开的角度。当视角为0度时,这就相当于我们的眼睛闭起来了,那就神马也看不到了。所以选择一个合适的视角尤为重要,一般40度至70度最适合,当然具体情况具体分析。

aspect:宽和高的比例,这里我们直接可以取程序窗口的宽度和高度比。

zNear:观察点与近侧裁剪平面的距离,眼睛距离近处的距离,一般选择0.01。

zFar:观察点与远侧裁剪平面的距离,眼睛远处的裁面,一般为1000,超过这个距离将被裁剪看不到。

zNear和zFar说明了对于绘制的图形,它与视线原点的距离0.01到1000之间必须是在两者之间。

在这里插入图片描述

3、我们看向远方的视线(gluLookAt函数)

我们还用到了一个函数gluLookAt,这个函数形象的表述了我们在三维世界里头眼睛所在的位置和朝向的位置,还有一个视角的方向。

void gluLookAt(
    GLdouble eyex,GLdouble eyey,GLdouble eyez,
    GLdouble centerx,GLdouble centery,GLdouble centerz, 
    GLdouble upx,GLdouble upy,GLdouble upz);

前两个非常的好理解,第一个参数就表示的是你眼睛的位置,第二个参数就表示你要看物体的位置坐标,当然,我们第二个参数可以不确定到具体的物体位置坐标,只要你向前看,视线上的任何一点都可以。第三个参数,要是你视线的正上方向量,根据设定角度不同,可以实现侧着头观察世界的效果。

4、通过我们的眼睛和视线探索世界

通过我们前面讲到的我们的眼睛设定(gluPerspective函数)和我们看向远方的视线(gluLookAt函数),我们就可以描述出我们观察时间的方式。还拿上节课的例子,我们通过gluPerspective将眼睛以45度的角度睁开,我的眼睛位于一个(10.0f,10.0f,10.0f)点的位置,视线朝着原点(0.0f,0.0f,0.0f)点的位置望去,这就是我们以下代码大致实现的内容。

			//获取窗口大小
			
			RECT tempClientRect;
			
			GetClientRect(hWnd,&tempClientRect);
			
			//初始化3D视角
			
			glMatrixMode(GL_PROJECTION);
			
			glLoadIdentity();
			
			gluPerspective(45,(float)tempClientRect.right/(float)tempClientRect.bottom,0.01f,1000.0f);
			
			glMatrixMode(GL_MODELVIEW);
			
			glLoadIdentity();
			
			//设置用户眼睛视角,展示壮观的三维世界从这里开始
			
			gluLookAt(10.0f,10.0f,10.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);

说到这里,后期当我们不停地改变眼睛的位置和视线的方向,就产生了视角移动的效果,可以产生人物移动观察世界的效果,类似第一人称射击游戏或RPG游戏人物视角的效果,是不是很有感觉,我们将在后期完善相关代码,随后再详细说。

5、窗口显示比例的锁定

当我们创建了视角以后,我们发现一个问题:当我们鼠标拖动窗口改变大小时,我们刚刚显示的物体竟然变形状了,而且立方体的位置不再显示在窗口的中心。试想以下,我们如果在玩游戏,出现人物如果会随着程序窗口大小的改变而不断地被拉长或压扁,那将是个多么糟糕的事情。因此我们需要另一个函数,来保证所有的物体保持横宽比例。

在这里插入图片描述

OpenGL中的glViewport 函数用于定义视口(Viewport),也就是确定窗口中显示的区域。它的定义如下:

void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);

x:视口的左下角X坐标。

y:视口的左下角Y坐标。

width:视口的宽度。

height:视口的高度。

glViewport函数的作用是将正投影坐标(OpenGL的默认坐标系)映射到屏幕上实际显示的区域。它将正投影坐标系中的点映射到屏幕上指定大小的矩形区域内。这里我们将的glViewport(0,0,tempClientRect.right,tempClientRect.bottom)就时将整个程序窗口平面设定为显示区域,那么配合着gluPerspective中设定的平面横纵比为(float)tempClientRect.right/(float)tempClientRect.bottom,我们就可以保持整个世界的横纵比例保持一致,不至于出现拉长、压扁的情况了。

			//获取窗口大小
			
			RECT tempClientRect;
			
			GetClientRect(hWnd,&tempClientRect);

			//重置视窗设置
			
			glViewport(0,0,tempClientRect.right,tempClientRect.bottom);
			
			glMatrixMode(GL_PROJECTION);
			
			glLoadIdentity();

在使用OpenGL进行绘图时,我们通常需要先通过glViewport来设置视口,将整个窗口或窗口的一部分作为渲染区域。这样,我们可以指定绘制的内容在窗口的哪个位置显示出来。通常情况下,我们将glViewport放置到窗口改变的消息处理函数中即可,但如果后期需要显示多个glViewport视口,就需要改变glViewport的设置位置。

大家还记不记得魔兽争霸3游戏界面里的人物选中头像界面,在二维平面相框中显示出来三维的头像,就可以个用glViewport实现出来,我们将在后面的程序中实现这一个功能,敬请期待。

在这里插入图片描述

6、我们需要一个三维坐标轴

接下来,我们看到的立方体是在一个黑色窗口里面,仿佛悬浮在空中一样,没有参照物,我们要创建一个可以看见的三维坐标轴方便观察。大家需要明确的一点是openGL中世界坐标系(World Coordinates)是右手坐标系,在二维屏幕上,屏幕水平方向是x 轴方向,向右为正,屏幕竖起方向是Y轴方向,向上为正,垂直于屏幕的方向是Z轴方向,从屏幕里往外为正。

在这里插入图片描述

我们首先去生成一个坐标轴,我们需要使用的画线操作。OpenGL的绘图的函数很多,OpenGL的绘图必须在在glBegin()和glEnd()函数之间完成,这里简单介绍基本几何绘图函数。

GL_POINTS:单个顶点集
GL_LINES :多组双顶点线段
GL_POLYGON: 单个简单填充凸多边形
GL_TRAINGLES:多组独立填充三角形
GL_QUADS:多组独立填充四边形
GL_LINE_STRIP: 不闭合折线
GL_LINE_LOOP: 闭合折线
GL_TRAINGLE_STRIP: 线型连续填充三角形串
GL_TRAINGLE_FAN: 扇形连续填充三角形串
GL_QUAD_STRIP: 连续填充四边形串

具体的使用方法上图一目了然。这个图我已经收藏了,用的时候超方便。
在这里插入图片描述
有了这些方法,我们就可以采用其中的GL_LINES (多组双顶点线段)来画我们的三维坐标轴了。这里我们用红色的线表示x轴,绿色的线表示y轴,蓝色线表示z轴。箭头方向的表示对应轴线的正值方向,另外一边就是负值方向。

	//显示坐标轴

			if(true)
			{

				//设置线的宽度

				glLineWidth(3.0f);

				//显示红色的X坐标轴
				
				glColor3f(1.0f,0.0f,0.0f);
				
				glBegin(GL_LINES);
				
				glVertex3f(-10.0f,0.0f,0.0f);
				
				glVertex3f(+10.0f,0.0f,0.0f);
				
				glEnd();
				
				//显示绿色的Y坐标轴
				
				glColor3f(0.0f,1.0f,0.0f);
				
				glBegin(GL_LINES);
				
				glVertex3f(0.0f,-10.0f,0.0f);
				
				glVertex3f(0.0f,+10.0f,0.0f);
				
				glEnd();
				
				//显示蓝色的Z坐标轴

				glColor3f(0.0f,0.0f,1.0f);				
				
				glBegin(GL_LINES);
				
				glVertex3f(0.0f,0.0f,-10.0f);
				
				glVertex3f(0.0f,0.0f,+10.0f);
				
				glEnd();

			}

添加以上代码后,我们就可以看到一个简陋的坐标轴了。

在这里插入图片描述

7、添加坐标轴的方向箭头

我们画出了坐标轴,但是没有方向箭头,总感觉少点什么。我么还是把方向箭头显示出来,这样我们就可以明确的感知到各个方向的正方向和负方向的区别了。

这里我们箭头使用了前面正方体类似的系统函数,系统还提供了类似四面体、正八面体、正十二面体、正二十面体、球体、圆环体、茶壶等多个基础函数,方便用户使用。

		//显示一个椎体
		
		glutSolidCone(0.5,1.0,30,30);

当然,系统提供的这些函数画出的立体图形只有默认的方向,如果用户想调整立体图形的方向和位置,就要用到转换矩阵相关函数。我们这里简单介绍一下:

void glTranslatef(GLfloat x,GLfloat y,GLfloat z);

函数功能:简单的理解,就是物体的位置移动。参数x,y,z分别指定沿x,y,z轴方向的平移分量。其作用就是将你绘点坐标的原点在当前原点的基础上平移一个(x,y,z)向量。

void glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);

函数功能:简单的理解,就物体的旋转。先解释一下旋转方向,做(0,0,0)到(x,y,z)的向量,方向满足右手定则,用右手握住这条向量,大拇指指向向量的正方向,四指环绕的方向就是旋转的方向。以点(0,0,0)到点(x,y,z)为轴,旋转angle角度。

接下来,我们就可以使用glTranslatef和glRotatef函数对圆锥箭头进行位置和角度的调整。在Opengl中存在大量的位置和角度的调整,后期还会详细了解以上操作函数。

				//显示坐标轴箭头
				
				glPushMatrix();
				
				glColor3f(1,0,0);
				
				glTranslatef(10,0,0);
				
				glRotatef(90,0.0f,1.0f,0.0f);
				
				glutSolidCone(0.5,1.0,30,30);
				
				glPopMatrix();

				//显示坐标轴箭头
				
				glPushMatrix();
				
				glColor3f(0,1,0);
				
				glTranslatef(0,10,0);
				
				glRotatef(-90,1.0f,0.0f,0.0f);
				
				glutSolidCone(0.5,1.0,30,30);
				
				glPopMatrix();

				//显示坐标轴箭头
				
				glPushMatrix();
				
				glColor3f(0,0,1);
				
				glTranslatef(0,0,10);
				
				glRotatef(0,1.0f,0.0f,0.0f);
				
				glutSolidCone(0.5,1.0,30,30);
				
				glPopMatrix();

在这里插入图片描述

标签:连载,OpenGL,0.0,函数,坐标轴,GLdouble,GL,我们,3D
From: https://blog.csdn.net/zhooyu/article/details/140863096

相关文章

  • vue实现3d词云组件
    vue实现3d词云组件<!--*@Description:词云组件页面*@Date:2024/3/1023:39--><template><div:style="{display:'flex',justifyContent:'center',border:'1pxsolidred',}"......
  • 【Unity】3D功能开发入门系列(四)
    Unity3D功能开发入门系列(四)一、组件的访问(一)组件的调用(二)组件的参数(三)引用别的组件(四)引用脚本组件(五)消息调用二、物体的访问(一)获取物体(二)父子物体(三)物体的操作(四)练习:俄罗斯方块三、资源的访问(一)资源的使用(二)资源数组(三)练习:三色球四、定时调用(一)定时调用(二)定时与线程(三......
  • webgl 相对 opengl有什么优缺点
    WebGL和OpenGL是两种常用的图形渲染API,但它们有一些显著的不同和各自的优缺点。此外,还有其他一些图形API也可以用于不同的应用场景。下面详细介绍WebGL与OpenGL的对比,并列举一些其他选择。WebGLvs.OpenGLWebGL的优点跨平台支持:WebGL运行在浏览器中,无需安装额......
  • DirectX9(D3D9)游戏开发:高光时刻录制和共享纹理的踩坑
    共享纹理老游戏使用directx9无法直接与cc高光sdk(d3d11)对接,但是d3d9ex有共享纹理,我们通过共享纹理把游戏画面共享给cc录制,记录一些踩坑的笔记。共享纹理示例://初始化Direct3DvoidinitD3D9(HWNDhWnd){hr=d3d9exdev->GetRenderTarget(0,&g_d3d9RenderSurface);......
  • Open3D 计算点云的归一化协方差矩阵
    目录一、概述1.1原理1.2实现步骤1.3应用二、代码实现2.1关键函数2.2完整代码三、实现效果3.1原始点云3.2数据显示Open3D点云算法汇总及实战案例汇总的目录地址:Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客一、概述        计算点云的归一......
  • 如何使用 Python 在 2D 曲面上切割 3D 体积?
    考虑3D中的闭合表面网格(mesh1),由两个合并块组成,如图所示。两个合并块,具有不同颜色的细分补丁。网格以STL文件形式给出,并被细分分成不同的补丁。每个面片都在STL文件中保存为单独的实体。此外,我有一个由STL文件给出的弯曲2D表面网格(......
  • GeneAvatar: 3D 数字人编辑方案
     定位:GeneAvatar是一种通用方法,用于编辑不同体积表示(如NeRFBlendShape、INSTA、Next3D)中的3D数字人,仅需一张2D图像即可实现友好的编辑操作。核心功能:支持使用2D编辑方法(如拖拽式GAN、文本驱动编辑等)从单一视角编辑3D数字人。编辑结果能在多种面部表情和视点间保持一致......
  • 连载|浅谈红队中的权限维持(六)-Linux 主机后门与Linux 隐藏文件
    本文来源无问社区,更多实战内容,渗透思路可前往查看http://www.wwlib.cn/index.php/artread/artid/11584.html0x01Linux主机后门1、添加用户一句话添加用户useraddtest;echo-e"123456n123456n"|passwdtest或者使用openssluseradd-popensslpasswd-1-salt'salt'12......
  • mapbox 结合deckgl添加3DTiles等操作
    1.初始化import{MapboxOverlay}from"@deck.gl/mapbox";import{LineLayer,GeoJsonLayer}from"@deck.gl/layers"; import{TripsLayer,Tile3DLayer}from"@deck.gl/geo-layers"; import{Tiles3DLoader}from"@loade......
  • [米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-26 RS485串口程序收发环路设计
    软件版本:Anlogic-TD5.9.1-DR1_ES1.1操作系统:WIN1064bit硬件平台:适用安路(Anlogic)FPGA实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板板卡获取平台:https://milianke.tmall.com/登录"米联客"FPGA社区http://www.uisrc.com视频课程、答疑解惑! 1概述在前面的课程中,我......