Android OpenGL ES 学习(五) -- 渐变色
创始人
2024-03-07 01:36:50
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

相关内容

热门资讯

三部门:不断完善学前教育成本分... 观点网讯:12月23日,国家发展改革委、教育部、财政部联合发布《关于完善幼儿园收费政策的通知》,要求...
汪清林区法院:化解未成年人纠纷... 近日,吉林省汪清林区法院审结了一起涉未成年人在校遭受人身损害案件,法院充分考量了未成年人的行为特点及...
北京市长城保护条例 北京市人民代表大会常务委员会公告 〔十六届〕第45号 《北京市长城保护条例》已由北京市第十六届人民代...
棒杰股份(002634)披露关... 截至2025年12月23日收盘,棒杰股份(002634)报收于5.28元,较前一交易日下跌4.52%...
高盛再度唱多!预计中国股市到2... 来源:视觉中国 界面新闻编辑 | 江怡曼 近日,高盛发布名为《中国策略:2025年中国股市十大...
尤文身价变化:共10人身价下降... 在意甲联赛的激烈竞争中,尤文图斯的球员身价变化引发了广泛关注。根据最新的德转数据,尤文队内有10名球...
美国发布H-1B签证新规,优先... 当地时间12月23日,美国国土安全部发布新规,正式以“加权选择”机制取代H-1B签证原有的随机抽签制...
悉尼恐袭事件,意外替德国默茨政... 刚刚过去的一周,发生在澳大利亚的悉尼邦迪海滩恐怖袭击事件引起全球关注。 对于万里之外的德国而言,这场...
视频丨“粤车南下”驶入香港市区... 今天(12月23日),“粤车南下”驶入香港市区政策正式实施,符合条件的广东私家车可直接驶入香港市区,...
立白回应与经销商解约纠纷:个别... 12月23日,红星新闻报道《多地代理商称与立白集团解约后 对方未按约交接市场致严重损失,律师解读》一...