OpenGL ES 2.0 (iOS)[01]: 一步从一个小三角开始


第一步,明确要干嘛

1. 目标:

使用 OpenGL ES 2.0 在 iOS 模拟器中绘制一个三角形。

2. 效果:

3. 分析图形:

1) 背景颜色是蓝色
–> 修改背景颜色

2) 直角三角形
–> 绘制三角形

4.绘制三角形?三角形由什么组成?

–> 三个端点 + 三条线 + 中间的填充色,即三个点连成线形成一个三角面。

1). 三个什么端点(屏幕坐标点)?
要回答这个问题要先了解 OpenGL ES 的坐标系在屏幕上是怎样分布的:
 OpenGL ES 的坐标系{x, y, z}

注:图片截自 《Learning OpenGL ES For iOS》一书

a. 通过图片的三维坐标系可以知道:
- 它是一个三维坐标系 {x, y, z}
- 三维坐标中心在正方体的几何中心 {0, 0, 0}
- 整个坐标系是 [0, 1] 的点,也就是说 OpenGL 中只支持 0 ~ 1 的点

注意,这里所讲的 0 和 1 ,最好理解成 0 –> 无限小, 1 –> 无限大 ,它并不是指 0 个单位的长度,或 1 个单位的长度。

b. 再来看看我们绘制的三角形,在 iOS 模拟器 或真机上 的坐标是怎样构成的:
三维坐标+坐标值 演示图

注:图片通过 CINEMA4D (c4d)三维软件绘制

二维就是长这样的了:
二维坐标( z = 0 )

2) 三条线?

a.连接三个端点形成封闭的三角面,那么 OpenGL ES 能不能直接绘制三角形 ? –> 答案是能。

b.那么 OpenGL 能直接画正方形么?
–> 答案是不能。

c.那OpenGL 能直接绘制什么?
–> 答案是:点精灵、线、三角形,它们统称为 图元(Primitive)。

注:答案来自于《OpenGL ES 2.0 Programming Guide》 7. Primitive Assembly and Rasterization 一章,截图如下:

1) 线元

Line Strip , 指首尾相接的线段,第一条线和最后一条线没有连接在一起;
Line Loops, 指首尾相接的线段,第一条线和最后一条线连接在一起,即闭合的曲线;
Line

2) 三角图元

Triangle Strip, 指条带,相互连接的三角形
Triangle Fan, 指扇面,相互连接的三角形
Triangle
扇面

3) 点精灵 【主要应用在 纹理 方面】

3)填充色?

就是指 RGBA 的颜色值;( ^_^ 感觉好废但还是要说)


第二步,怎么去画(纯理论)

怎么去画,就是通过多少个步骤完成一个完整的绘制渲染流程,当然这里指 OpenGL ES 2 的渲染管线流程)

OpenGL ES 2 的渲染管线

图形管线(Graphics Pipeline)
因为这里是 iOS 端的图,所以重新绘制了一下:
OpenGL ES 2 渲染流程图

注:此图根据 《OpenGL ES 2.0 programming guide》的 Graphics Pipeline 和 Diney Bomfim [All about OpenGL ES 2.x - (part 2/3)] 的管线图进行重新绘制。【绘制的软件为:Visio 2016】

1. 简述绘制流程的每一个单元【至左向右】

OpenGL ES 2.0 API :
 iOS 环境下
gltypes.h 是包含了 OpenGL ES 2.0 的基本数据类型的定义;
glext.h 是包含各种宏定义,以及矩阵运算等常用的函数;
gl.h 是 OpenGL ES 2.0 所有的核心函数(命令);

扩展
OpenGL ES 2.0 Reference (函数查询)在线
左边选择要查询的函数即可
离线的函数 Card
红框处单击打开
红箭头处选择保存即可

本人推荐使用离线的卡,不受网络影响,而且一目了然。配合官方的编程指南使用就最佳了。

2. Vertex Arrays / Buffer Objects :

1) Vertex Arrays Objects (简称:VAOs),顶点数组对象,就是一个数组,包含顶点坐标、颜色值、纹理坐标等数据;通过 CPU内存关联到 GPU 的内存区被 GPU 所使用;

【官方解释:Vertex data may be sourced from arrays that are stored in application memory (via a pointer) or faster GPU memory (in a buffer object).(意指:顶点数组保存在程序内存或快速GPU内存中,前者通过数组指针访问数据,后者直接通过 Buffer Objects 访问。【就是指 VAOs 或 VBOs 方式访问】)】

绘制的三角形的数组(三个顶(端)点坐标)如下图:
顶点数组
VFVertex
这是 C 语言的知识,应该不难理解。

