深入iOS开发:OpenGL ES 3.0绘制三角形、屏幕旋转及架构设计技巧解析

更新:11-08 名人轶事 我要投稿 纠错 投诉

大家好,今天小编来为大家解答深入iOS开发:OpenGL ES 3.0绘制三角形、屏幕旋转及架构设计技巧解析这个问题,很多人还不知道,现在让我们一起来看看吧!

OpenGL ES程序流水线图

着色器是一个语法类似于C语言的小程序片段。不同的图形接口有不同的着色器语言。对于OpenGL来说,是GLSL(OpenGL Shader Language),Metal也有自己的着色器语言。就我的经验而言,Metal 编程模型更加直观,而OpenGL 则过于陈旧,难以理解。

2.OpenGL ES 3.0绘制三角形

在开始具体操作之前,首先了解OpenGL ES程序的运行流程。 ES采用服务器/客户端编程模型。 CPU是客户端,调用的函数被发送到GPU(服务器端),由GPU转换为底层图形硬件支持的绘图命令。

OpenGL 旨在将函数调用转换为可发送到底层图形硬件的图形命令。由于该底层硬件专用于处理图形命令,因此OpenGL 绘图通常非常快。

程序运行过程

从iOS OpenGL ES 3编程1:"Hello world"可以看出,绘制三角形的操作应该在清除缓冲区操作之后进行。前面已经介绍过,具体的操作都是由着色器来实现的,所以我们先来了解一下着色器。

2.1.着色器

着色器不在Xcode 中编译,而是以源代码字符串的形式存在。当应用程序运行时,ARM(在iOS上)处理器会将其编译成与当前图形硬件兼容的可执行文件。该过程类似于C语言程序的编译和链接过程。尽管OpenGL ES 标准提供了加载已编译着色器二进制数据的功能,但iOS 不支持这种方法。这个问题稍后会描述。

1. 顶点着色器

顶点被变换和照亮,组装成基元,并光栅化以创建2D 图像。

#version300eslayout(location=0) 在vec4 位置;voidmain(){ gl_Position=位置;}

OpenGL ES 3.0着色器编写比2.0多了一项要求:在开头声明版本信息,#version 300 es,300表示使用OpenGL ES 3.0。将其更改为310 表示OpenGL ES 3.1。 Nexus 6P 支持3.1。目前所有iOS 设备最多仅支持3.0。由于3.0向后兼容2.0,意味着用2.0语法编写的着色器也可以正常使用。

in表示输入参数,vec4是类型,表示向量(x,y,z,w),同样vec3表示向量(x,y,z),以此类推。位置是参数名称。数据一般是从CPU上传到GPU,可以看作是CPU和GPU之间的通信端口。 layout(location=0)指定属性索引为0。ES 3.0最多支持16个属性。默认情况下,它们按递增的自然顺序排列。您可以使用位置来修改它们的顺序。这也是后续CPU向GPU上传数据的基础。

ES 3.0 有三个参数修饰符,in、uniform 和out。其中uniform与ES 2.0相同,代表不可变数据。数据在顶点着色器和片段着色器之间共享。每个顶点和片段着色器都可以访问相同的值。其余的对应关系是:

in==属性,表示输入数据

out==Varying,表示渲染管线后续操作的输出数据。

gl_Position是GLSL的内置变量,表示顶点坐标,数据类型为vec4。此外,还有几个内置变量,将在后续文档中介绍。

2. 片段着色器

#version300es precision highpfloat;out vec4 o_color;voidmain(){ o_color=vec4(1.0,1.0,0,1.0);//RGBA}

比顶点着色器多了一项要求:如果使用浮点数,则必须指定浮点精度。精度越高,对应的颜色过渡越细腻,计算时间就越长,漂亮的东西价格也就越高。由于ES 3.0不再提供gl_FragColor内置变量,因此在使用完全符合3.0语法的GLSL时,使用gl_FragColor会导致编译错误。为了表示顶点对应的像素颜色值,这里声明了一个vec4类型变量o_color。

