Android GlSurfaceView 入门教程 : 绘制一个三角形

news2024/11/28 8:34:04

1. GlSurfaceView是什么

GlSurfaceViewAndroid中的一个类,继承自SurfaceView,用于显示OpenGL ES图形渲染的一个视图。
OpenGL ES是一种跨平台的图形API,用于渲染2D3D图形,也可以将相机的画面显示到GlSurfaceView上,从而实现滤镜的效果。
GlSurfaceView提供了一个可以在Android应用程序中绘制OpenGL ES图形的界面,允许开发者将复杂的3D图形、动画和视觉效果嵌入到应用程序中。
GlSurfaceView处理了OpenGL ES渲染环境的创建、维护和更新,以及与其他Android视图和事件系统的交互。

2. android中怎使用GlSurfaceview

2.1 添加OpenGL ES版本支持

新建Android项目,在AndroidManifest.xml文件中,添加 OpenGL ES 版本支持。例如,要使用 OpenGL ES 2.0,请添加以下代码:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />

如果需要使用 OpenGL ES 3.0 则需要以下声明:0x00030000
如果需要使用 OpenGL ES 3.2 则需要以下声明:0x00030002

2.2 新建自定义的GlSurfaceView

新建一个MyGlSurfaceView类,继承自 GLSurfaceView,并进行初始化

import android.content.Context
import android.opengl.GLSurfaceView
import android.util.AttributeSet

class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {

    init {
        // 设置 OpenGL ES 版本
        setEGLContextClientVersion(2)

        // 设置渲染器
        val renderer = MyGLRenderer()
        setRenderer(renderer)
    }
}

2.3 新建自定义的Renderer

创建一个MyRenderer类,实现 GLSurfaceView.Renderer 接口,并实现其中的方法

class MyGLRenderer : GLSurfaceView.Renderer {
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        //设置清除屏幕时使用的颜色
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
    }

    override fun onDrawFrame(gl: GL10?) {
        // 清除屏幕
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        // 设置视口大小
        GLES20.glViewport(0, 0, width, height)
    }
}

2.4 使用MyGLSurfaceView

Activityxml中使用MyGLSurfaceView

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.heiko.myglsurfaceviewtest.MyGLSurfaceView
        android:id="@+id/gl_surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

2.5 运行看下效果

运行后,可以看到一个使用 OpenGL ES 绘制的黑色屏幕

在这里插入图片描述

3. 在自定义的MyGLRenderer中绘制三角形

3.1 添加顶点着色器和片段着色器的代码

MyGLRenderer 类中,添加顶点着色器和片段着色器的代码。在这里,我们创建一个简单的顶点着色器和片段着色器,它们将顶点位置传递给渲染管线并使用固定颜色进行渲染:

private val vertexShaderCode = "attribute vec4 vPosition;" +
        "void main() {" +
        "  gl_Position = vPosition;" +
        "}"

private val fragmentShaderCode = "precision mediump float;" +
        "uniform vec4 vColor;" +
        "void main() {" +
        "  gl_FragColor = vColor;" +
        "}"

3.2 添加编译和链接着色器的方法

MyGLRenderer 类中,添加一个方法来编译和链接着色器,然后返回着色器程序的 ID

private fun loadShaderProgram(vertexCode: String, fragmentCode: String): Int {
    // 编译顶点着色器
    val vertexShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)
    GLES20.glShaderSource(vertexShader, vertexCode)
    GLES20.glCompileShader(vertexShader)

    // 编译片段着色器
    val fragmentShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)
    GLES20.glShaderSource(fragmentShader, fragmentCode)
    GLES20.glCompileShader(fragmentShader)

    // 链接着色器程序
    val program = GLES20.glCreateProgram()
    GLES20.glAttachShader(program, vertexShader)
    GLES20.glAttachShader(program, fragmentShader)
    GLES20.glLinkProgram(program)
    return program
}

3.3 加载并创建着色器程序

MyGLRenderer 类中,添加成员变量来存储顶点数据、顶点缓冲区对象(VBO)和着色器程序 ID

