《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会使用这个颜色作为当前片段的最终颜色。

相关文章
|
存储 XML 开发工具
探索安卓应用开发:从基础到进阶
在这篇文章中,我们将一起踏上安卓应用开发的旅程。不论你是编程新手还是希望提升技能的开发者,这里都有你需要的东西。我们会从最基础的概念开始,逐步深入到更复杂的主题。文章将涵盖开发环境设置、用户界面设计、数据处理以及性能优化等方面。通过理论与实践的结合,你将能够构建出既美观又高效的安卓应用。让我们一起开启这段技术之旅吧!
|
Android开发 Swift iOS开发
深入探索iOS与Android操作系统的架构差异及其对应用开发的影响
在当今数字化时代,移动设备已经成为我们日常生活和工作不可或缺的一部分。其中,iOS和Android作为全球最流行的两大移动操作系统,各自拥有独特的系统架构和设计理念。本文将深入探讨iOS与Android的系统架构差异,并分析这些差异如何影响应用开发者的开发策略和用户体验设计。通过对两者的比较,我们可以更好地理解它们各自的优势和局限性,从而为开发者提供有价值的见解,帮助他们在这两个平台上开发出更高效、更符合用户需求的应用。
|
Android开发 Swift iOS开发
iOS和安卓作为主流操作系统,开发者需了解两者差异以提高效率并确保优质用户体验。
【10月更文挑战第1天】随着移动互联网的发展,智能手机成为生活必需品,iOS和安卓作为主流操作系统,各有庞大的用户群。开发者需了解两者差异以提高效率并确保优质用户体验。iOS使用Swift或Objective-C开发,强调简洁直观的设计;安卓则采用Java或Kotlin,注重层次与动画。Swift和Kotlin均有现代编程特性。此外,iOS设备更易优化,而安卓需考虑更多兼容性问题。iOS应用仅能通过App Store发布,审核严格;安卓除Google Play外还可通过第三方市场发布,审核较宽松。开发者应根据需求选择合适平台,提供最佳应用体验。
451 3
|
存储 Android开发 开发者
深入理解安卓应用开发的核心组件
【10月更文挑战第8天】探索Android应用开发的精髓,本文带你了解安卓核心组件的奥秘,包括Activity、Service、BroadcastReceiver和ContentProvider。我们将通过代码示例,揭示这些组件如何协同工作,构建出功能强大且响应迅速的应用程序。无论你是初学者还是资深开发者,这篇文章都将为你提供新的视角和深度知识。
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
430 0
|
搜索推荐 Android开发 开发者
安卓应用开发中的自定义控件实践
在安卓应用开发的广阔天地中,自定义控件如同璀璨的星辰,点亮了用户界面设计的夜空。它们不仅丰富了交互体验,更赋予了应用独特的个性。本文将带你领略自定义控件的魅力,从基础概念到实际应用,一步步揭示其背后的原理与技术细节。我们将通过一个简单的例子——打造一个具有独特动画效果的按钮,来展现自定义控件的强大功能和灵活性。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往更高阶UI设计的大门。
218 2
|
缓存 监控 前端开发
探索Android应用开发之旅:从新手到专家
【10月更文挑战第42天】本文将带你踏上Android应用开发的旅程,无论你是初学者还是有经验的开发者。我们将一起探索如何从零开始创建你的第一个Android应用,并逐步深入到更高级的主题,如自定义视图、网络编程和性能优化。通过实际示例和清晰的解释,你将学会如何构建高效、吸引人的Android应用。让我们一起开启这段激动人心的旅程吧!
206 2
|
传感器 XML IDE
探索安卓应用开发:从基础到进阶
【10月更文挑战第23天】在数字化时代的浪潮中,移动应用已成为人们日常生活的延伸。本文以安卓平台为例,深入浅出地介绍了如何从零开始构建一个安卓应用,涵盖了开发环境搭建、基本组件使用、界面设计原则以及进阶技巧等关键步骤。通过实例演示和代码片段,引导读者逐步掌握安卓应用开发的核心技能,旨在激发更多开发者对安卓平台的探索热情,并为初学者提供一条清晰的学习路径。
|
开发框架 前端开发 Android开发
探索安卓和iOS应用开发中的跨平台解决方案
【10月更文挑战第42天】在移动应用开发的广阔天地中,安卓和iOS系统如同两座巍峨的山峰,分别占据着半壁江山。开发者们在这两座山峰之间穿梭,努力寻找一种既能节省资源又能提高效率的跨平台开发方案。本文将带你走进跨平台开发的世界,探讨各种解决方案的优势与局限,并分享一些实用的代码示例,助你在应用开发的道路上更加游刃有余。
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
212 4
下一篇
开通oss服务