OpenGL精简案例一

文章目录

  • 案例一 绘制点线面
    • 定义Renderer
    • 顶点着色器
    • 片段着色器
      • 内置的特殊变量
    • 应用场景
    • 工具ShaderHelper
    • 工具 TextResourceReader
    • 效果图如下
  • 结论

案例一 绘制点线面

定义Renderer


import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;import com.guide.opengllib.R;
import com.guide.opengllib.simple.ShaderHelper;
import com.guide.opengllib.simple.TextResourceReader;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_LINES;
import static android.opengl.GLES20.GL_POINTS;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glClearColor;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glVertexAttribPointer;
import static android.opengl.GLES20.glViewport;/***/
public class CRenderer implements GLSurfaceView.Renderer {private String TAG = "Qm";//缓冲区private final FloatBuffer vertexData;//上下文private Context context;//float buffer大小private static final int BYTES_PER_FLOAT = 4;//程序private int program;//颜色着色器引用private int aColorLocation;//顶点着色器引用private int aPositionLocation;//glsl 颜色着色器坐标private static final String A_COLOR = "a_Color";//glsl 顶点着色器坐标private static final String A_POSITION = "a_Position";//顶点着色器 每行点个数private static final int POSITION_COMOPNENT_COUNT = 2;//颜色着色器 每行颜色个数private static final int COLOR_COMPONENT_CONT = 3;//每行间隔private static final int STRIDE = (POSITION_COMOPNENT_COUNT + COLOR_COMPONENT_CONT) *BYTES_PER_FLOAT;/*** 1.添加坐标点; OpenGl中,只能绘制点,直线和三角形* 在定义三角形时,我们总是以逆时针的顺序排列顶点,这称为卷曲顺序。*/float[] tableVertices = {// Order of coordinates: X, Y, R, G, B// Triangle Fan0f, 0f, 1f, 1f, 1f,-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, -0.5f, 0.0f, 1.0f, 0.0f,0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, 0.5f, 0.0f, 1.0f, 0.0f,-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,// Line 1-0.5f, 0f, 1f, 0f, 0f,0.5f, 0f, 1f, 0f, 0f,// Mallets0f, -0.25f, 0f, 0f, 1f,0f, 0.25f, 1f, 0f, 0f};public CRenderer(Context context) {this.context = context;//ByteBuffer.allocateDirect 分配一块内存;参数是分配多少字节的内存块。//order 季节缓冲区按照本地字节序组织它的内容。vertexData = ByteBuffer.allocateDirect(tableVertices.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();vertexData.put(tableVertices);}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {Log.w(TAG, "onSurfaceCreated");//设置背景清除颜色为红色。//第一个分量是红色的,第二个是绿色的,第三个是蓝色的,最后一个分量是alpha。glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//1.读取顶点着色器String vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.c_vertex_shader);//读取片段着色器String fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.c_fragment_shader);Log.w(TAG, "onSurfaceCreated,第1步");//2.创建顶点着色器int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);//创建片段着色器int fragmentShader = ShaderHelper.compileFragmentShader(fragmentShaderSource);Log.w(TAG, "onSurfaceCreated,第2步");//3.连接两个着色器program = ShaderHelper.linkProgram(vertexShader, fragmentShader);Log.w(TAG, "onSurfaceCreated,第3步");//4.验证该对象 program 是否可用ShaderHelper.validateProgram(program);Log.w(TAG, "onSurfaceCreated,第4步");//5.使用自定义的程序来绘制GLES20.glUseProgram(program);/*** 6.获取着色器并且为着色器赋值*/aColorLocation = glGetAttribLocation(program, A_COLOR);//获取顶点着色器 a_Position 对象的指针aPositionLocation = glGetAttribLocation(program, A_POSITION);Log.w(TAG, "onSurfaceCreated,第5步");/*** 6.为着色器赋值*/vertexData.position(0);//将位置设置在数据的开头处glVertexAttribPointer(aPositionLocation, POSITION_COMOPNENT_COUNT,GL_FLOAT, false, STRIDE, vertexData);//7.指定OpenGL在哪使用顶点数组glEnableVertexAttribArray(aPositionLocation);Log.w(TAG, "onSurfaceCreated,第6步");/*** 注释* 1.vertexData.position* vertexData将位置设置为2,因为读取颜色属性时,要从第一个颜色属性读取,而不是位置属性,* 而在原数据中,颜色属性的位置是2* 2.glVertexAttribPointer* 把颜色数据和着色器中的a_Color关联起来,STRIDE这个参数是跨距,这个值告诉OpenGL两个* 颜色属性质检的距离是多少,这样位置属性和颜色属性连接存储,就不会将位置属性当做颜色属性读* 3.glEnableVertexAttribArray* 指定OpenGL在哪使用顶点数组*/vertexData.position(POSITION_COMOPNENT_COUNT);glVertexAttribPointer(aColorLocation, COLOR_COMPONENT_CONT, GL_FLOAT,false, STRIDE, vertexData);glEnableVertexAttribArray(aColorLocation);Log.w(TAG, "onSurfaceCreated,第7步");}/*** 当表面发生变化时,onSurfaceChanged被调用。* 这个函数在曲面初始化时至少被调用一次。* 请记住,Android通常会在旋转时重启一个活动,在这种情况下,渲染器将被销毁并创建一个新的。** @param gl* @param width  新的宽度,以像素为单位。* @param height 新的高度,以像素为单位。*/@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {Log.w(TAG, "onSurfaceChanged");//设置OpenGL视口填充整个表面。glViewport(0, 0, width, height);}/*** 每当需要绘制一个新帧时,OnDrawFrame就会被调用。通常,这是在屏幕的刷新率下完成的。** @param gl*/@Overridepublic void onDrawFrame(GL10 gl) {//清除渲染表面。glClear(GL_COLOR_BUFFER_BIT);/*** 8.绘制页面,画桌子,画线,点;* glUniform4f:第一个参数指定Uniform变量的值,后面是红绿蓝和透明值* glDrawArrays:第一个参数绘制三角形,第二个参数从数组开头开始读取顶点,第三个参数读到第六个点*/glDrawArrays(GL_TRIANGLE_FAN, 0, 6);//绘制线glDrawArrays(GL_LINES, 6, 2);//画点glDrawArrays(GL_POINTS, 8, 1);glDrawArrays(GL_POINTS, 9, 1);}
}

