OpenGL ES繪制3D圖形以及設置視口

文章目錄

    • 關于 glDrawElements
      • 基本概念
      • 使用場景
      • mode 繪制模式
      • type 索引數據類型
      • indices 索引緩沖區
      • 工作原理
      • 繪制正方體實例
    • 視口
      • 透視投影(Perspective Projection)
      • 正交投影(Orthographic Projection)
      • 正交投影和透視投影對比

關于 glDrawElements

基本概念

glDrawElements 是 OpenGL 中用于渲染圖元的核心函數之一,它允許你使用索引緩沖區(Index Buffer)來指定頂點的繪制順序,從而實現高效的渲染。這個函數在處理需要重復使用頂點數據的場景時特別有用,比如 3D 模型渲染。

使用場景

  • 渲染包含大量重復頂點的復雜模型(如立方體、地形網格)。
  • 共享頂點屬性(如位置、法線、紋理坐標)。
void glDrawElements(int mode,           // 繪制模式(如 GL_TRIANGLES、GL_LINES)int count,          // 索引數量int type,           // 索引數據類型(如 GL_UNSIGNED_SHORT)java.nio.Buffer indices  // 索引緩沖區
);

mode 繪制模式

模式描述
GL_POINTS將每個頂點作為一個點繪制。
GL_LINES將頂點兩兩連接為線段(v0-v1, v2-v3, …)。
GL_LINE_STRIP連接所有頂點為連續線段(v0-v1-v2-…)。
GL_LINE_LOOP連接所有頂點為閉合線段(最后一個點連回第一個點)。
GL_TRIANGLES將頂點每三個一組構成三角形(v0-v1-v2, v3-v4-v5, …)。
GL_TRIANGLE_STRIP相鄰三個頂點構成三角形(v0-v1-v2, v1-v2-v3, …)。
GL_TRIANGLE_FAN以第一個頂點為中心,與后續相鄰頂點構成扇形三角形(v0-v1-v2, v0-v2-v3, …)。

count 索引數量

需要繪制的索引總數。例如,渲染一個立方體需要 36 個索引(12 個三角形 × 3 個頂點)。

type 索引數據類型

類型描述
GL_UNSIGNED_BYTE8 位無符號整數(范圍:0~255)。
GL_UNSIGNED_SHORT16 位無符號整數(范圍:0~65535)。
GL_UNSIGNED_INT32 位無符號整數(范圍:0~4294967295)。
頂點數 ≤ 255:使用 GL_UNSIGNED_BYTE。
頂點數 ≤ 65535:使用 GL_UNSIGNED_SHORT(最常用)。
頂點數 > 65535:使用 GL_UNSIGNED_INT(需 OpenGL ES 3.0+)

indices 索引緩沖區

存儲頂點索引的緩沖區對象(如 java.nio.Buffer)。索引值對應頂點數組中的位置。

工作原理

  • 頂點數組:定義所有頂點的屬性(如位置、顏色)。
  • 索引數組:指定頂點的繪制順序。
  • glDrawElements:根據索引從頂點數組中提取頂點,并按指定模式繪制。

繪制正方體實例

先看效果
在這里插入圖片描述
先上全部代碼