private val vertexData = floatArrayOf(
    0.0f, 0.5f, 0.0f,
    -0.5f, -0.5f, 0.0f,
    0.5f, -0.5f, 0.0f
)

private var vertexBufferId = 0
private var shaderProgramId = 0

这里vertexData 为什么这么传,是和openGL的世界坐标系相关的
在这里插入图片描述
可以看到vertexData的第一个值0.0f,第二个值0.5f这个坐标点位于Y轴偏上的位置,第三个值0.0f我们不用管,这个是Z轴,在2D图形中我们不需要Z轴,所以这个统一传0.0f就好了。
同理,第四个值-0.5f、第五个值-0.5f位于X轴坐标的偏左侧,第六个值也是Z轴,我们不用管。
第七个值是0.5f,第八个值是-0.5f位于X轴坐标的偏右侧,第九个值也是Z轴,我们不用管。
具体如下图所示

在这里插入图片描述

然后,在 onSurfaceCreated 方法中初始化这些值,然后加载并创建着色器程序

override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
    // 设置清除屏幕时使用的颜色
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)

    // 创建顶点缓冲区对象
    val buffers = IntArray(1)
    GLES20.glGenBuffers(1, buffers, 0)
    vertexBufferId = buffers[0]

    // 将顶点数据上传到缓冲区对象
    val vertexBuffer = ByteBuffer.allocateDirect(vertexData.size * 4)
        .order(ByteOrder.nativeOrder())
        .asFloatBuffer()
    vertexBuffer.put(vertexData)
    vertexBuffer.position(0)

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
    GLES20.glBufferData(
        GLES20.GL_ARRAY_BUFFER,
        vertexData.size * 4,
        vertexBuffer,
        GLES20.GL_STATIC_DRAW
    )
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)

    // 加载并创建着色器程序
    shaderProgramId = loadShaderProgram(vertexShaderCode, fragmentShaderCode);
}

3.4 绘制三角形

onDrawFrame 方法中,使用创建的着色器程序和顶点缓冲区对象来绘制三角形:

override fun onDrawFrame(gl: GL10?) {
    // 清除屏幕
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

    // 使用着色器程序
    GLES20.glUseProgram(shaderProgramId)

    // 绑定顶点缓冲区对象并启用顶点属性
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
    val positionLocation = GLES20.glGetAttribLocation(shaderProgramId, "vPosition")
    GLES20.glEnableVertexAttribArray(positionLocation)
    GLES20.glVertexAttribPointer(positionLocation, 3, GLES20.GL_FLOAT, false, 0, 0)

    // 设置片段着色器的颜色
    val colorLocation = GLES20.glGetUniformLocation(shaderProgramId, "vColor")
    GLES20.glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f)

    // 绘制三角形
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3) // GL_TRIANGLES:三角形 GL_POINTS:点

    // 禁用顶点属性并解除顶点缓冲区对象的绑定
    GLES20.glDisableVertexAttribArray(positionLocation)
    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
}

3.5 设置视口大小

onSurfaceChanged 方法中,还是一样,设置视口大小:

override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
    // 设置视口大小
    GLES20.glViewport(0, 0, width, height)
}

3.6 运行看下效果

在这里插入图片描述

4. Android中GLES20.java的API说明

上面我们已经实现了一个三角形的绘制,但是对于GLES20API还是不太了解,接下来再来看下常用的GLES20 API

