《OpenGL ES应用开发实践指南:Android卷》—— 2.5 引入OpenGL管道

简介:

本节书摘来自华章出版社《OpenGL ES应用开发实践指南:Android卷》一 书中的第2章,第2.5节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

2.5 引入OpenGL管道

现在,我们已经定义了曲棍球桌子的结构,并且把这些数据复制到了OpenGL可以存取的本地内存;在把曲棍球桌子画到屏幕上之前,它需要在OpenGL的管道(pipeline)中传递,这就需要使用称为着色器(shader)的子例程(见图2-6)。这些着色器会告诉图形处理单元(GPU)如何绘制数据。有两种类型的着色器,在绘制任何内容到屏幕之前,需要定义它们。
Joe问:什么是字节序
字节序(Endianness)是描述一个硬件架构是如何组织位(bit)和字节(byte)的方式,它们在底层组成一个数字。现实中,最常见的就是多字节数,既可以把它们按大头序(big endian order)排列,即把最重要的字节放在前面;或者按小头序(little endian order)排列,即把最不重要的字节放前面。
举个例子,有个十进制数10 000,如果把它转成二进制数,就是10011100010000。在大头的架构上,这些位就会排列成:
00100111 00010000
在小头的架构上,它们就会排列为:
00010000 00100111
这次使用十六进制再来看一下。十进制数10 000就是十六进制系统中的2710;因为每两个字符对应一个8位字节,在看计算机代码时,十六进制用起来更好些;在大头的架构上,这个数字会另存为:
27 10
而在小头的架构上,同样的数字会另存为:
10 27
正常情况下,我们不需要担心字节序。当使用ByteBuffer时,只需要保证它和硬件使用了同样的字节序;否则结果就会出现莫名其妙的错误。在Wikipedia上有更多关于字节序的内容。
1.顶点着色器(vertex shader)生成每个顶点的最终位置,针对每个顶点,它都会执行一次;一旦最终位置确定了,OpenGL就可以把这些可见顶点的集合组装成点、直线以及三角形。
2.片段着色器(fragment shader)为组成点、直线或者三角形的每个片段生成最终的颜色,针对每个片段,它都会执行一次;一个片段是一个小的、单一颜色的长方形区域,类似于计算机屏幕上的一个像素。
一旦最后的颜色生成了,OpenGL就会把它们写到一块称为帧缓冲区(frame buffer)的内存块中,然后,Android会把这个帧缓冲区显示到屏幕上。
screenshot

Joe问:为什么使用着色器
在着色器出现之前,OpenGL只能使用一个固定的方法集合控制很少而有限的事情,比如场景里有多少光线或者加多少雾;这些固定的API很容易使用,但是它们很难扩展。你只能实现API提供的效果,而且仅此而已;几乎不能添加如卡通着色一样的自定义
效果。
随着时间的推移,底层的硬件有了很大提高;设计OpenGL的人意识到这些API需要演进,并跟上这些变化。在OpenGL ES 2.0里,他们使用着色器加入了可编程API;为了保持简洁,他们把那些固定的API完全删除了,因此,用户必须使用着色器。
我们现在用着色器控制每个顶点应该如何画到屏幕上,我们也控制所有点、直线和三角形上的每个片段应该如何绘制;这打开了一个新的、充满了无限可能的新世界。我们现在可以按每个像素实现光照和其他优美的效果,如卡通着色。只要我们可以用着色器语言表达出来,就可以加入任何理想的自定义效果。
作为OpenGL和着色器的快速参考,khronos.org提供了一个很好的快速参考卡片,可以把它打印出来,并且随时查看。

2.5.1 创建第一个顶点着色器

让我们创建一个简单的顶点着色器,它会分配在代码中定义的那些位置;为此,首先需要按照下面的步骤为这个着色器创建一个新的文件:
1.首先,需要创建一个新文件夹;右键单击项目中的“res”文件夹,选择“New”,再选择“Folder”,并把这个新文件夹命名为“raw”。
2.现在,需要创建一个新文件;右键单击刚刚创建的新文件夹,选择“New”,再选择“File”,并把新文件命名为“simple_vertex_shader.glsl”。
既然着色器的新文件已经创建好了,让我们在其中加入如下代码:
screenshot

这些着色器使用GLSL定义,GLSL是OpenGL的着色语言;这个着色语言的语法结构与C语言相似。更多的信息可以参考前文提到的快速参考卡片或者完整的规范。
对于我们定义过的每个单一的顶点,顶点着色器都会被调用一次;当它被调用的时候,它会在a_Position属性里接收当前顶点的位置,这个属性被定义成vec4类型。
一个vec4是包含4个分量的向量;在位置的上下文中,可以认为这4个分量是x、y、z和w坐标,x、y和z对应一个三维位置,而w是一个特殊的坐标,第6章会讲述更多关于w的细节。如果没有指定,默认情况下,OpenGL都是把向量的前三个坐标设为0,并把最后一个坐标设为1。
还记得曾经讲过一个顶点会有几个属性,比如颜色和位置么?关键词“attribute”就是把这些属性放进着色器的手段。
之后,可以定义main(),这是着色器的主要入口点;它所做的就是把前面定义过的位置复制到指定的输出变量gl_Position;这个着色器一定要给gl_Position赋值;OpenGL会把gl_Position中存储的值作为当前顶点的最终位置,并把这些顶点组装成点、直线和三角形。

2.5.2 创建第一个片段着色器

