OpenGL ES -> GLSurfaceView绘制点、线、三角形、正方形、圆(顶点法绘制)

XML文件

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

自定义GLSurfaceView代码

class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {private var mRenderer = MyGLRenderer()init {// 设置 OpenGL ES 3.0 版本setEGLContextClientVersion(3)setRenderer(mRenderer)// 设置渲染模式, 仅在需要重新绘制时才进行渲染,以节省资源renderMode = RENDERMODE_WHEN_DIRTY}
}

自定义GLSurfaceView.Renderer代码

class MyGLRenderer : GLSurfaceView.Renderer {private var mDrawData: DrawData? = nulloverride fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {// 当 Surface 创建时调用, 进行 OpenGL ES 环境的初始化操作, 设置清屏颜色为青蓝色 (Red=0, Green=0.5, Blue=0.5, Alpha=1)GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)mDrawData = DrawData().apply {initVertexBuffer()initShader()}}override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {// 当 Surface 尺寸发生变化时调用,例如设备的屏幕方向发生改变, 设置视口为新的尺寸,视口是指渲染区域的大小GLES30.glViewport(0, 0, width, height)mDrawData?.computeMVPMatrix(width.toFloat(), height.toFloat())}override fun onDrawFrame(gl: GL10?) {// 每一帧绘制时调用, 清除颜色缓冲区GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)mDrawData?.drawSomething()}
}

GLSurfaceView.Renderer需要的绘制数据

class DrawData {private var mProgram : Int = -1private var NO_OFFSET = 0private var VERTEX_POS_DATA_SIZE = 3// 最终变化矩阵private val mMVPMatrix = FloatArray(16)// 投影矩阵private val mProjectionMatrix = FloatArray(16)// 相机矩阵private val mViewMatrix = FloatArray(16)private var mViewPortRatio = 1f// 1. 准备顶点数据val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下)val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4) // 分配直接内存.order(ByteOrder.nativeOrder()) // 使用小端, 即低地址存放低位数据, 高地址存放高位数据.asFloatBuffer()// 2. 创建顶点缓冲区对象(Vertex Buffer Object, VBO), 并上传顶点数据到缓冲区对象中fun initVertexBuffer(){vertexBuffer.put(vertex) // 将顶点数据放入 FloatBuffervertexBuffer.position(0) // 在将数据放入缓冲区后,位置指针会指向缓冲区的末尾。重置位置指针为 0,使得在后续操作中可以从缓冲区的开始位置读取数据val vbo = IntArray(1)GLES30.glGenBuffers(1, vbo, 0) // 生成一个缓冲区对象ID,并存储在数组 vbo 中,存放位置为0GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]) // 绑定生成的顶点缓冲区对象,使其成为当前缓冲区操作的目标GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertex.size * 4, // 数据总字节数 = 顶点数 * Float占4字节vertexBuffer,GLES30.GL_STATIC_DRAW)}// 3. 初始化着色器程序fun initShader()  {val vertexShaderCode = """#version 300 eslayout (location = 0) in vec4 aPosition;uniform mat4 uMVPMatrix; // 新增投影矩阵void main() {gl_Position = uMVPMatrix * aPosition; // 应用投影变换}""".trimIndent()       // 顶点着色器代码val fragmentShaderCode = """#version 300 esprecision mediump float;uniform vec4 vColor;out vec4 fragColor;void main() {fragColor = vColor;}""".trimIndent()         // 片段着色器代码// 加载顶点着色器和片段着色器, 并创建着色器程序val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)val fragmentShader = LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)mProgram = GLES30.glCreateProgram()GLES30.glAttachShader(mProgram, vertexShader)GLES30.glAttachShader(mProgram, fragmentShader)GLES30.glLinkProgram(mProgram)GLES30.glUseProgram(mProgram)}// 4. 计算变换矩阵fun computeMVPMatrix(width: Float, height: Float) {// 正交投影矩阵takeIf { width > height }?.let {mViewPortRatio = width / heightMatrix.orthoM(mProjectionMatrix, // 透视投影矩阵NO_OFFSET, // 偏移量-mViewPortRatio, // 近平面的坐标系左边界mViewPortRatio, // 近平面的坐标系右边界-1f, // 近平面的坐标系的下边界1f, // 近平面坐标系的上边界0f, // 近平面距离相机距离1f // 远平面距离相机距离)} ?: run {mViewPortRatio = height / widthMatrix.orthoM(mProjectionMatrix, // 透视投影矩阵NO_OFFSET, // 偏移量-1f, // 近平面坐标系左边界1f, // 近平面坐标系右边界-mViewPortRatio, // 近平面坐标系下边界mViewPortRatio, // 近平面坐标系上边界0f, // 近平面距离相机距离1f // 远平面距离相机距离)}// 设置相机矩阵// 相机位置(0f, 0f, 1f)// 物体位置(0f, 0f, 0f)// 相机方向(0f, 1f, 0f)Matrix.setLookAtM(mViewMatrix, // 相机矩阵NO_OFFSET, // 偏移量0f, // 相机位置x0f, // 相机位置y1f, // 相机位置z0f, // 物体位置x0f, // 物体位置y0f, // 物体位置z0f, // 相机上方向x1f, // 相机上方向y0f // 相机上方向z)// 最终变化矩阵Matrix.multiplyMM(mMVPMatrix, // 最终变化矩阵NO_OFFSET, // 偏移量mProjectionMatrix, // 投影矩阵NO_OFFSET, // 投影矩阵偏移量mViewMatrix, // 相机矩阵NO_OFFSET // 相机矩阵偏移量)val matrixHandler = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")GLES30.glUniformMatrix4fv(matrixHandler, 1, false, mMVPMatrix, NO_OFFSET)}// 5. 使用着色器程序绘制图形fun drawSomething(){GLES30.glLineWidth(50.0f)// 获取顶点数据的位置, 并使用该位置的数据val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glVertexAttribPointer(positionHandle, VERTEX_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, 0)// 设置片段着色器的颜色val colorHandle = GLES30.glGetUniformLocation(mProgram, "vColor")GLES30.glUniform4f(colorHandle, 1.0f, 0.5f, 0.5f, 1.0f) // 红色// 绘制图形GLES30.glDrawArrays(GLES30.GL_POINTS, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)GLES30.glDisableVertexAttribArray(positionHandle)}
}object LoadShaderUtil{// 创建着色器对象fun loadShader(type: Int, source: String): Int {val shader = GLES30.glCreateShader(type)GLES30.glShaderSource(shader, source)GLES30.glCompileShader(shader)return shader}
}

绘制点、线、三角形、正方形、圆

绘制点GLES30.GL_POINTS

// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)GLES30.glDrawArrays(GLES30.GL_POINTS, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    在这里插入图片描述

绘制线

两个点绘制一条线间隔绘制GLES30.GL_LINES