package com.e.openglimport android.opengl.GLSurfaceView
import android.opengl.GLU
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10class CubeRenderer : GLSurfaceView.Renderer {private val vertexBuffer: FloatBufferprivate val indexBuffer: ShortBufferprivate val colorBuffer: FloatBuffer// 正方體的8個頂點坐標private val vertices = floatArrayOf(-0.5f, -0.5f, -0.5f,  // 左下后 V00.5f, -0.5f, -0.5f,  // 右下后 V10.5f, 0.5f, -0.5f,  // 右上后 V2-0.5f, 0.5f, -0.5f,  // 左上后 V3-0.5f, -0.5f, 0.5f,  // 左下前 V40.5f, -0.5f, 0.5f,  // 右下前 V50.5f, 0.5f, 0.5f,  // 右上前 V6-0.5f, 0.5f, 0.5f // 左上前 V7)// 正方體12個三角形的頂點索引(兩個三角形組成一個面)private val indices = shortArrayOf(0, 1, 2, 0, 2, 3,  // 后面1, 5, 6, 1, 6, 2,  // 右面5, 4, 7, 5, 7, 6,  // 前面4, 0, 3, 4, 3, 7,  // 左面3, 2, 6, 3, 6, 7,  // 上面4, 5, 1, 4, 1, 0 // 下面)// 每個頂點的顏色(RGBA)private val colors = floatArrayOf(0.0f, 0.0f, 0.0f, 1.0f,  // V0黑色1.0f, 0.0f, 0.0f, 1.0f,  // V1紅色1.0f, 1.0f, 0.0f, 1.0f,  // V2黃色0.0f, 1.0f, 0.0f, 1.0f,  // V3綠色0.0f, 0.0f, 1.0f, 1.0f,  // V4藍色1.0f, 0.0f, 1.0f, 1.0f,  // V5紫色1.0f, 1.0f, 1.0f, 1.0f,  // V6白色0.0f, 1.0f, 1.0f, 1.0f // V7青色)private var angleX = 0fprivate var angleY = 0finit {// 初始化頂點緩沖區val vbb = ByteBuffer.allocateDirect(vertices.size * 4)vbb.order(ByteOrder.nativeOrder())vertexBuffer = vbb.asFloatBuffer()vertexBuffer.put(vertices)vertexBuffer.position(0)// 初始化索引緩沖區val ibb = ByteBuffer.allocateDirect(indices.size * 2)ibb.order(ByteOrder.nativeOrder())indexBuffer = ibb.asShortBuffer()indexBuffer.put(indices)indexBuffer.position(0)// 初始化顏色緩沖區val cbb = ByteBuffer.allocateDirect(colors.size * 4)cbb.order(ByteOrder.nativeOrder())colorBuffer = cbb.asFloatBuffer()colorBuffer.put(colors)colorBuffer.position(0)}override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {// 設置清屏顏色為灰色gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f)// 啟用深度測試gl.glEnable(GL10.GL_DEPTH_TEST)// 啟用頂點和顏色數組gl.glEnableClientState(GL10.GL_VERTEX_ARRAY)gl.glEnableClientState(GL10.GL_COLOR_ARRAY)}override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {// 設置視口大小gl.glViewport(0, 0, width, height)// 設置投影矩陣gl.glMatrixMode(GL10.GL_PROJECTION)gl.glLoadIdentity()// 設置透視投影val aspectRatio = width.toFloat() / heightGLU.gluPerspective(gl, 45.0f, aspectRatio, 0.1f, 1000.0f)// 設置模型視圖矩陣gl.glMatrixMode(GL10.GL_MODELVIEW)gl.glLoadIdentity()}override fun onDrawFrame(gl: GL10) {// 清除顏色和深度緩沖區gl.glClear(GL10.GL_COLOR_BUFFER_BIT or GL10.GL_DEPTH_BUFFER_BIT)// 設置模型視圖矩陣gl.glLoadIdentity()gl.glTranslatef(0.0f, 0.0f, -5.0f) // 將正方體移到屏幕中央前方// 旋轉正方體angleX += 1.0fangleY += 0.5fgl.glRotatef(angleX, 1.0f, 0.0f, 0.0f) // 繞X軸旋轉gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f) // 繞Y軸旋轉// 設置頂點和顏色指針gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer)gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer)// 使用 glDrawElements 繪制正方體gl.glDrawElements(GL10.GL_TRIANGLES, indices.size,GL10.GL_UNSIGNED_SHORT, indexBuffer)}
}