既然已经创建了一个顶点着色器,就有了为每个顶点生成最终位置的子例程;我们仍然需要创建一个为每个片段生成最终颜色的子例程。在此之前,让我们花些时间了解一下什么是片段,以及一个片段是怎么产生的。
光栅化(Rasterization)技术
移动设备的显示屏由成千上百万个小的、独立的部件组成,它们称为像素(pixel);这些像素中的每一个都有能力显示几百万种不同颜色范围中的一种颜色。然而,这实际上是一种视觉技巧:大多数显示器并不能真正创造几百万种颜色,所以每个像素通常由三个单独的子组件构成,它们发出红色、绿色和蓝色的光,因为每个像素都非常小,人的眼睛会把红色、绿色及蓝色的光混合在一起,从而创造出巨量的颜色范围;把足够多的单独的像素放在一起,就能显示出一页文本或者蒙娜丽莎像。
OpenGL通过“光栅化”的过程把每个点、直线及三角形分解成大量的小片段,它们可以映射到移动设备显示屏的像素上,从而生成一幅图像。这些片段类似于显示屏上的像素,每一个都包含单一的纯色。为了表示颜色,每个片段都有4个分量:其中红色、绿色、蓝色用来表示颜色,阿尔法(alpha)分量用于表示透明度;关于这个颜色模型是如何工作的,我们将在2.6节中讨论更多的细节。

380d9a8000019fa0db3521f887ecf33fa049582d

在图2-7中,可以见到OpenGL怎样把一条直线光栅化为一个片段集合。显示系统通常会把这些片段直接映射到屏幕上的像素,结果一个片段就对应一个像素;然而,并不总是这样的:一个超高分辨率的设备可能需要使用较大的片段,以减少GPU的工作负荷。
编写代码
片段着色器的主要目的就是告诉GPU每个片段的最终颜色应该是什么。对于基本图元的每个片段,片段着色器都会被调用一次,因此,如果一个三角形被映射到10 000个片段,片段着色器就会被调用10 000次。
让我们继续并编写这个片段着色器;在项目中创建一个新的文件——“/res/raw/simple_fragment_shader.glsl”,并加入如下代码:
screenshot

精度限定符
在这个片段着色器中,文件顶部的第一行代码定义了所有浮点数据类型的默认精度。这就像在Java代码中选择浮点数还是双精度浮点数一样。
可以选择lowp、mediump和highp,它们分别对应低精度、中等精度及高精度;然而,只有某些硬件实现支持在片段着色器中使用highp。
为什么顶点着色器没有定义精度呢?顶点着色器同样可以改变其默认的精度,但是,对于一个顶点的位置而言,精确度是最重要的,OpenGL设计者决定把顶点着色器的精度默认设置成最高级——highp。
你可能已经猜到了,高精度数据类型更加精确,但是这是以降低性能为代价的;对于片段着色器,出于最大兼容性的考虑,选择了mediump,这也是基于速度和质量的权衡。

生成片段的颜色
这个片段着色器的剩余部分与早前定义的顶点着色器一样。不过这次我们要传递一个uniform,它叫做u_Color。它不像属性,每个顶点都要设置一个;一个uniform会让每个顶点都使用同一个值,除非我们再次改变它。如顶点着色器中的位置所使用的属性一样,u_Color也是一个四分量向量,但在颜色的上下文中,这四个分量分别对应红色、绿色、蓝色和阿尔法。
接着我们定义了main(),它是这个着色器的主入口点,它把我们在uniform里定义的颜色复制到那个特殊的输出变量——gl_FragColor。着色器一定要给gl_GragColor赋值,OpenGL会使用这个颜色作为当前片段的最终颜色。

相关文章
|
17天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
1月前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin协程的实践指南
【2月更文挑战第16天】 在移动开发领域,性能优化和应用响应速度是衡量用户体验的关键因素。对于Android开发者而言,Kotlin协程提供了一种革新的异步编程方式,旨在简化后台任务的处理并提高应用效率。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何在实际项目中实现以提升应用性能和用户满意度。通过具体示例和最佳实践,我们将了解协程如何在不阻塞主线程的情况下执行耗时操作,以及它们是如何成为现代Android开发不可或缺的工具。
25 1
|
14天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
12 1
Android开发之OpenGL的画笔工具GL10
|
1月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin协程的实践指南
【2月更文挑战第26天】 在移动开发领域,性能优化和应用响应速度是用户体验的关键因素。针对Android平台,Kotlin协程作为一种新的并发处理方式,以其轻量级线程管理和非阻塞特性,正在改变开发者编写异步和后台任务的方式。本文将深入探讨Kotlin协程的原理,并通过实例展示如何在Android应用中有效利用协程来提升性能和响应能力。
|
1月前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【2月更文挑战第17天】 在移动开发领域,性能优化和流畅的用户体验是永恒的追求。随着Kotlin语言在Android平台的普及,协程作为其提供的一种轻量级线程管理方案,已成为提升应用响应性和并发处理能力的重要工具。本文将深入探讨Kotlin协程的核心概念、使用场景以及在实际Android开发中如何有效利用协程来改善应用性能和代码可读性。通过实例分析,我们将揭示协程在异步任务执行、网络请求和数据库操作中的高效应用,并展示如何结合现有框架和库无缝集成协程,从而为开发者提供一份全面的Kotlin协程实践指南。
|
4月前
|
XML 小程序 Java
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)
49 0
|
4月前
|
XML 前端开发 Java
【Android App】三维处理中三维投影OpenGL功能的讲解及实战(附源码和演示 超详细必看)
【Android App】三维处理中三维投影OpenGL功能的讲解及实战(附源码和演示 超详细必看)
33 1
|
4月前
|
XML Java Android开发
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
Android App开发中OpenGL三维投影的讲解及实现(附源码和演示 简单易懂)
37 1
|
7月前
|
Android开发
Android应用开发权限
Android应用开发权限
44 1