Android OpenGL ES 学习(五) -- 渐变色
创始人
2024-03-07 08:39:04
0

OpenGL 学习教程
Android OpenGL ES 学习(一) – 基本概念
Android OpenGL ES 学习(二) – 图形渲染管线和GLSL
Android OpenGL ES 学习(三) – 绘制平面图形
Android OpenGL ES 学习(四) – 正交投屏
Android OpenGL ES 学习(五) – 渐变色
代码工程地址: https://github.com/LillteZheng/OpenGLDemo.git

这次要完成的效果:
在这里插入图片描述
前面的代码中,我们的颜色是写死一种的,如何实现上面的渐变色呢?
这里就需要用到光栅化:
在这里插入图片描述
再复习一下光栅化的概念:它会图元映射成屏幕上相应的像素,生成供片段着色器使用上色的片段。

前面说道,顶点数据不止包含位置,还有其他信息,所以,在绘制顶点位置的时候,也传递顶点颜色,由 OpenGL 实现栅格化的效果。
这里,你可能会有疑惑,传递了三个颜色,也应该也是三个颜色啊,怎么会有渐变色呢?
带着疑问,我们来试试。

一. 着色器代码

前面说道,GLSL 在3.0 使用 in 和 out 来在着色器之间,传递数值。所以,我们在顶点着色器中使用 out 定义相同名字的颜色,在片段着色器中,使用 in 接收端相同的名字的颜色值。

private const val VERTEX_SHADER = """#version 300 eslayout(location = 0) in vec4 a_Position;// mat4:4×4的矩阵uniform mat4 u_Matrix;//定义可以给外部赋值的顶点数据layout(location = 1) in vec4 a_Color;//给片段着色器的颜色顶点out vec4 vTextColor;void main(){// 矩阵与向量相乘得到最终的位置gl_Position = u_Matrix * a_Position;gl_PointSize = 30.0;//传递给片段着色器的颜色vTextColor = a_Color;}"""private const val FRAGMENT_SHADER = """#version 300 esprecision mediump float;out vec4 FragColor;//接收端顶点着色器的数据,名字要相同in vec4 vTextColor;void main(){FragColor = vTextColor;}
"""

1.1 定义三角形的顶点位置和颜色

        private val POINT_DATA = floatArrayOf(//三角形,用三个分量,z 分量为 00f,0.5f,0f,-0.5f,-0.5f,0f,0.5f,-0.5f,0f)private val COLOR_DATA = floatArrayOf(//颜色值 RGB1f,0.5f,0.5f,1f,0f,1f,0f,0.5f,1f)//加载到内存private var vertexData = BufferUtil.createFloatBuffer(POINT_DATA)private var colorData = BufferUtil.createFloatBuffer(COLOR_DATA)

1.2 关联和使用顶点索引数据:

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES30.glClearColor(1f, 1f, 1f, 1f)makeProgram(VERTEX_SHADER, FRAGMENT_SHADER)uMatrix = getUniform(U_MATRIX)GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT,false, 0, vertexData)GLES30.glEnableVertexAttribArray(0)GLES30.glVertexAttribPointer(1, 3, GLES30.GL_FLOAT,false, 0, colorData)GLES30.glEnableVertexAttribArray(1)}