代碼中都有標注,核心代碼在 onDrawFrame 中,最后一行通過
gl.glDrawElements( GL10.GL_TRIANGLES, indices.size,GL10.GL_UNSIGNED_SHORT, indexBuffer)

讀取頂點數據等信息,繪制正方體。

注意:    
創建Buffer時,vbb.order(ByteOrder.nativeOrder()) 一般得加上。
它是 Java NIO 緩沖區操作中的關鍵步驟,用于設置字節序(Byte Order),確保數據在內存中的存儲方式與設備硬件一致。不添加這行有時候你會發現繪制的沒啥錯,就是不顯示圖像!!!

視口

透視投影(Perspective Projection)

基本概念
模擬人眼視覺:遠處物體看起來更小,產生 "近大遠小" 的效果。
視錐體(Frustum):由近平面、遠平面和四個側面組成的截頭四棱錐,只有視錐體內的物體可見。
// 方法 1:使用 glFrustumf
glFrustumf(left, right, bottom, top, near, far);// 方法 2:使用 GLU.gluPerspective 內部也是使用 glFrustumf 來實現
GLU.gluPerspective(fovy, aspect, zNear, zFar);
fovy(視野角度):角度越大,視野越寬廣(類似廣角鏡頭);角度越小,視野越狹窄(類似長焦鏡頭)。
aspect(寬高比):需與視口寬高比匹配,否則會導致圖像拉伸。
near 和 far:影響深度精度和可見距離,比值過大會導致深度沖突(Z-Fighting)