2) _ Vertex Buffer Objects_ , (简称:VBOs [ Vertex Buffer Objects ]),缓存对象,就是持有顶点数组数据或数据下标的对象【并不是指面向对象里面的对象哦,其实一块 GPU 内存块】。

【官方解释:Buffer objects hold vertex array data or indices in high-performance server memory. (意指:VBOs 是持有保存在GPU快速内存区的顶点数据或顶点数据下标的缓存对象。)】

a. 为什么是 server ?
–> 答,OpenGL 是基于 CS 模式的设计而成,客户端操作就相当于我们写的 OpenGL API ( OpenGL commands ) 的各种操作,服务器就是图形处理相关的硬件。( ES 当然也是这意思咯。)

【官方解释:OpenGL is implemented as a client-server system, with the application you write being considered the client, and the OpenGL implementation provided by the manufacturer of your computer graphics hardware being the server.】

注:
**1) **a.b. 里面的【官方解释…】在 OpenGL ES 2.0 Reference Card 可以找到。
**2) **b.1 的【官方解释…】在《OpenGL Programming Guide》第八版 Introduction OpenGL 一章的第一小节 What Is OpenGL 中的解释。

3. Vertex Shader (顶点着色器) :

处理顶点相关的数据,包括顶点在屏幕的位置(矩阵变换),顶点处的光照计算,纹理坐标等。

顶点着色器的信号图:

注:图片截自:《OpenGL ES 2.0 Programming Guide》 1. Introduction to OpenGL ES 2.0 – OpenGL ES 2.0 – Vertex Shader 一节中

1) __输入信号:__Attributes、Uniforms、Samplers (optional)

a. Attributes : 属性的意思,指每一个顶点数据;

b. Uniforms :

b-1. 统一的意思 , 是一个只读全局常量,存储在程序的常量区;
b-2. 当 Vertex Shader 和 Fragment Shader 定义了同名同类型的 Uniform 常量时,此时的 Uniform 常量就变成了全局常量(指向同一块内存区的常量);

c. Samplers (可选的) :
是一个特殊的 Uniforms 保存的是 Texteures(纹理) 数据;

2) 输出信号: Varying

Varying :
a. 它是 Vertex Shader 与 Fragment Shader 的接口,是为了解决功能性问题(两个 Shader 的信息交互);

b. 储存 Vertex Shader 的输出信息;

c. Vertex Shader 与 Fragment Shader 中必须要有必须要同名同类型的Varying 变量,不然会编译错误;(因为它是两个 Shader 的信息接口啊,不一样还接什么口啊。)

3) 交互信息: Temporary Variables

Temporary Variables :
a. 指临时变量;
b. 储存 Shader 处理过程中的中间值用的;
c. 声明在 Funtions(函数) 或 Variable(变量) 内部;

4) __输出的内建变量:__gl_Position、gl_FrontFacing、gl_PointSize

a. gl_Position ( highp vec4 变量 ) :
就是 Vertex Position,Vertex Shader 的输出值,而且是必须要赋值的变量;只有在 Vertex Shader 中使用才会有效

注:highp vec4, highp ( high precision ) 高精度的意思,是精度限定符;vec4 ( Floating Point Vector ) 浮点向量 , OpenGL ES 的数据类型。

b. _ gl_PointSize ( mediump float 变量 ) :_
告诉 Vertex Shader 栅格化点的尺寸(pixels,像素化),想要改变绘制点的大小就是要用这个变量 只有在 Vertex Shader 中使用才会有效

注:mediump , mediump ( medium precision ) 中等精度的意思,是精度限定符;还有最后一个精度限制符是 lowp ( low precision ),低精度的意思。

c. _ gl_FrontFacing ( bool 变量 ) : _
改变渲染物体的 Front Facing 和 Back Facing , 是用于处理物体光照问题的变量,双面光照(3D 物体里外光照)问题的时候才会使用的变量,只能在 Vertex Shader 中进行设置, Fragment Shader 是只读的

4. Primitive Assembly (图元装配) :

1) 第一步,把 Vertex Shader 处理后的顶点数据组织成 OpenGL ES 可以直接渲染的基本图元:点、线、三角形;

2) 第二步,裁剪 ( Clipping ) ,只保留在渲染区域(视锥体,视觉区域)内的图元;

3) 第二步,剔除 ( Culling ),可通过编程决定剔除前面、后面、还是全部;

注:
视锥体,实际上是一个三维锥体包含的空间区域,由摄影机和物体的捕捉关系形成;
视锥体 图片来源 《透视投影详解》一文

