OpenGLES进阶教程7-天空盒效果

教程

OpenGLES入门教程1-Tutorial01-GLKit
OpenGLES入门教程2-Tutorial02-shader入门
OpenGLES入门教程3-Tutorial03-三维变换
OpenGLES入门教程4-Tutorial04-GLKit进阶
OpenGLES进阶教程1-Tutorial05-地球月亮
OpenGLES进阶教程2-Tutorial06-光线
OpenGLES进阶教程3-Tutorial07-粒子效果
OpenGLES进阶教程4-Tutorial08-帧缓存
OpenGLES进阶教程5-Tutorial09-碰碰车
OpenGLES进阶教程6-Tutorial10-平截体优化
这一次的内容是精心准备的天空盒特效,为了节约大家时间,这次在教程里面不贴代码,demo部分的内容都是干货
写这个demo的过程中遇到了一些坎,最后会提到。
特别留意天空盒纹理坐标推导顶点数据对象切换

概念准备

天空盒特效:OpenGL ES提供了一个立方体贴图(cube mapping)的专门用于产生天空盒效果的纹理贴图模式。
举例:一个人,站在立方体的中间,上下左右前后看到的都是立方体的图片。

效果展示

为节省流量,gif比较模糊,清晰效果可以看demo。


核心思路

天空盒的核心就是通过方向来取样纹理,纹理坐标被当作方向向量,建立适合的正方体后,位置坐标就是纹理坐标。

具体细节

1、尺寸大小

天空盒的尺寸可以随意,但是需要足够大以容纳渲染的场景。
同时天空盒的中心要尽可能贴近视点的眼睛位置,避免太近产生纹理拉伸。

2、纹理坐标到纹素推导(核心)

纹理坐标(s, t, r)被当作方向向量看待,每个纹理单元都表示从原点所看到的纹理立方体上的图像。
如果是texture2D的情况,纹理坐标(s, t)会直接返回相应位置的纹素;
textureCube的情况,首先读取cube纹理,然后以正方体中心为原点,(s,t,r)为方向,求出正方体和方向向量的交点位置(a, b),按照位置(a, b)在纹理上面选择相对应的纹素。
举个例子:
对于(s, t, r) , 假设 S=fabs(s) ,同理有T R。
如果S > T 并且 S > R。 那么可以确定交点在面+x 和 -x
根据s的±可以确定±x面。
直线过原点和点(s, t, r) ,那么也会过点(1, t/s, r/s)。
(t/s) 和(r/s)就是对应的纹素位置。
考虑到立方体的面为[-1, 1],那么可以把 (t/s + 1) / 2,这样就得到真正的纹素坐标( (t/s + 1) / 2, (r/s + 1) / 2)

3、顶点数据对象切换(核心)

  • glBindVertexArrayOES
    很多应用会在同一个渲染帧调用多次glBindBuffer()、glEnableVertexAttribArray()和glVertexAttribPointer()函数(用不同的顶点属性来渲染多个对象)
    新的顶点数据对象(VAO) 扩展会几率当前上下文中的与顶点属性相关的状态,并存储这些信息到一个小的缓存中。之后可以通过单次调用glBindVertexArrayOES() 函数来恢复,不需要在调用glBindBuffer()、glEnableVertexAttribArray()和glVertexAttribPointer()。

  • VAO和VBO
    VBO:顶点缓冲区对象(buffer-object),用于存储顶点坐标、纹理坐标、顶点法线、顶点颜色等。
    VAO:顶点数据对象,记录顶点数据存储状态信息的状态对象(status-object)。

This extension introduces vertex array objects which encapsulate vertex array states on the server side (vertex buffer objects).
These objects aim to keep pointers to vertex data and to provide
names for different sets of vertex data. Therefore applications are
allowed to rapidly switch between different sets of vertex array
state, and to easily return to the default vertex array state.
Q:Should vertex array objects be sharable across multiple OpenGL ES
contexts?
A: No.

总结

demo实现过程遇到最大的一个坑,如下:


bug.gif

暂停的适合,天空盒的效果会消失!
然后开始寻找问题所在,最后发现问题代码出现在这里

        // 增加角度
        if (!self.mPauseSwitch.on) {
            self.angle += 0.01;
        }

实在无法理解为什么角度的改变会影响天空盒的显示。
回顾了一下OpenGL ES的绘制过程,从顶点缓存到变换、着色到帧缓存,发现天空盒的绘制都没有问题。
接着开始思考,会不会是飞机的绘制影响了天空盒的绘制?因为这是两个着色器,存在不同的顶点数据和纹理。
于是尝试在绘制完天空盒后调用下面,防止天空盒绑定的数据缓存被飞机的影响。

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

在绘制完飞机后调用下面,防止飞机的顶点数据去影响到天空盒。

    glDisableVertexAttribArray(GLKVertexAttribPosition);
    glDisableVertexAttribArray(GLKVertexAttribNormal);
    glBindTexture(GL_TEXTURE_2D, 0);

然而并没有什么用 ==!

问题搁在心头好几天,每天都会尝试,也在google查GLKSkyboxEffect相关的问题,可惜GLKSkyboxEffect是苹果官方自己实现。
本来天空盒是上周就已经实现好,为了写这篇文章实现了一个暂停的功能,就出现这个bug。虽然去掉暂停功能很正常,但是这个表明demo确实有缺陷,无法弃之不顾。
经过很多天尝试后,已经可以确定的是,是飞机的绘制影响了天空盒的位置,角度的旋转只是隐藏了bug。
开始寻找非OpenGL ES的文章,看看OpenGL的天空盒实现,同时查看苹果官方的文档。
最后偶然在苹果的文档中看到一个关键词OES,我似乎明白了什么。
OES是OpenGL ES的一个非标准扩展,天空盒里面有用到,而我并没有处理。
尝试用OES来管理飞机的顶点模型。

//    glGenVertexArraysOES(1, &_mPositionBuffer);
//    glBindVertexArrayOES(_mPositionBuffer);

问题果然迎仍而解:暂停的时候天空盒是正常的。
接下来开始尝试不用OES,寻找问题的根源。
最后的结论:天空盒的绘制调用了glBindVertexArrayOES(),可是在绘制结束后没有glBindVertexArrayOES(0);导致飞机的顶点数据影响了天空盒的顶点数据。
解决方案:在绘制完天空盒后调用glBindVertexArrayOES(0);,问题完美解决。

Tips

天空盒还有两部分内容:一个是切图,这个比较简单,用CoreGraphics即可;另一个是用Shader来实现天空盒,而非GLKSkyboxEffect,这部分加进来篇幅就过长了。这两部分都在github上面放了源码,都已经编译调试没问题,下载完可以直接运行。
附上代码

思考题

  • 为什么视点距离天空盒太近会产生纹理拉伸?
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容