4.1 Android中GLES20 API的一些主要功能说明

  • Shaders(着色器):GLES20使用可编程的着色器来渲染图形。顶点着色器处理顶点数据,片段着色器处理像素数据。着色器需要用GLSL(OpenGL Shading Language)编写。
  • Buffers(缓冲区):GLES20使用缓冲区来存储顶点数据和索引数据。顶点缓冲区对象(VBO)存储顶点数据,元素缓冲区对象(EBO)存储索引数据。
  • Textures(纹理):GLES20支持多种纹理类型,如2D纹理、立方体贴图等。纹理用于给3D对象添加详细的表面特征
  • Framebuffers(帧缓冲区):GLES20使用帧缓冲区对象(FBO)来存储渲染结果。你可以将渲染结果渲染到纹理中,然后将纹理应用到其他对象上,实现高级渲染效果。
  • Transformations(变换):GLES20支持多种变换操作,如平移、旋转、缩放等。变换矩阵用于在顶点着色器中处理顶点数据。
  • Lighting(光照):GLES20支持基本的光照计算,如环境光、漫反射光、镜面反射光等。光照计算通常在顶点着色器或片段着色器中进行。
  • Blending(混合):GLES20支持颜色混合,用于实现透明度、半透明等效果。混合操作可以根据源颜色和目标颜色按照指定的混合因子进行计算。
  • Culling(剔除):GLES20支持面剔除,可以剔除不可见的面,提高渲染性能。面剔除可以根据面的正面或反面进行。
  • Depth Testing(深度测试):GLES20支持深度测试,用于判断像素的可见性。深度测试可以根据像素的深度值进行比较,只渲染最前面的像素。
  • Stencil Testing(模板测试):GLES20支持模板测试,用于实现遮罩、镜子等效果。模板测试可以根据模板缓冲区的值对像素进行掩盖或者保留。

4.2 GLES20 API中一些主要方法的说明

  • glGenBuffers:生成缓冲区对象,如顶点缓冲区对象(VBO)和元素缓冲区对象(EBO)。
  • glBindBuffer:绑定缓冲区对象,使其成为当前活动的缓冲区。
  • glBufferData:将数据上传到缓冲区对象。
  • glVertexAttribPointer:定义顶点属性数组,指定顶点数据在缓冲区中的布局。
  • glEnableVertexAttribArray:启用顶点属性数组。
  • glDisableVertexAttribArray:禁用顶点属性数组。
  • glUseProgram:使用某个着色器程序进行渲染。
  • glGetUniformLocation:获取着色器程序中uniform变量的位置。
  • glUniformMatrix4fv:为uniform变量设置矩阵数据。
  • glCreateShader:创建着色器对象。
  • glShaderSource:为着色器对象设置源代码。
  • glCompileShader:编译着色器对象。
  • glGetShaderiv:获取着色器对象的编译状态。
  • glAttachShader:将着色器对象附加到着色器程序。
  • glLinkProgram:链接着色器程序。
  • glGetProgramiv:获取着色器程序的链接状态。
  • glDeleteShader:删除着色器对象。
  • glGenTextures:生成纹理对象。
  • glBindTexture:绑定纹理对象。
  • glTexParameteri:设置纹理参数,如过滤模式、环绕模式等。
  • glTexImage2D:上传纹理数据。
  • glGenFramebuffers:生成帧缓冲区对象。
  • glBindFramebuffer:绑定帧缓冲区对象。
  • glFramebufferTexture2D:将纹理对象附加到帧缓冲区对象。
  • glDrawArrays:绘制顶点数组,渲染图形。
  • glDrawElements:绘制索引数组,渲染图形。
  • glEnable:启用某个OpenGL功能,如深度测试、剔除、混合等。
  • glDisable:禁用某个OpenGL功能。
  • glBlendFunc:设置混合函数。
  • glCullFace:设置剔除面的模式。
  • glClearColor:设置清除颜色缓冲区时使用的颜色。
  • glClear:清除颜色缓冲区、深度缓冲区和/或模板缓冲区。

5. 开启调试

GLSurfaceView.setDebugFlags() 方法可以激活 log或者错误检测,它们可以帮助调试 OpenGL ES 调用。具体使用时,在 GLSurfaceView 的构造函数中,调用 setRender() 之前调用GLSurfaceView.setDebugFlags()就可以了。下面是个例子:

class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {

    init {
        // 设置 OpenGL ES 版本
        setEGLContextClientVersion(2)
        //打开调试和日志
        setDebugFlags(DEBUG_CHECK_GL_ERROR or DEBUG_LOG_GL_CALLS)

        // 设置渲染器
        val renderer = MyGLRenderer()
        setRenderer(renderer)
    }
}

