【openGL2021版】天空盒
大家好,我是Lampard猿奋~
欢迎来到船新的openGL基础系列的博客,今天主要实现的是天空盒
(1)什么是天空盒
上周我们已经实现了FPS式的摄像机控制,键盘的“WSAD”可以控制摄像头的前后左右移动,鼠标右键可以控制摄像头旋转
接下来就是要丰富一下蓝蓝的背景,给背景加上一个天空盒 。那什么是天空盒呢?
在实时渲染中,如果要绘制非常远的物体,例如远处的山、天空等,随着观察者的距离的移动,这个物体的大小是几乎没有什么变化的。而实现这种“无穷远”的背景技术就是天空盒技术
而天空盒的实现也非常简单,其实就是将一个立方体展开,然后在六个面上贴上相应的贴图,如上图所示
(2)引入第三方图片解析库soil
说到图片解析库我可是有莫名的熟悉感,早些日子的时候接触到python的Image帮助我实现了制作GIF的需求
现在在openGL上我们同样需要一个图片解析库去帮助我去解析制作天空盒所需的纹理资源
(1)下载SOIL库链接到项目中
首先需要网上下载SOIL库的头文件和lib库(文末也会提供下载链接),在代码中连接进来然后重新编译一下,没有报错就OK,如果有报错可能还是需要去官网下载一个符合自身VS版本的
(2)利用SOIL_load_OGL_texture方法解码纹理
紧接着我们就可以用soil库中的SOIL_load_OGL_texture方法去帮助我们去解码纹理并返回一个openGL的纹理ID,这个方法有四个参数,分别对应的意思是文件名,文件格式,老的纹理ID和一个解码模式
其中间两个参数填0是默认模式,然后最后一个参数我们选SOIL_FLAG_POWER_OF_TWO.现在我们就可以重写纹理类的Init方法了,我还留了一个参数invertY来决定是否翻转我们的纹理(因为有时候解出来的纹理会上下颠倒)
编译一下,显示正确,我们接着往下做
(3)缓存纹理对象
从天空盒开始之后就会用到很多很多的纹理资源,不可能说每一个纹理对象都用到的时候创建,对于创建过的纹理资源我们模仿cocos中的纹理缓冲区,以键值对的形式来缓存我们的纹理对象
我们用LoadTexture方法来加载纹理资源,如果map中没有该纹理路径的键则创建一个新的纹理对象,并以纹理路径为键缓存,否则则直接返回这个纹理对象。最后在main文件中修改一下纹理对象创建的方式即可
(3)创建天空盒类
纹理解析完之后,我们就可以大胆的创建我们的天空盒了。如上文所说,天空盒其实就是一个“无穷远”的立方体,所以我们给天空盒定义前后左右上下六个纹理对象的成员变量,以及一个初始化函数和一个绘制函数
(1)Init天空盒初始化方法
有了纹理对象的加载方法,那加载函数就简单了,我们就只需要分别对六个纹理对象初始化一遍就行
(2)什么是无穷远?
一个矩形图片我们可以用之前学习的glBegin(GL_QUADS)来绘制,但是问题是在于多远是无穷远呢?如果绘制的物体比这个天空盒还远,那不就穿帮出bug了吗?
此时就需要理解深度缓冲的概念了,当openGL深度缓冲开启的时候,每一个位置会记录当前位置上深度优先级最高的像素点的颜色(有点像我们的ZOrder?),这个优先级取值是0-1之间,约靠近0优先级越高。当我们关闭深度缓冲的时候,绘制的内容就是取优先级最低的情况,所以我们绘制天空盒之前需要关闭深度缓冲,绘制物体的时候再重新开启就可以保证绘制的物体在天空盒之前
但是还有一个问题,如果写死天空盒的位置,有了深度缓冲的概念,其他物体是出不去了,但是我摄像头移动,我玩家直接出去了不也是一个bug吗?
这是我们只要把摄像机当前的xyz传递过来,绘制前对天空盒作一个glTranslatef就好啦,下面展示了前纹理的绘制其余的五个面也是同样的做法即可
(3)展示效果
前期准备完成,然后我们就在main方法中创建一个摄像头,然后在绘制的函数中同时绘制天空盒即可
最后看看我们的效果,可以看到无论摄影机怎么变都逃不出天空盒
附soli库下载路径: