Android OpenGL ES (六)渐变色

2024-02-28 07:58
文章标签 android es 渐变色 opengl

本文主要是介绍Android OpenGL ES (六)渐变色,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

之前我们绘制的图形都是只有一个颜色,而本章节我们绘制一个正方形,并且给图形上渐变色,让简单的图形变得绚丽些。

原理

在基础概念的课程中,我们讲解了渲染管道的流程,现在我们再回顾一下。

OpenGL ES开发重点

之前的章节我们都了解使用过了uniform、attribute这两个限定符,现在我们再了解下varying这个限定符。

  • attritude:一般用于各个顶点各不相同的量。如顶点位置、纹理坐标、法向量、颜色等等。
  • uniform:一般用于对于物体中所有顶点或者所有的片段都相同的量。比如光源位置、统一变换矩阵、颜色等。
  • varying:表示易变量,一般用于顶点着色器传递到片段着色器的量。

从上图我们了解到,varying是从顶点着色器传递给片段着色器的变量数据,但这不够严谨准确,接下来仔细分析下这个流程。

我们举例的场景是这样的:有一条线段,有2个顶点,顶点A是红色,顶点B是蓝色,他们做渐变色处理。相关代码如下:

private static final String VERTEX_SHADER = "" +"uniform mat4 u_Matrix;\n" +"attribute vec4 a_Position;\n" +// a_Color:从外部传递进来的每个顶点的颜色值"attribute vec4 a_Color;\n" +// v_Color:将每个顶点的颜色值传递给片段着色器"varying vec4 v_Color;\n" +"void main()\n" +"{\n" +"    v_Color = a_Color;\n" +"    gl_Position = u_Matrix * a_Position;\n" +"}";
private static final String FRAGMENT_SHADER = "" +"precision mediump float;\n" +// v_Color:从顶点着色器传递过来的颜色值"varying vec4 v_Color;\n" +"void main()\n" +"{\n" +"    gl_FragColor = v_Color;\n" +"}";
  1. 顶点着色器 : 每个顶点都执行一次,比如我们绘制一个线段,包含了2个顶点,那么就是执行2次顶点着色器。而我们这里传递给顶点着色器的数据包含了每个顶点的位置、颜色。
  2. 组装图元:将顶点连接,根据需求绘制顶点、线段、三角形,本次案例是线段。
  3. 光栅化图元:关键! 在光栅化图元的时候,将两个顶点之间的线段分解成大量的小片段,varying数据在这个过程中计算生成,记录在每个片段中(而不是从顶点着色器直接传递给片段着色器)。
  4. 片段着色器:每个片段都计算一次,假如是线段中间的片段,那么传递过来的varying值是紫色的。

所以,梳理下上面的流程:顶点的位置(attribute)、颜色(attribute) → 顶点着色器 → 光栅化:计算出每个片段的具体颜色值 → 片段着色器

代码实现

了解了原理、GLSL代码后,其实Java层的部分和之前差不多,应该部分读者可以自己写出来了。
这次课程的案例代码是一个彩色的正方形,GLSL代码如上,Java代码如下。

private static final float[] POINT_DATA = {-0.5f, -0.5f,0.5f, -0.5f,-0.5f, 0.5f,0.5f, 0.5f,
};
private static final float[] COLOR_DATA = {// 一个顶点有3个向量数据:r、g、b1f, 0.5f, 0.5f,1f, 0f, 1f,0f, 1f, 1f,1f, 1f, 0f,
};/*** 坐标占用的向量个数*/
private static final int POSITION_COMPONENT_COUNT = 2;
/*** 颜色占用的向量个数*/
private static final int COLOR_COMPONENT_COUNT = 3;@Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {// 省略部分代码int aPositionLocation = getAttrib("a_Position");int aColorLocation = getAttrib("a_Color");mProjectionMatrixHelper = new ProjectionMatrixHelper(mProgram, "u_Matrix");mVertexData.position(0);GLES20.glVertexAttribPointer(aPositionLocation,POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, 0, mVertexData);GLES20.glEnableVertexAttribArray(aPositionLocation);mColorData.position(0);GLES20.glVertexAttribPointer(aColorLocation,COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, 0, mColorData);GLES20.glEnableVertexAttribArray(aColorLocation);
}@Override
public void onDrawFrame(GL10 glUnused) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, POINT_DATA.length / POSITION_COMPONENT_COUNT);
}

效果如下:

 

渐变色正方形.png

数据传递格式优化