6. 源码下载

本文源码下载 : Android使用GlSurfaceView和OpenGL绘制三角形 Demo

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Boot 中的 SQL 注入攻击是什么,原理,如何预防

Spring Boot 中的 SQL 注入攻击是什么&#xff0c;原理&#xff0c;如何预防 随着互联网的发展&#xff0c;Web 应用程序的数量不断增加&#xff0c;而 SQL 注入攻击也成为了常见的网络安全问题之一。SQL 注入攻击是通过在 Web 应用程序中注入恶意的 SQL 代码&#xff0c;从而…

@RestController 和 @Controller的区别?

Controller 返回一个页面单独使用 Controller 不加 ResponseBody的话一般使用在要返回一个视图的情况&#xff0c;这种情况属于比较传统的Spring MVC 的应用&#xff0c;对应于前后端不分离的情况 RestController 返回JSON 或 XML 形式数据 但RestController只返回对象&#…

FPGA综合设计实验:基于PWM脉宽调制的呼吸流水灯设计

目录 一、引言 二、项目准备 1.项目预期目标 2.项目原理及总体实现思路 三、项目模块设计 1.顶层模块 2.按键控制模块 3.呼吸灯模块 4.数码管显示模块 5.二进制转BCD码模块 四、项目测试 1.仿真测试 2.实物测试 五、项目总结 1.选题思考与过程反思 2.设计的具体…

MySQL之常见的CRUD面试题【上】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于MySQL数据库的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 导读&#xff1a; 一.数据库的连表…

如何获得免费英文文献翻译呢?

我偶然之间发现的一个小技巧分享给大家&#xff01; 这个方法很简单&#xff0c;巧妙地运用了某外国浏览器自带的翻译功能&#xff0c;所以我们需要的是某外国浏览器 1.将需要翻译的pdf文档保存 2.进入http://pdfdo.com/pdf-to-html.aspx将PDF转为网页 3. 上传文件后耐心等待转…

web学习--SpringMVC--1 基础学习

写在前面&#xff1a; 所有的web学习基于springboot项目&#xff0c;而不会去单独的使用spring来进行。 文章目录 SpringMVC介绍原理MVC模式 入门使用导入依赖编写controller类 详细介绍注解详解ControllerRequestMappingResponseBodyRestControllerRequestParamRequestBodyR…

聚观早报 | 字节跳动要造机器人;苹果已开发悬空虚拟键盘

今日要闻&#xff1a;字节跳动要造机器人&#xff1b;苹果已开发悬空虚拟键盘&#xff1b;苹果汽车或售价9万美元&#xff1b;全球首例猪心脏移植患者仅存活60天&#xff1b;首款搭载ChatGPT的自行车问世 字节跳动要造机器人 7 月 3 日消息&#xff0c;「机器人」作为未来科技…

MySQL-分库分表详解(四)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

记录安装ESXI-6.7遇到的问题(DELL)

从官网下载完ISO镜像,使用rufus制作启动盘 安装过程中报错信息 缺少网卡驱动 安装打包网卡驱动请查看此链接:https://www.cnblogs.com/Sunzz/p/11438066.html 通过检测网卡驱动后,报错信息 解决办法 关闭BIOS中的Secure Boot 具体步骤如下&#xff1a; 1.按F2进入bios 2…

最长回文子串 (力扣) 动态规划 JAVA

给你一个字符串 s&#xff0c;找到 s 中最长的回文子串。 如果字符串的反序与原始字符串相同&#xff0c;则该字符串称为回文字符串。 示例 1&#xff1a; 输入&#xff1a;s “babad” 输出&#xff1a;“bab” 解释&#xff1a;“aba” 同样是符合题意的答案。 示例 2&#…

FlinkSQL 解析字符串+行转列

