Android显示系统(05)- OpenGL ES - Shader绘制三角形(使用glsl文件)

一、前言:

上一篇文章我们使用了Shader绘制了一个基本的三角形,但是,发现那样写Shader程序特别麻烦,各种加双引号,还没有语法高亮提示。因为glsl也和java、c++一样是一门语言,实际工程项目都是单独的glsl文件管理的,本节我们整改下之前的项目。

二、整改步骤:

  • 新建assets目录,管理glsl资源文件;
  • 新增ShaderController类来操作glsl文件;
  • Shader代码移植到glsl文件当中;

三、编码:

1、创建glsl文件:

  • 新建assets目录:

    在这里插入图片描述

    在这里插入图片描述

  • 新建glsl文件:

    在这里插入图片描述

2、编写Shader程序:

顶点着色器:

文件路径:.\app\src\main\assets\triangle_vertex.glsl

attribute vec4 vPosition;void main() {gl_Position = vPosition;
}

片元着色器:

文件路径:.\app\src\main\assets\triangle_fragment.glsl

precision mediump float;uniform vec4 vColor;
void main() {gl_FragColor = vColor;
}

3、 新建ShaderController类管理Shader程序:

文件路径:com/example/glsurfaceviewdemo/ShaderController.java

package com.example.glsurfaceviewdemo;import android.content.Context;
import android.opengl.GLES30;
import android.util.Log;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;public class ShaderController {/*** 从 assets 文件夹中读取指定文件的内容并返回为字符串** @param filename 文件名* @param context  上下文对象* @return 读取的文件内容字符串*/public static String loadShaderCodeFromFile(String filename, Context context) {// 用于存储读取的着色器代码的字符串StringBuilder shaderCode = new StringBuilder();try {InputStream inputStream = context.getAssets().open(filename);// 使用 BufferedReader 包装输入流,以便逐行读取文件内容BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line;// 逐行读取文件内容并将每行内容追加到 shaderCode 中while ((line = bufferedReader.readLine()) != null) {shaderCode.append(line).append("\n");}// 关闭 BufferedReaderbufferedReader.close();} catch (IOException e) {e.printStackTrace();}// 返回读取的文件内容字符串return shaderCode.toString();}// 创建并编译着色器public static int compileShader(int type, String shaderCode) {// 创建一个着色器int shader = GLES30.glCreateShader(type);// 将着色器代码设置到着色器对象中GLES30.glShaderSource(shader, shaderCode);// 编译着色器GLES30.glCompileShader(shader);return shader;}/*** 创建 OpenGL Program 对象,用于链接顶点着色器和片段着色器** @param vertexShader   顶点着色器源代码* @param fragmentShader 片段着色器源代码* @return 创建的 OpenGL Program 对象 ID*/public static int createGLProgram(String vertexShader, String fragmentShader) {// 编译生成顶点着色器int vShader = compileShader(GLES30.GL_VERTEX_SHADER, vertexShader);if (vShader == 0) {Log.e("GLProgram", "Failed to compile vertex shader.");return 0; // 返回0表示创建失败}// 编译生成片元着色器int fShader = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentShader);if (fShader == 0) {Log.e("GLProgram", "Failed to compile fragment shader.");GLES30.glDeleteShader(vShader); // 删除已经生成的顶点着色器return 0;}// 创建一个OpenGL程序int program = GLES30.glCreateProgram();if (program == 0) {Log.e("GLProgram", "Failed to create OpenGL program.");GLES30.glDeleteShader(vShader);GLES30.glDeleteShader(fShader);return 0;}// attach两个编译好的着色器到program当中GLES30.glAttachShader(program, vShader);GLES30.glAttachShader(program, fShader);// 链接OpenGL程序GLES30.glLinkProgram(program);// 检查链接结果是否成功int[] linkStatus = new int[1];GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0);if (linkStatus[0] == 0) {Log.e("GLProgram", "Failed to link program: " + GLES30.glGetProgramInfoLog(program));GLES30.glDeleteProgram(program);GLES30.glDeleteShader(vShader);GLES30.glDeleteShader(fShader);return 0;}// 删除着色器,因为已经链接到程序中,不再需要保留GLES30.glDeleteShader(vShader);GLES30.glDeleteShader(fShader);Log.i("GLProgram", "GL program created successfully.");return program;}
}

4、修改原来的Triangle类:

文件路径:`com/example/glsurfaceviewdemo/Triangle.java````java
package com.example.glsurfaceviewdemo;import android.content.Context;
import android.opengl.GLES30;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.opengles.GL;public class Triangle {// 顶点数据是float类型,因此,使用这个存储private FloatBuffer mVertexBuffer;private int mProgram;// 定义的三角形顶点坐标数组private final float[] mTriangleCoords = new float[]{0.0f, 0.2f, 0.0f,   // 顶部-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f   // 右下角};public Triangle(Context context) {// 1.初始化顶点缓冲区,存储三角形坐标// 为顶点坐标分配DMA内存空间ByteBuffer byteBuffer = ByteBuffer.allocateDirect(mTriangleCoords.length * 4);// 设置字节顺序为本地字节顺序(会根据硬件架构自适应大小端)byteBuffer.order(ByteOrder.nativeOrder());// 将字节缓冲区转换为浮点缓冲区mVertexBuffer = byteBuffer.asFloatBuffer();// 将顶点三角形坐标放入缓冲区mVertexBuffer.put(mTriangleCoords);// 设置缓冲区的位置指针到起始位置mVertexBuffer.position(0);// 2.加载并编译vertexShader和fragmentShaderString vertexShaderCode = ShaderController.loadShaderCodeFromFile("triangle_vertex.glsl", context);String fragmentShaderCode = ShaderController.loadShaderCodeFromFile("triangle_fragment.glsl", context);// 3.创建一个OpenGL程序,并链接程序mProgram = ShaderController.createGLProgram(vertexShaderCode, fragmentShaderCode);}// 定义的fragment的颜色数组,表示每个像素的颜色private final float[] mColor = new float[]{0.0f, 1.0f, 0.0f, 1.0f};// 顶点着色器的位置句柄private int mPositionHandle = 0;// 片元着色器的位置句柄private int mColorHandle = 0;private final int COORDS_PER_VERTEX = 3;public void draw() {// 使用programGLES30.glUseProgram(mProgram);// 获取顶点着色器的位置句柄mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");// 启用顶点属性数组GLES30.glEnableVertexAttribArray(mPositionHandle);// 准备三角形坐标数据// 重置缓冲区位置mVertexBuffer.position(0);// 指定顶点属性数据的格式和位置GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES30.GL_FLOAT, false, 0, mVertexBuffer);// 获取片元着色器的颜色句柄mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");// 设置绘制三角形的颜色GLES30.glUniform4fv(mColorHandle, 1, mColor, 0);// 绘制三角形GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, mTriangleCoords.length / COORDS_PER_VERTEX);// 禁用顶点属性数组GLES30.glDisableVertexAttribArray(mPositionHandle);}
}
```

四、运行:

在这里插入图片描述

五、小结:

本文主要是讲原来的shader代码拆分到对应的glsl文件中去,为了保证连贯性,Shader没有增减语句,但是,实际工程中来说,这个shader程序写得不够规范,后续章节逐渐补齐。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战用React封装100个组件【009】

Hello,大家好,今天我挑战的组件是这样的! 欢迎大家把项目拉下来使用哦! 项目地址: https://github.com/hismeyy/react-component-100 今天还是用到了react-icons。这里就不过多介绍啦,大家可以在前面的挑战…

电子病历静态数据脱敏路径探索

一、引言 数据脱敏(Data Masking),屏蔽敏感数据,对某些敏感信息(比如patient_name、ip_no、ad、no、icd11、drug等等 )通过脱敏规则进行数据的变形,实现隐私数据的可靠保护。电子病历作为医疗领…

React性能优化

三个可以优化的地方 避免过度多次渲染 组件会在以下情况下重新渲染 注意&#xff1a;例如组件组合的形式&#xff0c;<Test><Counter></Counter></Test>,即使Test发生了重新渲染&#xff0c;Counter也不会重新渲染。另外使用React这样的库或框架时&a…

部署项目报错

vue2项目部署后 Error: Cannot find module /views/*** 1.起因 登录页、首页等静态页面可以正常进入&#xff0c;后端访问也正常&#xff0c;可以获取到验证码。 但是登录之后会发现首页空白或者进入不到首页 F12查看有报错信息&#xff1a;Error: Cannot find module ‘/v…

高端空气净化器airgle—甲醛克星 | 双十二选购指南

随着双十二购物节的临近&#xff0c;许多消费者开始关注高端空气净化器的选购。甲醛作为室内空气污染的主要元凶之一&#xff0c;选择一款高效的空气净化器显得尤为重要。本文将详细介绍Airgle高端空气净化器的技术优势及其在除甲醛方面的卓越表现。 甲醛对健康的影响 甲醛超标…

LCR 023. 相交链表

一.题目&#xff1a; LCR 023. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 二.我的原始解法-无&#xff1a; 三.其他人的正确及好的解法&#xff0c;力扣解法参考&#xff1a; 哈希表法及双指针法&#xff1a;LCR 023. 相交链表 - 力扣&#xff08;LeetCode&#xff0…

RocketMq详解:六、RocketMq的负载均衡机制

上一章&#xff1a;《SpringBootAop实现RocketMq的幂等》 文章目录 1.背景1.1 什么是负载均衡1.2 负载均衡的意义 2.RocketMQ消息消费2.1 消息的流转过程2.2 Consumer消费消息的流程 3.RocketMq的负载均衡策略3.1 Broker负载均衡3.2 Producer发送消息负载均衡3.3 消费端的负载均…

02-开发环境搭建

02-开发环境搭建 鸿蒙开发环境的准备主要分为以下环节&#xff1a; 注册开发者实名认证创建应用下载安装开发工具新建工程 注册开发者 在华为开发者联盟网站上&#xff0c;注册成为开发者&#xff0c;并完成实名认证。 打开华为开发者联盟官网&#xff0c;点击“注册”进入…

使用SQLark分析达梦慢SQL执行计划的一次实践

最近刚参加完达梦的 DCP 培训与考试&#xff0c;正好业务系统有个 sql 查询较慢&#xff0c;就想着练练手。 在深入了解达梦的过程中&#xff0c;发现达梦新出了一款叫 SQLark 百灵连接的工具。 我首先去官网大致浏览了下。虽然 SQLark 在功能深度上不如 DM Manager 和 PL/SQ…

Hive分区值的插入

对于Hive分区表&#xff0c;在我们插入数据的时候需要指定对应的分区值&#xff0c;而这里就会涉及很多种情况。比如静态分区插入、动态分区插入、提供的分区值和分区字段类型不一致&#xff0c;或者提供的分区值是NULL的情况&#xff0c;下面我们依次来展现下不同情况下的表现…

云计算vspere 安装过程

1 材料的准备 1 安装虚拟机 vmware workstation 2 安装esxi 主机 3 在esxi 主机上安装windows 2018 dns 服务器 4 在虚拟机上安装windows 2018 服务器 6 安装vcenter 5 登入界面测试 这里讲一下&#xff0c;由于部署vspere 需要在windows 2012 服务器上部…

【0x0001】HCI_Inquiry命令详解

目录 一、命令概述 1.1. 返回事件说明 1.2. 设备报告规则 二、命令格式及参数 2.1. HCI_Inquiry命令格式 2.2. LAP参数 2.3. Inquiry_Length 2.4. Num_Responses 三、响应事件 3.1. HCI_Command_Status 事件 3.2. HCI_Inquiry_Result, HCI_Inquiry_Result_with_RSSI…

五.指派问题

匈牙利发求解指派问题找独立0元素&#xff0c;常用的步骤为&#xff1a;

2024蜀道山高校联合公益赛

mixian 数组越界&#xff0c;可以去攻击stdout泄露libc&#xff0c;之后伪随机数绕过 from pwn import* from struct import pack import ctypes #from LibcSearcher import * from ae64 import AE64 def bug():gdb.attach(p)pause() def s(a):p.send(a) def sa(a,b):p.sendaf…

【若依框架】RuoYi-Vue的前端和后端配置步骤和启动步骤

&#x1f399;告诉你&#xff1a;Java是世界上最美好的语言 &#x1f48e;比较擅长的领域&#xff1a;前端开发 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我持续下去的动力&#xff01; 目录 一. 作者有话说 …

Python毕业设计选题:基于大数据的旅游景区推荐系统_django

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页界面 用户注册界面 用户登录界面 景点信息界面 景点资讯界面 个人中心界面 …

Endnote 参考文献内容没有按引用顺序进行排序

Endnote 参考文献内容没有按引用顺序进行排序&#xff1a; word论文正文第一个引用就是[4]打头&#xff0c;疯狂卸载重装&#xff0c;修改设置&#xff0c;排查了大半天&#xff0c;最后解决了。 常规解决方案 就是在Endnote 软件里面对outputstyle进行修改&#xff0c;将Biogr…

图像滤波和卷积的不同及MATLAB应用实例

滤波与卷积在图像处理中都是非常重要的运算&#xff0c;但它们有着明显的区别。以下是滤波与卷积的主要不同点&#xff0c;并附带一个MATLAB实例来展示两者在图像处理中的效果差异。 一、滤波与卷积的不同 定义与目的&#xff1a; 1&#xff09;滤波&#xff1a;滤波是一种信…

低级爬虫实现-记录HCIP云架构考试

因工作需要考HCIP云架构&#xff08;HCIP-Cloud Service Solution Architect&#xff09;证书, 特意在淘宝上买了题库&#xff0c; 考过了。 事后得知自己被坑了&#xff0c; 多花了几十大洋。 所以想着在授权期内将题库“爬”下来&#xff0c; 共享给大家。 因为整个过程蛮有…

Scala—Sliding(滑动窗口)用法详解

Scala—Sliding&#xff08;滑动窗口&#xff09;用法详解 Scala 的 sliding 方法在处理集合时&#xff0c;可以方便地获取一个集合的“滑动窗口”&#xff08;能够按照指定的窗口大小和步长从集合中获取子集合&#xff09;。 sliding 方法定义&#xff1a; def sliding(size…