上面我们在描述顶点的信息时候,用了2个数组去分别描述位置、颜色两个信息。那么我们就得去确保两个数组中顶点的位置和颜色是否一一对应,一定错乱就会得不到想要的效果。除了2个数组存两种信息的方式外,我们还可以选择一个数组存两种信息的方式。可以采用“顶点1位置+顶点1颜色+顶点2位置+顶点2颜色......”这样的方式去存储。代码如下:

private static final float[] POINT_DATA = {// 一个顶点有5个向量数据:x、y、r、g、b-0.5f, -0.5f, 1f, 0.5f, 0.5f,0.5f, -0.5f, 1f, 0f, 1f,-0.5f, 0.5f, 0f, 1f, 1f,0.5f, 0.5f, 1f, 1f, 0f,
};

这样我们每个顶点的颜色和位置从代码层面上的清晰度就比较明确了。

而在将这些数据传递给GLSL中,则会稍微复杂点,我们需要引入跨距“Stride”这个概念。

/*** 坐标占用的向量个数*/
private static final int POSITION_COMPONENT_COUNT = 2;
/*** 颜色占用的向量个数*/
private static final int COLOR_COMPONENT_COUNT = 3;
/*** 数据数组中每个顶点起始数据的间距:数组中每个顶点相关属性占的Byte值*/
private static final int STRIDE =(POSITION_COMPONENT_COUNT + COLOR_COMPONENT_COUNT) * BYTES_PER_FLOAT;
@Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {// 省略部分代码......mVertexData.position(0);GLES20.glVertexAttribPointer(aPositionLocation,POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, mVertexData);GLES20.glEnableVertexAttribArray(aPositionLocation);// 将数组的初始读取位置右移2位,所以数组读取的顺序是r1, g1, b1, x2, y2, r2, g2, b2...mVertexData.position(POSITION_COMPONENT_COUNT);// COLOR_COMPONENT_COUNT:从数组中每次读取3个向量// STRIDE:每次读取间隔是 (2个位置 + 3个颜色值) * Float占的Byte位GLES20.glVertexAttribPointer(aColorLocation,COLOR_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDE, mVertexData);GLES20.glEnableVertexAttribArray(aColorLocation);
}

现在我们结合上面方法内第二段代码中,实现颜色数据传递的内容,重新再讲解下glVertexAttribPointer这个方法的参数要求。

  1. 顶点信息索引,位置、纹理坐标、法向量、颜色等等 - aColorLocation,顶点颜色索引
  2. 每个顶点属性需要关联的分量个数(必须为1、2、3或者4。初始值为4。) - |COLOR_COMPONENT_COUNT,颜色RGB需要3个向量
  3. 数据类型 - GLES20.GL_FLOAT,浮点类型
  4. 指定当被访问时,固定点数据值是否应该被归一化(GL_TRUE)或者直接转换为固定点值(GL_FALSE)(只有使用整数数据时)
  5. 指定连续顶点属性之间的偏移量。如果为0,那么顶点属性会被理解为:它们是紧密排列在一起的。初始值为0。- STRIDE:每次读取间隔是 (2个位置 + 3个颜色值) * Float占的Byte位 = 5 * 4 = 20.
  6. 数据缓冲区 - mVertexData,顶点数据,包含了位置和颜色

场景应用

在顶点数据较多,且属性数据不变的情况下,使用单个数组来存储数据是个比较好的方案,而在部分数据有所变动,如顶点位置不变,颜色变化的情况下,用多个数组存储数据会是比较好的方案。

这篇关于Android OpenGL ES (六)渐变色的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/754869

相关文章

SpringBoot整合(ES)ElasticSearch7.8实践

《SpringBoot整合(ES)ElasticSearch7.8实践》本文详细介绍了SpringBoot整合ElasticSearch7.8的教程,涵盖依赖添加、客户端初始化、索引创建与获取、批量插... 目录SpringBoot整合ElasticSearch7.8添加依赖初始化创建SpringBoot项

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I

Android 实现一个隐私弹窗功能

《Android实现一个隐私弹窗功能》:本文主要介绍Android实现一个隐私弹窗功能,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 效果图如下:1. 设置同意、退出、点击用户协议、点击隐私协议的函数参数2. 《用户协议》、《隐私政策》设置成可点击的,且颜色要区分出来res/l

Android实现一键录屏功能(附源码)

《Android实现一键录屏功能(附源码)》在Android5.0及以上版本,系统提供了MediaProjectionAPI,允许应用在用户授权下录制屏幕内容并输出到视频文件,所以本文将基于此实现一个... 目录一、项目介绍二、相关技术与原理三、系统权限与用户授权四、项目架构与流程五、环境配置与依赖六、完整