近期遇到一个实时flinksql需求&#xff0c;需要根据ids数组字段解析成名称数组字段。。。 其中parent_path存放的内容是点号分割的字符串"1659077318807721985.1659120595539924993.1659121050219255810" 第一步&#xff1a;新建kafka source源 create TEMPORARY t…

怎样处理服务器无法复制粘贴问题?服务器不能复制粘贴怎么办?

我们经常需要在服务器上进行一些操作&#xff0c;如复制粘贴文件、修改配置等等。但有时候我们会遇到服务器无法使用复制粘贴功能的问题&#xff0c;这时该怎么办呢&#xff1f;以下是一些解决方法。 1&#xff0e;检查RDP剪贴板功能是否开启 在远程桌面连接(RDP)中&#xff…

基于多案例系统学习防洪评价报告编制方法与水流数学模型建模

查看原文>>>基于多案例系统学习防洪评价报告编制方法与水流数学模型建模 随着社会经济的快速发展&#xff0c;我国河道周边土地开发利用率不断增大&#xff0c;临河建筑物与日俱增&#xff0c;部分河道侵占严重&#xff0c;导致防洪压力增大。加之部分河流沿岸临河建…

Win10无法安装到这个磁盘,选中的磁盘具有mbr分区

关闭这个窗口执行一下操作; 1.按住 shiftF10快捷键&#xff0c;打开命令提示符终端&#xff1b; 2.输入diskpart &#xff0c;并按下回车 &#xff1b; 3.输入list disk&#xff0c;并按下回车&#xff0c;查看盘的使用情况 ; 4.输入 select disk 0 &#xff0c;并按下回车&am…

Mybatis-SQL分析组件 | 京东云技术团队

背景 大促备战&#xff0c;最大的隐患项之一就是慢sql&#xff0c;带来的破坏性最大&#xff0c;也是日常工作中经常带来整个应用抖动的最大隐患&#xff0c;而且对sql好坏的评估有一定的技术要求&#xff0c;有一些缺乏经验或者因为不够仔细造成一个坏的sql成功走到了线上&am…

SpringBoot使用EasyExcel实现Excel的导入导出

一、概念 EasyExcel 是一个基于 Java 的、快速、简洁、解决大文件内存溢出的 Excel 处理工具。它能让你在不用考虑性能、内存的等因素的情况下&#xff0c;快速完成 Excel 的读、写等功能。 二、EasyExcel常用注解 注解名称属性介绍ExcelProperty value属性设置表头的名称 i…

CSPM是什么?

背景 2021年10月&#xff0c;中共中央、国务院发布的《国家标准化发展纲要》明确提出构建多层次从业人员培养培训体系&#xff0c;开展专业人才培养培训和国家质量基础设施综合教育。建立健全人才的职业能力评价和激励机制。由中国标准化协会&#xff08;CAS&#xff09;组织开…

【lora模块调试:亿百特lora-型号E22-400T30D-V=代码调试-STM32H7xx/F4xx/F1xx-基础样例(2)】

【lora模块调试&#xff1a;亿百特lora-型号E22-400T30D-V代码调试-STM32H7xx/F4xx/F1xx-基础样例&#xff08;2&#xff09;】 1、概述2、实验环境3、实验说明3-1调试开发板H71、先了解硬件H72、测试keil版本的H7软件代码&#xff08;1&#xff09;找到样例代码。&#xff08;…

3.清除浮动

3.1 为什么需要清除浮动? 由于父级盒子在很多情况下&#xff0c;不方便给高度&#xff0c;但是子盒子浮动又不占有位置&#xff0c;最后父级盒子高度为0时&#xff0c;就会影响下面的标准流盒子。 ●由于浮动元素不再占用原文档流的位置&#xff0c;所以它会对后面的元素排…

java开发微信公众平台之素材上传

微信公众平台官方文档 我在本地使用工具请求接口一切正常。 当我开始写代码的时候 我蒙了 后台怎么模拟form表单上传图片 放参考文章链接https://blog.csdn.net/subaiqiao/article/details/122059076 首先引入依赖 <dependency><groupId>com.squareup.okhttp3&l…