修改上面的代碼,使用循環多繪制一些正方體

   override fun onDrawFrame(gl: GL10) {// 清除顏色和深度緩沖區gl.glClear(GL10.GL_COLOR_BUFFER_BIT or GL10.GL_DEPTH_BUFFER_BIT)// 旋轉正方體angleX += 1.0fangleY += 0.5f// 設置頂點和顏色指針gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer)gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer)for (i in 0..10) {// 使用 glDrawElements 繪制正方體// 設置模型視圖矩陣gl.glLoadIdentity()gl.glTranslatef(0.0f, -1f, -(5.0f * i.toFloat())) // 修改平移距離使繪制看起來遠近的效果gl.glRotatef(angleX, 1.0f, 0.0f, 0.0f) // 繞X軸旋轉gl.glRotatef(angleY, 0.0f, 1.0f, 0.0f) // 繞Y軸旋轉gl.glDrawElements(GL10.GL_TRIANGLES, indices.size,GL10.GL_UNSIGNED_SHORT, indexBuffer)}}

效果如下圖,有一種越遠越小的感覺。

在這里插入圖片描述

正交投影(Orthographic Projection)

基本概念
平行投影:光線從無限遠處平行照射物體,物體大小與距離無關。
保持比例:物體的真實尺寸和角度在投影后保持不變,平行線投影后仍平行。
// 方法 1:3D 正交投影(OpenGL ES 1.x/2.0)
void glOrthof(float left, float right, float bottom, float top, float near, float far);// 方法 2:2D 正交投影(OpenGL ES 1.x,簡化版)
void GLU.gluOrtho2D(float left, float right, float bottom, float top);

將上面透視投影的方法換成正交投影,同樣繪制多個正方體。

override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {// 設置視口大小gl.glViewport(0, 0, width, height)// 設置投影矩陣gl.glMatrixMode(GL10.GL_PROJECTION)gl.glLoadIdentity()// 設置透視投影val aspectRatio = width.toFloat() / height// GLU.gluPerspective(gl, 45.0f, aspectRatio, 0.1f, 1000.0f)// 正交投影GLU.gluOrtho2D(gl, -5F, 5F, -5F, 5F)// 設置模型視圖矩陣gl.glMatrixMode(GL10.GL_MODELVIEW)gl.glLoadIdentity()}

效果圖如下,只能看到最前面的一個正方體

在這里插入圖片描述

正交投影和透視投影對比

特性正交投影透視投影
特性正交投影透視投影
視覺效果無近大遠小,深度感弱近大遠小,深度感強
投影矩陣線性變換(僅縮放和平移)非線性變換(包含除法)
深度精度均勻分布近平面精度高,遠平面精度低
物體大小與距離無關隨距離增加而減小
適用場景2D 游戲、UI、地圖、CAD3D 游戲、VR、真實感渲染

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/83448.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/83448.shtml
英文地址,請注明出處:http://en.pswp.cn/web/83448.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【SAS求解多元回歸方程】REG多元回歸分析-多元一次回歸

多元一次回歸是一種統計方法,用于分析多個自變量(解釋變量)與一個因變量(響應變量)之間的線性關系。 目錄 【示例】 基本語法 SAS代碼 參數估計 方差分析 回歸統計量 y的擬合診斷 y的回歸變量值 【示例】 設Y…

卡通幼兒園教育通用可愛PPT模版分享

幼兒園教育通用PPT模版,教育教學PPT模版,卡通教育PPT模版,可愛卡通教學課件PPT模版,小清新動物卡通通用PPT模版,教學說課通用PPT模版,開學季PPT模版,國學頌歌PPT模版,可愛簡約風PPT模…

力扣HOT100之技巧:75. 顏色分類

這道題實際上就是讓我們不用sort()函數來實現對原數組的排序,這里我直接使用快速排序對原數組進行排序了,也是復習一下基于快慢指針的快速排序寫法。面試手撕快排的思路參考這個視頻。 用時擊敗100%,還行。下面直接貼代碼。 class Solution …

離線部署openstack 2024.1 keystone

控制節點身份服務 離線下載 apt-get install --download-only keystone python3-openstackclient apache2 libapache2-mod-wsgi-py3mkdir /controller/keystone mv /var/cache/apt/archives/*.deb /controller/keystone/ dpkg -i /controller/keystone/*.deb在一個控制節點操…

帆軟 BI 從入門到實戰全攻略(一):安裝激活與添加數據

一、帆軟 BI 產品概述? 在當今大數據時代,數據分析與可視化成為企業洞察業務、驅動決策的關鍵利器。帆軟軟件有限公司作為中國專業的大數據 BI 和分析平臺提供商,自 2006 年成立以來,憑借其在商業智能和數據分析領域的深耕細作,…

網絡協議通俗易懂詳解指南

目錄 1. 什么是網絡協議? 1.1 協議的本質 1.2 為什么需要協議? 1.3 協議分層的概念 2. TCP協議詳解 - 可靠的信使 ?? 2.1 TCP是什么? 2.2 TCP的核心特性 ?? 面向連接 ??? 可靠傳輸 ?? 流量控制 2.3 TCP三次握手 - 建立連接 2.4 TCP四次揮手 - 斷開連接…

量子加速器切入 AI 底層架構!能源焦慮時代,ORCA 正在改寫數據中心的計算邏輯

內容來源:量子前哨(ID:Qforepost) 文丨浪味仙 排版丨浪味仙 行業動向:2000字丨5分鐘閱讀 人工智能的飛速發展,令計算需求呈現爆炸式增長,也催生出專為 AI 設計的新型計算基礎設施形態——AI…

< 買了個麻煩 (二) 618 京東云--輕量服務器 > “可以為您申請全額退訂呢。“ 工單記錄:可以“全額退款“

事情進展是這樣的: 海外接聽 一分鐘 1-2 元,具體多少要問聯通。 這幾天接電話,有點兒心煩,看見來自 010-86310548 以為是 ICP 備案,結果接起來全是 VPS (輕量應用服務器)這個工單,就…

接口限頻算法:漏桶算法、令牌桶算法、滑動窗口算法

文章目錄 限頻三大算法對比與選型建議一、漏桶算法(Leaky Bucket Algorithm)1.核心原理2.實現3.為什么要限制漏桶容量4.優缺點分析 二、令牌桶算法(Token Bucket Algorithm)1.核心原理2.實現(1)單機實現&am…

HTML5 盒子模型

1. 盒子模型的概念 2. 邊框(border) 邊框顏色(border-color) 邊框粗細(border-width) 邊框樣式(border-style) border簡寫(border:) 3. 外邊距&am…

【Linux】Linux高級I/O

參考博客:https://blog.csdn.net/sjsjnsjnn/article/details/128345976 一、五種IO模型 阻塞式I/O非阻塞式I/OI/O復用(多路轉接)信號驅動式I/O異步I/O I/O我們并不陌生,簡單的說就是輸入輸出;對于一個輸入操作通常包…

關于界面存在AB測試后UI刷新空白的問題

問題描述: 在同一頁面存在AB面,A和B同時都有一個rv,然后A面的rv填充不了數據,B面的可以。 問題解決: header_task布局里的include_new_gift_sign里有一個和外層一樣id的recyclerview include的標簽的作用是。在infl…

Go 協程(Goroutine)入門與基礎使用

一、什么是協程(Goroutine)? 簡單來說,協程是由 Go 語言運行時管理的輕量級線程。相比系統線程,它的調度開銷極小,內存占用非常少(默認只需 2KB 棧空間)。 你可以在一個程序中輕松…

matlab 各種智能優化算法

1. 優化算法相關 蟻群優化算法(ACO) 蟻群優化算法是一種模擬螞蟻覓食行為的優化技術。以下是一個簡化版的ACO用于解決旅行商問題(TSP)的MATLAB代碼: function [bestRoute, minDist] acoTsp(distMatrix, numAnts, n…

Hilt -> Android 專屬依賴注入(DI)框架

Hilt 是 Google 基于 Dagger 封裝的 Android 專屬依賴注入(DI)框架,顯著簡化了依賴管理流程,提升代碼可維護性和可測試性。以下是核心要點及使用指南: dagger2: Dagger 2 原理和使用-CSDN博客 Hilt vs Dagger2&…

AISHELL-5 全球首套智能駕艙中文語音交互數據集開源

隨著汽車成為人們日常生活中不可或缺的一部分,而駕駛艙中傳統的觸摸交互方式容易分散駕駛員的注意力,存在安全風險,因此,車內基于語音的交互方式得到重視。與通常家庭或會議場景中的語音識別系統不同,駕駛場景中的系統…

openstack之neutron(一)

NFV基礎 neutron是對二層物理網絡的抽象與管理,實例的網絡功能由連接到vSwitch的端口上的vNIC共同實現,再通過物理服務器的物理網卡訪問外部的物理網絡。 NFV實現 網卡虛擬化:tap、tun、veth; 交換機虛擬化:linuxbri…

【Java】Arrays.sort:TimSort

一,概述 書接前文【Java】Arrays.sort:DualPivotQuicksort-CSDN博客 Arrays.sort對基本數據類型使用了雙軸快速排序,但是對Object[]類型,則使用了TimSort,TimSort是穩定的排序,它整合了插入排序歸并排序,…

一個n8n構建的能和LLM對話的Agent

一個n8n構建的能和LLM對話的Agent 1.OLLAMA1.1.下載和安裝1.2.設置環境變量1.3.重啟ollama1.4.測試1.5.拉取模型2.n8n部署2.1. 鏡像拉取和啟動2.2.注冊和登錄2.3.新建一個工作流3.說在后面的話環境搭建說明: windows(RTX 5090)+VM CENTOS 采用本地化的ollama運行LLM n8n是一…

升級 Ubuntu Linux 內核的幾種不同方法

方法 1 - 使用 dpkg 升級 Linux 內核(手動方式) 這個方法可以幫助你從 kernel.ubuntu.com 網站手動下載可用的最新 Linux 內核。如果你打算安裝最新版(而不是穩定版或者正式發布版),那這種方法…