OpenGL 学习教程
Android OpenGL ES 学习(一) – 基本概念
Android OpenGL ES 学习(二) – 图形渲染管线和GLSL
Android OpenGL ES 学习(三) – 绘制平面图形
Android OpenGL ES 学习(四) – 正交投屏
Android OpenGL ES 学习(五) – 渐变色
Android OpenGL ES 学习(六) – 使用 VBO、VAO 和 EBO/IBO 优化程序
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

Android OpenGL ES 学习(五) -- 渐变色相关推荐

  1. Android OpenGL ES 学习(十一) –渲染YUV视频以及视频抖音特效

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  2. Android OpenGL ES 学习(二) -- 图形渲染管线和GLSL

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  3. Android OpenGL ES 学习(六) – 使用 VBO、VAO 和 EBO/IBO 优化程序

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  4. Android OpenGL ES 学习(十) – GLSurfaceView 源码解析GL线程以及自定义 EGL

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  5. Android OpenGL ES 学习(九) – 坐标系统和实现3D效果

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  6. Android OpenGL ES 学习(十二) - MediaCodec + OpenGL 解析H264视频+滤镜

    OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...

  7. Android OpenGl Es 学习(二):定义顶点和着色器

    概述 这是一个新的系列,学习OpengGl Es,其实是<OpenGl Es 应用开发实践指南 Android卷>的学习笔记,感兴趣的可以直接看这本书,当然这个会记录自己的理解,以下只作为 ...

  8. android自定义美颜相机完整程序,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,其实现原理基本上都是以OpenGL ES为核心的特效处理,大神可以忽 ...

  9. android 美颜相机开发,Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机...

    源码链接:https://github.com/smzhldr/AGLFramework 一.前言 商店里有数十款的美颜相机类产品,以及像抖音,唱吧之类带有视频的软件,功能很强大,其实现原理基本上都是 ...

最新文章

  1. ac自动机模板(hdu2222)
  2. 热榜第一!GitHub 标星 5.6w,如何用 Python 实现所有算法?
  3. JOOMLA中文安装时 数据库发生错误解块办法
  4. 【CV】使用OpenCV进行消失点检测(附代码)
  5. 通过Wireshark抓包分析谈谈DNS域名解析的那些事儿
  6. python使用shell环境变量_linux中添加环境变量(python为例)
  7. Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))...
  8. #并行优化# 容错算法 (Fault Tolerant)
  9. ros 安装c++编译的可执行文件
  10. linux版本的redis bin,redis-4.0.2.tar.gz for centos的linux系统版本下载(安装详细步骤)...
  11. python sys模块 argv用法_python中sys模块的argv
  12. java.lang unsupported classversion解决方法
  13. 详细的组态王软件与200 Smart PLC网口通信教程
  14. build up__css
  15. 计算机专业—毕业设计题目大全
  16. linux运行igv报错,远程linux IGV桌面显示(putty+xming+xmanager)-Go语言中文社区
  17. k8s环境之cicd部署+远程触发
  18. java 配置文件加密_Spring cloud config 配置文件加密方式
  19. Redis---Redis三种常用数据结构
  20. 好用的平板触控笔,apple pencil的平替笔推荐

热门文章

  1. 外汇占款激增究竟是谁惹的祸
  2. 简单实用的二级树形菜单hovertree
  3. 制作网页常见图片格式及特性介绍
  4. 中国房地产泡沫必破裂 而且将会有10年的持续调整
  5. shell--基础语法
  6. Windows虚拟键盘码
  7. Spring5源码分析系列(九)Spring事务原理详解
  8. appium webview H5 测试
  9. layui表格时间戳转换日期格式
  10. python中np.max与np.maximum的区别