1.3 绘制:

    override fun onDrawFrame(gl: GL10?) {//步骤1:使用glClearColor设置的颜色,刷新SurfaceGLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP,0,3)}

效果:
在这里插入图片描述
嗯嗯。。。 ,是的,为啥是渐变色的?不是传了三个颜色吗?
看看官网的解释:

这个图片可能不是你所期望的那种,因为我们只提供了3个颜色,而不是我们现在看到的大调色板。这是在片段着色器中进行的所谓片段插值(Fragment Interpolation)的结果。当渲染一个三角形时,光栅化(Rasterization)阶段通常会造成比原指定顶点更多的片段。光栅会根据每个片段在三角形形状上所处相对位置决定这些片段的位置。
基于这些位置,它会插值(Interpolate)所有片段着色器的输入变量。比如说,我们有一个线段,上面的端点是绿色的,下面的端点是蓝色的。如果一个片段着色器在线段的70%的位置运行,它的颜色输入属性就会是一个绿色和蓝色的线性结合;更精确地说就是30%蓝 + 70%绿。
这正是在这个三角形中发生了什么。我们有3个顶点,和相应的3个颜色,从这个三角形的像素来看它可能包含50000左右的片段,片段着色器为这些像素进行插值颜色。

什么意思呢,我的理解是,这个三角形在光栅化的时候,被分割成N多个小像素点,再填充颜色时候,也是按像素去填充的,从三角形的颜色来看,也可以知道,它是从酒红色过度到蓝色的。

为了验证这个说法也比较简单,我们绘制一条先,它只有两个点,红色和蓝色,看看表现如何,修改顶点数据为线:

        private val POINT_DATA = floatArrayOf(//线段-0.5f,0f,0f,0.5f,0f,0f)private val COLOR_DATA = floatArrayOf(//颜色值 RGB1f,0f,0f,0f,0f,1f,)

绘制那里从三角形改成线

    override fun onDrawFrame(gl: GL10?) {//步骤1:使用glClearColor设置的颜色,刷新SurfaceGLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)GLES30.glLineWidth(10f)GLES30.glDrawArrays(GLES30.GL_LINES,0,2)}

在这里插入图片描述

二. 优化数据

上面的数据,位置和颜色是分开的,一个位置数组,对应一个颜色数组,他们需要一一对应。
但我们可以用另外一种方式,把位置和颜色放到同个数组里面,如:

        private val POINT_COLOR_DATA = floatArrayOf(//定点+颜色0f,0.5f,0f,1f,0.5f,0.5f,-0.5f,-0.5f,0f,1f,0f,1f,0.5f,-0.5f,0f,0f,0.5f,1f)
private var vertexData = BufferUtil.createFloatBuffer(POINT_COLOR_DATA)

这样,我们只需要一个数组,加载一次内存就可以了。

修改加载索引的方式:

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES30.glClearColor(1f, 1f, 1f, 1f)makeProgram(VERTEX_SHADER, FRAGMENT_SHADER)uMatrix = getUniform(U_MATRIX)vertexData.position(0)//步进为 24GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT,false, 24, vertexData)GLES30.glEnableVertexAttribArray(0)//颜色地址从3开始,前面3个为位置vertexData.position(3)GLES30.glVertexAttribPointer(1, 3, GLES30.GL_FLOAT,false, 24, vertexData)GLES30.glEnableVertexAttribArray(1)}

两个点要解释:

步进为啥是24:
顶点着色器允许我们指定任何以顶点属性为形式的输入。这使其具有很强的灵活性的同时,它还的确意味着我们必须手动指定输入数据的哪一个部分对应顶点着色器的哪一个顶点属性。所以,我们必须在渲染前指定OpenGL该如何解释顶点数据。
数据之间是紧密排列的,所以,当只有顶点数据的时候,我们认为它是正确能被获取的:
在这里插入图片描述

  • 位置数据被储存为32位(4字节)浮点值。
  • 每个位置包含3个这样的值。
  • 在这3个值之间没有空隙(或其他值)。这几个值在数组中紧密排列(Tightly Packed)。
  • 数据中第一个值在缓冲开始的位置。

从这里的解释来看,我们第一次完成的渐变色,也可以修改成:

//旧方案GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT,false, 0, vertexData)// 根据步进定义,定个分量个数 * 4(字节)GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT,false, 3 * 4, vertexData
)

也能正常绘制渐变色的三角形。

现在插入了颜色值,所以它的步进为 6 * 4 = 24:
在这里插入图片描述
vertexData.position(3)
对每个顶点属性来说,他们的其实位置都不同,位置默认为0,而颜色值的偏移量是在位置之后,所以偏移量为3。

这样,渐变色我们就学习完了。

参考:
https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/
https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/
https://juejin.cn/post/7145094035521470500

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...