顶点着色器

attribute vec4 a_Position;
attribute vec4 a_Color;varying vec4 v_Color;void main(){v_Color = a_Color;gl_Position = a_Position;gl_PointSize = 10.0;
}

片段着色器

precision mediump float;varying vec4 v_Color;void main(){gl_FragColor = v_Color;
}

以下为glsl语法中摘录的一部分,可以发现gl_FragColor gl_Position gl_PointSize 均为内部变量,且必须赋值

内置的特殊变量

glsl程序使用一些特殊的内置变量与硬件进行沟通.他们大致分成两种 一种是 input类型,他负责向硬件(渲染管线)发送数据.
另一种是output类型,负责向程序回传数据,以便编程时需要.

在 vertex Shader 中:

output 类型的内置变量:

变量说明单位
highp vec4 gl_Position;gl_Position 放置顶点坐标信息vec4
mediump float gl_PointSize;gl_PointSize 需要绘制点的大小,(只在gl.POINTS模式下有效)float

在 fragment Shader 中:

input 类型的内置变量:

变量说明单位
mediump vec4 gl_FragCoord;片元在framebuffer画面的相对位置vec4
bool gl_FrontFacing;标志当前图元是不是正面图元的一部分bool
mediump vec2 gl_PointCoord;经过插值计算后的纹理坐标,点的范围是0.0到1.0vec2

应用场景


import android.annotation.SuppressLint;
import android.opengl.GLSurfaceView;
import android.os.Bundle;import androidx.appcompat.app.AppCompatActivity;
import com.guide.opengllib.simple.c.CRenderer;public class Simplectivity extends AppCompatActivity {private GLSurfaceView glSurfaceView;private GLSurfaceView.Renderer mRenderer;@SuppressLint("ClickableViewAccessibility")@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);glSurfaceView = new GLSurfaceView(this);mRenderer = new CRenderer(this);glSurfaceView.setEGLContextClientVersion(2);glSurfaceView.setRenderer(mRenderer);setContentView(glSurfaceView);}@Overrideprotected void onResume() {super.onResume();glSurfaceView.onResume();}@Overrideprotected void onPause() {super.onPause();glSurfaceView.onPause();}
}