  • 绘制顺序:将传入的坐标作为单独线条绘制,ABCDEFG六个顶点,绘制AB、CD、EF三条线
// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)
GLES30.glLineWidth(30f)
GLES30.glDrawArrays(GLES30.GL_LINES, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    在这里插入图片描述

两个点绘制一条线连续绘制GLES30.GL_LINE_STRIP

  • 绘制顺序:将传入的顶点作为折线绘制,ABCD四个顶点,绘制AB、BC、CD三条线
// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)
GLES30.glLineWidth(30f)
GLES30.glDrawArrays(GLES30.GL_LINE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    在这里插入图片描述

两个点绘制一条线循环绘制GLES30.GL_LINE_LOOP

  • 绘制顺序:将传入的顶点作为闭合折线绘制,ABCD四个顶点,绘制AB、BC、CD、DA四条线
// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)
GLES30.glLineWidth(30f)
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    在这里插入图片描述

绘制三角形

三个点绘制一条线间隔绘制GLES30.GL_TRIANGLES

  • 绘制顺序:将传入的顶点作为单独的三角形绘制,ABCDEF绘制ABC,DEF两个三角形
// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    -

绘制正方形

三个点绘制一条线连续绘制GLES30.GL_TRIANGLE_STRIP

  • 绘制顺序:将传入的顶点作为三角条带绘制,ABCDEF绘制ABC,BCD,CDE,DEF四个三角形
// 1. 准备顶点数据
val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, // 左上-0.5f, -0.5f, 0.0f, // 左下0.5f, 0.5f, 0.0f, // 右上0.5f, -0.5f, 0.0f, // 右下
)
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    -

绘制圆

三个点绘制一条线连续绘制GLES30.GL_TRIANGLE_FAN

  • 绘制顺序:将传入的顶点作为扇面绘制,ABCDEF绘制ABC、ACD、ADE、AEF四个三角形
// 1. 准备顶点数据
val vertex = run {val radius = 0.5fval segments = 36 // 分段数(越多越圆滑)val angleStep = (2 * PI / segments).toFloat()val vertices = mutableListOf<Float>()// 中心点vertices.add(0f)vertices.add(0f)vertices.add(0f)// 圆周上的点for (i in 0..segments) {val angle = i * angleStepvertices.add(radius * cos(angle))vertices.add(radius * sin(angle))vertices.add(0f)}vertices.toFloatArray()
}
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)
  • 效果图
    在这里插入图片描述

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

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

相关文章

threejs 安装教程

嗨&#xff0c;我是小路。今天主要和大家分享的主题是“threejs 安装教程”。 在当今的数字化时代&#xff0c;用户对视觉体验的要求越来越高。传统的2D网页已经无法满足所有需求&#xff0c;而三维&#xff08;3D&#xff09;图形技术则为前端开发者提供了新的方向。…

win11编译pytorch cuda128版本流程

Geforce 50xx系显卡最低支持cuda128&#xff0c;torch cu128 release版本目前还没有释放&#xff0c;所以自己基于2.6.0源码自己编译wheel包。 1. 前置条件 1. 使用visual studio installer 安装visual studio 2022&#xff0c;工作负荷选择【使用c的桌面开发】,安装完成后将…

如何安装Vm和centos

一、VMware 安装 &#xff08;一&#xff09;前期准备 下载 VMware 软件&#xff1a;首先&#xff0c;你需要从 VMware 官方网站下载适合你计算机操作系统版本的 VMware Workstation 软件安装包。确保选择的版本与你的主机操作系统兼容&#xff0c;例如&#xff0c;如果你的主…

OpenGL 04--GLSL、数据类型、Uniform、着色器类

一、着色器 在 OpenGL 中&#xff0c;着色器&#xff08;Shader&#xff09;是运行在 GPU 上的程序&#xff0c;用于处理图形渲染管线中的不同阶段。 这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说&#xff0c;着色器只是一种把输入转化为输出的程序。着色器…

服务器离线部署DeepSeek

目标 本次部署的目标是在本地服务器上部署DeepSeek。但是该服务不能连接外网&#xff0c;因此只能使用离线部署的方式。为了一次完成部署。现在云服务器上进行尝试。 云服务器部署尝试 云服务器配置 CentOS72080Ti 11GB 安装准备 1、上传iso并配置为本地yum源 安装前先将…

删除idea recent projects 记录

1、退出idea&#xff08;一定要全部退出idea&#xff0c;要不然删除后&#xff0c;idea一退出&#xff0c;又保存上了&#xff09; 2、进入 C:\Users\Administrator\AppData\Roaming\JetBrains\IntelliJIdea2024.1\options 目录 根据不同的版本号 IntelliJIdea2024.1 这个地方…

【MySql】EXPLAIN执行计划全解析:15个字段深度解读与调优指南

文章目录 一、执行计划核心字段总览二、关键字段深度拆解1. type&#xff08;访问类型&#xff09;——查询性能的晴雨表典型场景分析&#xff1a; 2. key_len&#xff08;索引使用长度&#xff09;——索引利用率的检测仪计算示例&#xff1a; 3. Extra&#xff08;附加信息&a…

如何实现一个 Spring Boot Starter

在 Spring Boot 中&#xff0c;Starter 是一种自动配置的模块&#xff0c;它封装了一些常用的功能&#xff0c;并通过 Spring Boot 的约定大于配置的原则&#xff0c;使开发者能够快速使用和集成相关功能。通常&#xff0c;Spring Boot Starter 包含了所需的依赖、配置、自动化…

使用python做http代理请求

有这样一个需求现在有两台A&#xff0c;B两台电脑组成了一个局域网&#xff0c;在A电脑上开发webjava应用&#xff0c;需要调用第三方接口做http请求&#xff0c;但是这个请求只能在B电脑上请求。 一种解决方案&#xff1a;自定义一个中间服务&#xff0c;在电脑B上运行一个简…

系统架构设计师考点——嵌入式技术

一、备考指南 嵌入式技术主要考查的是嵌入式基础知识、嵌入式设计等相关知识&#xff0c;在系统架构设计师的考试中选择题占2~4分&#xff0c;案例分析有时会考关键路径的技术问答&#xff0c;这个题目一般比较难&#xff0c;但是由于案例分析题是五题选三题&#xff0c;所以…

当AI重构认知:技术狂潮下的教育沉思录

备注&#xff1a;文章未Deepseek R1模型辅助生成&#xff0c;如有不妥请谅解。 以下使原文&#xff1a; 我有三个娃&#xff0c;各间隔4到5岁&#xff0c;经历过搜索引擎&#xff0c;短视频&#xff0c;短剧&#xff0c;本身曾经也是教育专业出生&#xff0c;任何事务都有两面性…

EasyExcel 实践案例:打印工资条

文章目录 &#x1f4a1; 1. 每个员工一个 Excel 文件✅ 占位符格式&#x1f4cc; Excel 模板&#x1f4cc; Java 代码&#x1f525; 关键点 &#x1f4a1; 2. 每个员工一个 Sheet✅ 占位符格式&#x1f4cc; Java 代码&#x1f525; 关键点 &#x1f4a1; 3. 一个 Sheet&#x…

编程题-从前序与中序遍历序列构造二叉树(中等-重点)

题目&#xff1a; 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 提示: preorder 和 inorder 均 无重复 元素 解法一&#xff08;递归&#xff0…

Vue 3 + Vite 项目配置访问地址到服务器某个文件夹的解决方案

前言 在开发 Vue 3 Vite 项目时&#xff0c;我们经常需要将项目部署到服务器的某个特定文件夹下。例如&#xff0c;将项目部署到 /my-folder/ 目录下&#xff0c;而不是服务器的根目录。这时&#xff0c;我们需要对 Vite 和 Vue Router 进行一些配置&#xff0c;以确保项目能…

【Rust中级教程】2.10. API设计原则之受约束性(constrained) Pt.1:对类型进行修改、`#[non_exhaustive]`注解

喜欢的话别忘了点赞、收藏加关注哦&#xff08;加关注即可阅读全文&#xff09;&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 2.10.1. 接口的更改要三思 如果你的接口要做出对用户可见的更改&#xff0c;那么一定要三思…

Imagination GPU 3D Graphics Wrokload

本次分享Imagination GPU 的3D 图像处理负载流程。 总的分为两个阶段 第一阶段&#xff1a;Geometry Processing Phase&#xff08;几何处理阶段&#xff09;是渲染管线中的一个关键环节&#xff0c;主要负责对三维几何数据进行处理和变换&#xff0c;以便后续在屏幕上进行显…

自动化设备对接MES系统找DeepSeek问方案

项目需要现场的PLC设备HTTP协议JSON格式的方式对接MES系统平台&#xff0c;于是试了一下&#xff1a; 找到的相关资源链接在这里。

VoIP之音频3A技术

音频3A技术是改善语音通话质量的三种关键技术的简称&#xff0c;包括声学回声消除&#xff08;Acoustic Echo Cancellation, AEC&#xff09;、自动增益控制&#xff08;Automatic Gain Control, AGC&#xff09;、自噪声抑制&#xff08;Automatic Noise Suppression, ANS&…

量子计算的数学基础:复数、矩阵和线性代数

量子计算是基于量子力学原理的一种新型计算模式,它与经典计算机在信息处理的方式上有着根本性的区别。在量子计算中,信息的最小单位是量子比特(qubit),而不是传统计算中的比特。量子比特的状态是通过量子力学中的数学工具来描述的,因此,理解量子计算的数学基础对于深入学…

京准电钟:NTP精密时钟服务器在自动化系统中的作用

京准电钟&#xff1a;NTP精密时钟服务器在自动化系统中的作用 京准电钟&#xff1a;NTP精密时钟服务器在自动化系统中的作用 NTP精密时钟服务器在自动化系统中的作用非常重要&#xff0c;特别是在需要高精度时间同步的场景中。NTP能够提供毫秒级的时间同步精度&#xff0c;这…