5. Rasterization ( 光栅化 ) :

光栅化的信号图:

作用是,将基本图元(点、线、三角形)转换成二维的片元(Fragment, 包含二维坐标、颜色值、纹理坐标等等属性), 像素化基本图元使其可以在屏幕上进行绘制(显示)。

6. Texture Memory ( 纹理内存 ) :

Texture 就是指保存了图片(位图)的所有颜色的缓存;Texture Memory 就是图片的颜色(像素)内存;每一个嵌入式系统对 Texture Memory 的大小都是有限制的;

1) 完整的 iOS 渲染绘制管线图中,向上指向 Vertex Shader 的虚线,意指 Texture Coordinate (纹理坐标)信息是通过程序提供给它的;

2) 完整的 iOS 渲染绘制管线图中,指向 Fragment Shader 的实线,因为 Fragment Shader 处理的是光栅化后的数据,即像素数据,而 Texture 本身就是像素数据,所以 Texture Memory 可以直接当成 Fragment Shader 的输入;

7. Fragment Shader ( 片元着色器 ) :

片元着色器信号图:

1) 输入信号: Varying、Uniforms、Samples
与 Vertex Shader 的输入是同一个意思,具体请查看 Vertex Shader 处的解释~~~;

2) 输入的内建变量:gl_FragCoord、gl_FrontFacing、gl_PointCoord

a. _ gl_FragCoord ( mediump vec4 只读变量 ) :_
是保存窗口相对坐标的 { x, y, z, 1/w } 的变量,z 表示深度 (will be used for the fragment’s depth), w 表示旋转;

b. _ gl_PointCoord ( mediump int 只读变量 ) : _
是包含了当前片元原始点位置的二维坐标;点的范围是 [ 0, 1 ] ;

c. gl_FrontFacing
请查看 Vertex Shader 处的解释;

3) 输出信号 (内建变量) : gl_FragColor、gl_FragData (图上没写)

a. gl_FragColor ( mediump vec4 ) :
片元的颜色值;

b. gl_FragData ( mediump vec4 ) :
是一个数组,片元颜色集;

注:两个输出信号只能同时存在一个,就是 写了 gl_FragColor 就不要写 gl_FragData , 反之亦然;【If a shader statically assigns a value to gl_FragColor, it may not assign a value to any element of gl_FragData. If a shader statically writes a value to any element of gl_FragData, it may not assign a value to gl_FragColor. That is, a shader may assign values to either gl_FragColor or gl_FragData, but not both.

-

补充知识 ( For Shader )

8. Per-Fragment Operations :

信号图:

1) Pixel ownership test ( 像素归属测试 ) :
判断像素在 Framebuffer 中的位置是不是为当前 OpenGL ES Context 所有,即测试某个像素是否属于当前的 Context 或是否被展示(是否被用户可见);

2) Scissor Test ( 裁剪测试 ) :
判断像素是否在由 glScissor* 定义的裁剪区域内,不在该剪裁区域内的像素就会被丢弃掉;

3) Stencil Test ( 模版测试 ):
将模版缓存中的值与一个参考值进行比较,从而进行相应的处理;

4) Depth Test ( 深度测试 ) :
比较下一个片段与帧缓冲区中的片段的深度,从而决定哪一个像素在前面,哪一个像素被遮挡;

5) Blending ( 混合 ) :
将片段的颜色和帧缓存中已有的颜色值进行混合,并将混合所得的新值写入帧缓存 (FrameBuffer) ;

6) Dithering ( 抖动 ) :
使用有限的色彩让你看到比实际图象更为丰富的色彩显示方式,以缓解表示颜色的值的精度不够大而导致颜色剧变的问题。

9. Render Buffer & Frame Buffer:

关系图:

1) Render Buffer ( 渲染缓存 ) :

a. 简称 RBO , Render Buffer Object;
b. 是由程序(Application)分配的 2D 图片缓存;
c. Render Buffer 可以分配和存储颜色(color)、深度(depth)、模版(stectil)值,也可以把这三种值装载到 Frame Buffer 里面;

2) Frame Buffer ( 帧缓存 ) :

a. 简称 FBO , Frame Buffer Object;
b. 是颜色、深度、模板缓存装载在 FBO 上所有装载点的合集;
c. 描述颜色、深度、模板的大小和类型的属性状态;
d. 描述 Texture 名称的属性状态;
e. 描述装载在 FBO 上的 Render Buffer Objects ( 渲染缓存对象 ) 的属性状态;

扩充知识(FBO):

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值