工具ShaderHelper


import android.opengl.GLES20;
import android.util.Log;import static android.opengl.GLES20.GL_COMPILE_STATUS;
import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
import static android.opengl.GLES20.GL_LINK_STATUS;
import static android.opengl.GLES20.GL_VALIDATE_STATUS;
import static android.opengl.GLES20.GL_VERTEX_SHADER;
import static android.opengl.GLES20.glAttachShader;
import static android.opengl.GLES20.glCompileShader;
import static android.opengl.GLES20.glCreateProgram;
import static android.opengl.GLES20.glCreateShader;
import static android.opengl.GLES20.glDeleteProgram;
import static android.opengl.GLES20.glDeleteShader;
import static android.opengl.GLES20.glGetProgramiv;
import static android.opengl.GLES20.glGetShaderiv;
import static android.opengl.GLES20.glLinkProgram;
import static android.opengl.GLES20.glShaderSource;
import static android.opengl.GLES20.glValidateProgram;/***/
public class ShaderHelper {private static final String TAG = "ShaderHelper";/** 加载和编译一个顶点着色器,返回OpenGL对象ID */public static int compileVertexShader(String shaderCode) {return compileShader(GL_VERTEX_SHADER, shaderCode);}/** 加载和编译一个片段着色器,返回OpenGL对象ID */public static int compileFragmentShader(String shaderCode) {return compileShader(GL_FRAGMENT_SHADER, shaderCode);}/** 编译一个着色器,返回OpenGL对象ID */private static int compileShader(int type, String shaderCode) {//创建一个新的着色器对象final int shaderObjectId = glCreateShader(type);if (shaderObjectId == 0) {Log.w(TAG, "ShaderHelper: Could not create new shader.");}//传入着色器源glShaderSource(shaderObjectId, shaderCode);//编译着色器glCompileShader(shaderObjectId);//获取编译状态final int[] compileStatus = new int[1];glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);//验证编译状态if (compileStatus[0] == 0) {//如果失败,删除着色器对象glDeleteShader(shaderObjectId);Log.w(TAG, "ShaderHelper: Compilation of shader failed");}//返回着色器对象IDreturn shaderObjectId;}/** 将顶点着色器和片段着色器连接到OpenGL中,返回OpenGL对象ID,连接失败返回0 */public static int linkProgram(int vertexShaderId, int fragmentShaderId) {//创建一个新的程序对象final int programObjectId = glCreateProgram();if (programObjectId == 0) {Log.w(TAG, "ShaderHelper: Could not create new program");}//将顶点着色器附加到程序上glAttachShader(programObjectId, vertexShaderId);//将片段着色器附加到程序上glAttachShader(programObjectId, fragmentShaderId);//将两个着色器连接到一个程序中glLinkProgram(programObjectId);//获取连接状态final int[] linkStatus = new int[1];glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);//验证链接状态if (linkStatus[0] == 0) {//如果失败,删除程序对象glDeleteProgram(programObjectId);Log.v(TAG, "Results of linking program:\n" + GLES20.glGetProgramInfoLog(programObjectId));}//返回程序对象IDreturn programObjectId;}/** 验证OpenGL程序,应该只在开始应用程序调用 */public static boolean validateProgram(int programObjectId) {glValidateProgram(programObjectId);final int[] validateStatus = new int[1];glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0);return validateStatus[0] != 0;}public static int buildProgram(String vertexShaderSource, String fragmentShaderSource) {int program;int vertexShader = compileVertexShader(vertexShaderSource);int fragmentShader = compileFragmentShader(fragmentShaderSource);program = linkProgram(vertexShader, fragmentShader);validateProgram(program);return program;}
}

工具 TextResourceReader

public class TextResourceReader {public static String readTextFileFromResource(Context context, int resourceId) {StringBuilder body = new StringBuilder();try {InputStream inputStream = context.getResources().openRawResource(resourceId);InputStreamReader inputStreamReader = new InputStreamReader(inputStream);BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String nextLine;while ((nextLine = bufferedReader.readLine()) != null) {body.append(nextLine);body.append('\n');}} catch (IOException e) {throw new RuntimeException("Could not open resource:" + resourceId, e);} catch (Resources.NotFoundException nfe) {throw new RuntimeException("Resource not found :" + resourceId, nfe);}return body.toString();}
}

效果图如下

glDrawArrays(GL_TRIANGLE_FAN, 0,6);
在这里插入图片描述
我们不妨尝试将第三个参数修改,帮助我们理解gl的绘制原理
glDrawArrays(GL_TRIANGLE_FAN, 0, 1);
在这里插入图片描述

glDrawArrays(GL_TRIANGLE_FAN, 0, 2);
在这里插入图片描述

glDrawArrays(GL_TRIANGLE_FAN, 0, 3);
在这里插入图片描述

glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
在这里插入图片描述

glDrawArrays(GL_TRIANGLE_FAN, 0, 5);
在这里插入图片描述

结论

PS
1. GL_TRIANGLE_FAN绘制最少三个点
2. 绘制时为逆时针方向
3. 过程:读取顶点数据->执行顶点着色器->组装图元->光栅化图元->执行片段着色器->写入帧缓冲区->显示到屏幕;
4. 关于语法可参见 OpenGL手册

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

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

相关文章

Vue3.0 新特性以及使用变更总结

Vue3.0 在2020年9月正式发布了,也有许多小伙伴都热情的拥抱Vue3.0。去年年底我们新项目使用Vue3.0来开发,这篇文章就是在使用后的一个总结, 包含Vue3新特性的使用以及一些用法上的变更。 图片.png 为什么要升级Vue3 使用Vue2.x的小伙伴都熟悉…

Vue中如何为Echarts统计图设置数据

在前端界面接收后端数据后,将数据赋值给ECharts中的data时出现了,数据读取失败的问题(可能是由于数据渲染的前后顺序问题)。后通过如下方式进行了解决: 1、接下来将介绍UserController中的countUsers方法,…

vue实现富文本

效果图展示 一、安装依赖 npm install vue-quill-editor --save二、具体使用 html <template><!-- 富文本 --><quill-editorref"myQuillEditor"v-model"content":options"editorOption"blur"onEditorBlur($event)"…

【模拟】算法实战

文章目录 一、算法原理二、算法实战1. leetcode1576 替换所有的问号2. leetcode495 提莫攻击3. leetcode6 N字形变换4. leetcode38 外观数列5. leetcode1419 数青蛙 三、总结 一、算法原理 模拟就是用计算机来模拟题目中要求的操作&#xff0c;模拟题目通常具有代码量大、操作…

Docker - Docker安装MySql并启动

因为项目需要连接数据库&#xff0c;但是远程服务器上的mysql我不知道账户和密码&#xff0c;这个时候便是docker发挥作用的关键时刻了&#xff01; 目录 docker安装安装gcc卸载老docker&#xff08;如有&#xff09;安装软件包设置镜像仓库更新yum软件包索引安装docker启动doc…

2023_Spark_实验二:IDEA安装及配置

一、下载安装包 链接&#xff1a;百度网盘 请输入提取码 所在文件夹&#xff1a;大数据必备工具--》开发工具(前端后端)--》后端 下载文件名称&#xff1a;ideaIU-2019.2.3.exe &#xff08;喜欢新版本也可安装新版本&#xff0c;新旧版本会存在部分差异&#xff09; IDEA …

线性代数的学习和整理11: 子式与余子式

目录 1 原始矩阵A 2 子式&#xff08;都是行列式&#xff09; 2.1 k阶子式&#xff08;行数列数即可&#xff09; 比如1阶子式&#xff1a;因为只有1行1列 比如2阶子式&#xff1a;因为有2行2列 比如3阶子式&#xff1a;因为有3行3列 2.2 k阶主子式 {行序号数组} {列序号…

VS的调试技巧

Visual Studiohttps://visualstudio.microsoft.com/zh-hans/vs/ 目录 1、什么是调试&#xff1f; 2、debug和release 3、调试 3.1、环境 3.2、 快捷键 3.2.1、F10和F11 3.2.2、ctrlF5 3.2.3、F5与F9 3.2.3.1、条件断点 3.3、监视和内存观察 3.3.1、监视 3.3.2、内存 …

CSS中如何实现元素之间的间距(Margin)合并效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 外边距合并的示例&#xff1a;⭐ 如何控制外边距合并&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff…

Redis 列表 | Navicat

在最近的博客 文章 中&#xff0c;我们已经了解了 Redis 的六种数据类型。其中&#xff0c;Redis 列表&#xff08;List&#xff09;包含一组字符串&#xff0c;他们按照被添加的顺序进行排序。本文将就列表数据类型进行展开介绍&#xff0c;并且重点介绍一些主要的命令来管理它…

探索Python的魔法世界,开启编程奇幻之旅!

无需魔杖&#xff0c;只需键盘&#xff0c;Python将带你进入一个充满奇幻和创造力的世界。本篇博客将引领你走进Python的魔法大门&#xff0c;从编程新手蜕变为编码魔法师&#xff0c;开启一段激动人心的编程奇幻之旅。 &#x1f340;引言 如果你是一名编程初学者&#xff0c;并…

精准运营,智能决策!解锁天翼物联水利水务感知云

面向智慧水利/水务数字化转型需求&#xff0c;天翼物联基于感知云平台创新能力&#xff0c;提供涵盖水利水务泛协议接入、感知云水利/水务平台、水利/水务感知数据治理、数据看板在内的水利水务感知云服务&#xff0c;构建水利水务感知神经系统新型数字化底座&#xff0c;实现智…

【ArcGIS Pro二次开发】(63):批量更改字段别名

在我工作中遇到的大多数图斑&#xff0c;字段名称一般是英文&#xff0c;字段别名是中文&#xff0c;使用起来是比较方便的。 但有时候也会遇到一些不一样的情况&#xff0c;不知是经过了怎样的处理&#xff0c;图斑的字段别名被修改成了和字段名称一样的英文&#xff0c;这样…

Visual Studio 2022的MFC框架——AfxWinMain全局对象和InitInstance函数

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。 在看这篇帖子前&#xff0c;请先看我的另一篇帖子《Visual Studio 2022的MFC框架——应用程序向导》。 当程序调用了CWinApp类的构造…

度矩阵、邻接矩阵

度矩阵&#xff08;degree matrix&#xff09; 度矩阵是对角阵&#xff0c;对角上的元素为各个顶点的度&#xff0c;顶点vi的度表示和该顶点相关联的变得数量。 在无向图中&#xff0c;顶点vi的度d(vi)N(i)&#xff08;即与顶点相连的边的数目&#xff09;有向图中&#xff0…

PHP8函数的引用和取消-PHP8知识详解

今天分享的是php8函数的引用和取消&#xff0c;不过在PHP官方的参考手册中&#xff0c;已经删除了此类教程。 1、函数的引用 在PHP8中不管是自定义函数还是内置函数&#xff0c;都可以直接简单的通过函数名调佣。函数的引用大致有下面3种&#xff1a; 1.1、如果是PHP的内置函…

mysql sql_mode数据验证检查

sql_mode 功能 sql_mode 会影响MySQL支持的sql语法以及执行的数据验证检查。通过设置sql_mode ,可以完成不同严格程度的数据校验&#xff0c;有效地保障数据准确性 sql_mode 严格模式 VS 宽松模式 宽松模式 比如&#xff0c;插入的数据不满足 表的数据类型&#xff0c;也可能…

Vulnhub: Ragnar Lothbrok: 1靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.226 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.226 作者提示修改hosts文件 目录爆破 gobuster dir -u http://armbjorn -w /usr/share/wordlists/dirbuster/directory-l…

【FreeRTOS】【应用篇】任务管理相关函数

文章目录 前言一、函数解析1. 任务挂起 vTaskSuspend()① 使用场景② 设计思路③ 代码 2. 任务恢复 vTaskResume()① 作用② 设计思路③ 代码 3. 挂起任务调度器 vTaskSuspendAll()① 作用② 代码 4. 恢复任务调度器 xTaskResumeAll()① 设计思路② 代码 5. 任务删除函数 vTask…

Servlet的使用(JavaEE初阶系列17)

目录 前言&#xff1a; 1.Servlet API的使用 1.1HttpServlet 1.2HttpServletRequest 1.3HttpServletResponse 2.表白墙的更新 2.1表白墙存在的问题 2.2前后端交互接口 2.3环境准备 2.4代码的编写 2.5数据的持久化 2.5.1引入JDBC依赖 2.5.2创建数据库 2.5.3编写数…