现在着色器内容的编码已经完成,下面介绍如何使用它们。

2.2.编译和使用着色器

前面提到,shader 以源代码字符串的形式保存,并在App 运行过程中进行编译。那么,下面介绍编译shader的步骤。

2.2.1.编译着色器

需要编译两个着色器:顶点(GL_VERTEX_SHADER)和片段(GL_FRAGMENT_SHADER)。 Shader源码中可能存在写入错误导致编译失败,因此需要进行编译检查。 OpenGL ES不会主动提示编译结果,需要你主动查询。

编译着色器的过程与编译C代码类似:

创建着色器

指定着色器源代码

编译源代码

检查编译错误

适当时,删除编译的着色器数据

示例代码如下:

GLuintcompileShader(char*shaderContent, GLenum shaderType){//1GLuint shader=glCreateShader(shaderType);//2glShaderSource(shader,1, shaderContent,NULL);//3glCompileShader(shader);//4GLintcompileStatus; glGetShaderiv(着色器, GL_COMPILE_STATUS ,compileStatus);if(compileStatus==GL_FALSE) { GLint infoLength; glGetShaderiv(着色器, GL_INFO_LOG_LENGTH, infoLength);if(infoLength 0) { GLchar *infoLog=malloc(sizeof(GLchar) * infoLength); glGetShaderInfoLog(shader, infoLength, NULL, infoLog);printf("%s -n%sn", C_STRING(shaderType), infoLog);free(infoLog); } }返回着色器;}

对于错误输出,也可以直接使用字符串数组,省去分配堆内存的麻烦。

GLint shaderCompileLogLength;glGetShaderiv(着色器,GL_INFO_LOG_LENGTH,shaderCompileLogLength);charcompileMessage[shaderCompileLogLength];glGetShaderInfoLog(着色器,shaderCompileLogLength,NULL,compileMessage);printf("s-nsn",C_STRING(shaderType),compileMessage) ;

删除编译器一般是在释放绘图资源时进行的。将之前保存的着色器句柄传递给void glDeleteShader(GLuint Shader);那是。该函数不会立即删除着色器,而是将指定着色器标记为已删除。着色时只有当设备没有与任何程序对象关联(Attach)时,内存才会被清除。

2.2.2.使用着色器

着色器不能单独作用于OpenGL,而是通过一个中介者来组织和使用,这个中介者就是程序对象(程序)。 OpenGL ES规定一个程序必须配备一对着色器,而且只能配备一对,即有效程序=顶点着色器+片段着色器。

看到程序执行结果后,很多人会想,为什么只指定了几个顶点及其颜色,图形就会显示出过渡颜色。

OpenGL ES 规范没有定义窗口层;相反,托管操作系统必须提供函数来创建OpenGL ES 渲染上下文(接受命令)和帧缓冲区(将任何绘图命令的结果写入其中)。在iOS 上使用OpenGL ES 需要使用iOS 类来设置和呈现绘图表面,并使用平台无关的API 来渲染其内容。

3.OpenGL ES处理屏幕旋转

iPhone等设备的屏幕旋转会导致上一节创建的图形超出屏幕范围。具体情况是纵向启动应用程序,然后水平转动屏幕,或反之亦然,如下图。

从竖屏转横屏时存在偏移

横屏转竖屏时有偏移

显然,这不是我们想要的,需要修复。

3.1.维修简单

[self.view addSubview:view];添加我们自定义的GLView作为子视图,在屏幕旋转时会出现上述的偏移问题。一个简单的解决方案是在Storyboard 中将View 类设置为我们自定义的GLView 或设置self.view=view;在控制器中。这两种说法具有相同的效果。

这种storyboard设置的方法需要我们重写initWithCoder:而我们重写的是initWithFrame:导致代码没有被执行。类似的逻辑必须在initWithCoder:中实现才有效,这就造成了代码冗余。

无论是Storyboard、Xib还是initWithFrame:和self.view=view;视图在显示时都会执行layoutSubviews,所以在这个交集处绘制是一个不错的选择。将initWithFrame:中的绘图代码迁移到layoutSubviews中,并删除View中的其他代码。然后运行应用程序。可以发现,旋转屏幕时,画面正常。

但是,调用[self.view addSubview:view]的问题;仍然存在。这就需要ViewController通知View重新布局子视图来触发layoutSubviews。对此问题进行进一步分析。

首先,控制器覆盖- viewWillTransitionToSize: 和TransitionCoordinator:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {NSLog(@"size=%@, 图层矩形=%@",NSStringFromCGSize(size),NSStringFromCGRect(self.view.layer.bounds)); [self.viewlayoutIfNeeded];}

size是旋转后的屏幕尺寸,view.layer.bounds是旋转前的屏幕尺寸,layoutIfNeeded不会导致我们自定义的View执行layoutSubviews。

layoutIfNeeded 无效

同样,[self.view setNeedsLayout];不触发layoutSubviews。既然我们的View是Controller的View的子视图,那么如果我们遍历子视图并一一发送刷新通知会发生什么呢?

for(UIView*subviewinself.view.subviews) { [子视图layoutIfNeeded];}

执行发现而不触发layoutSubviews。改成[subview setNeedsLayout];此时就触发了layoutSubviews,但是结果还是错误。

遍历通知子视图进行刷新

END,本文到此结束,如果可以帮助到大家,还望关注本站哦!

用户评论

冷青裳

要学习 iOS 游戏开发吗?这本书应该能帮到我!

    有20位网友表示赞同!

败类

OpenGL ES 3 一直是我的心仪目标,看看能不能从这本书入手。

    有18位网友表示赞同!

栀蓝

屏幕旋转挺重要的功能啊,这个教程讲了吗?

    有6位网友表示赞同!

日久见人心

架构设计是游戏开发的基础吧,期待了解更多有用的技巧。

    有7位网友表示赞同!

红尘烟雨

终于找到一篇关于iOS OpenGL ES 3 的详细教程!

    有12位网友表示赞同!

暮光薄凉

希望这本书介绍一些常见的三角形绘制方法。

    有9位网友表示赞同!

凉凉凉”凉但是人心

我之前对图形渲染还不太了解,这本书会不会比较入门级别?

    有5位网友表示赞同!

∞◆暯小萱◆

游戏开发需要不断学习新技术,正好来看看这本书的内容。

    有6位网友表示赞同!

余温散尽ぺ

看了标题感觉这本书内容很全面。

    有18位网友表示赞同!

厌归人

想让手机上的APP界面看起来更漂亮,这个教程可能非常有用!

    有11位网友表示赞同!

坠入深海i

平时写Android 开发的代码,有机会来了解一下iOS 的编程。

    有5位网友表示赞同!

君临臣

三角形绘制?架构设计? 这都是游戏开发的关键要素啊!

    有18位网友表示赞同!

拉扯

现在很多手机游戏都使用了 OpenGL ES 3.0 吧?

    有7位网友表示赞同!

爱情的过失

学习 iOS 游戏开发需要哪些基础知识呢?

    有6位网友表示赞同!

杰克

希望这本书能帮助我更好地理解iOS 开发的原理。

    有13位网友表示赞同!

哽咽

感觉这个教程很适合刚入门的人!

    有16位网友表示赞同!

莫名的青春

我要开始我的游戏开发之旅,这本教材很棒!

    有16位网友表示赞同!

┲﹊怅惘。

期待能在这本书中学习到最新的 iOS 开发技巧。

    有13位网友表示赞同!

眉黛如画

希望这本书有具体的代码示例和调试技巧。

    有6位网友表示赞同!

【深入iOS开发:OpenGL ES 3.0绘制三角形、屏幕旋转及架构设计技巧解析】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:高效目标管理指南:掌握OKR目标设定核心原则 下一篇:《北冥传说(131)情丝纠葛》