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.pswp.cn/web/70856.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/70856.shtml
英文地址,請注明出處:http://en.pswp.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;這…