亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android中的OpenGL使用配置詳解

 更新時(shí)間:2023年02月28日 16:33:28   作者:躬行之  
這篇文章主要為大家介紹了Android中的OpenGL使用配置詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

PS:雖然感覺(jué)好久沒(méi)更新了,但是輸入沒(méi)有停止,短暫的停止是為了以后更好的更新,共勉。

前面有關(guān) Android 音視頻的渲染都是使用MediaCodec進(jìn)行渲染,MediaCodec也有自己的弊端比如無(wú)法進(jìn)行視頻的編輯處理,而視頻可以 OpenGL ES來(lái)進(jìn)行渲染,可以很好進(jìn)行處理,比如添加濾鏡等,這里介紹下 Android 中 OpenGL,也就是 OpenGL  ES,它是免費(fèi)、跨平臺(tái)的、功能完善的 2D/3D 圖形庫(kù)接口 API,他針對(duì)多種嵌入式系統(tǒng)進(jìn)行了專門(mén)設(shè)計(jì),它是一個(gè)精心提取出來(lái)的 OpenGL 的子集,主要內(nèi)容如下:

  • 介紹
  • GLSurfaceView
  • 渲染器Renderer
  • 坐標(biāo)映射
  • 繪制三角形
  • 繪制效果

介紹

Android 可通過(guò)開(kāi)放圖形庫(kù) OpenGL ES 來(lái)支持高性能 2D 和 3D 圖形,OpenGL 是一種跨平臺(tái)的圖形 API,用于為 3D 圖形處理硬件指定標(biāo)準(zhǔn)的軟件接口。OpenGL ES 是 OpenGL 規(guī)范的一種形式,適用于嵌入式設(shè)備,Android 支持多版 OpenGL ES API,各版本情況如下:

  • OpenGL ES 1.0 和 1.1 - 此 API 規(guī)范受 Android 1.0 及更高版本的支持。
  • OpenGL ES 2.0 - 此 API 規(guī)范受 Android 2.2(API 級(jí)別 8)及更高版本的支持。
  • OpenGL ES 3.0 - 此 API 規(guī)范受 Android 4.3(API 級(jí)別 18)及更高版本的支持。
  • OpenGL ES 3.1 - 此 API 規(guī)范受 Android 5.0(API 級(jí)別 21)及更高版本的支持。

在 AndroidManifest.xml 中聲明 OpenGL ES 的版本

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

GLSurfaceView

GLSurfaceViewSurfaceViewOpenGL實(shí)現(xiàn),從 Android 1.5 開(kāi)始加入,在 SurfaceView的基礎(chǔ)上添加了 EGL 的管理以及自帶的渲染線程 GLThread,其主要功能如下:

  • 管理一個(gè)Surface,這個(gè)Surface是一塊特殊的內(nèi)存,可以組合到 Android 的 View 系統(tǒng)中,也就是可以和View一起使用。
  • 管理一個(gè) EGL,這個(gè)EGL可以讓 OpenGL 渲染到這個(gè)Surface上,EGL是 Android 與 OpenGL之間的橋梁。
  • 支持用戶自定義渲染器Renderer對(duì)象。
  • 使用專用線程上進(jìn)行渲染。
  • 支持按需渲染(on-demand)和連續(xù)渲染(continuous )。
  • Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls.

EGL 窗口、OpenGL 表面、GL 表面含義都相同。

GLSurfaceView常用設(shè)置如下:

EGL配置

EGLConfigChooser的默認(rèn)實(shí)現(xiàn)是SimpleEGLConfigChooser,默認(rèn)情況下GLSurfaceView將選擇深度緩沖深度至少為 16 位的PixelFormat.RGB_888格式的 surface,默認(rèn)的EGLConfigChooser實(shí)現(xiàn)是SimpleEGLConfigChooser,具體如下:

private class SimpleEGLConfigChooser extends ComponentSizeChooser {
    public SimpleEGLConfigChooser(boolean withDepthBuffer) {
        super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
    }
}

可以通過(guò)如下方式修改EGLConfig的默認(rèn)行為:

// 設(shè)置默認(rèn)EGLConfig的深度緩沖,true則為16位的深度緩沖
setEGLConfigChooser(boolean needDepth)
// 指定自定義的EGLConfigChooser
setEGLConfigChooser(android.opengl.GLSurfaceView.EGLConfigChooser configChooser)
// 指定各個(gè)分量的值
public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
            int alphaSize, int depthSize, int stencilSize)

渲染

通過(guò)setRenderer設(shè)置渲染器并啟動(dòng)渲染線程GLThread,渲染模式有兩種如下:

  • RENDERMODE_CONTINUOUSLY:適合重復(fù)渲染的場(chǎng)景,默認(rèn)的渲染模式。
  • RENDERMODE_WHEN_DIRTY:只有Surface被創(chuàng)建后渲染一次,只調(diào)用了requestRender才會(huì)繼續(xù)渲染。

渲染模式可以通過(guò)setRenderMode來(lái)進(jìn)行設(shè)置,具體如下:

// 設(shè)置渲染器
public void setRenderer(Renderer renderer)
// 設(shè)置渲染模式,僅在setRenderer之后調(diào)用生效
public void setRenderMode(int renderMode)

setDebugFlags和setGLWrapper

setDebugFlags用于設(shè)置 Debug 標(biāo)記,方便調(diào)試跟蹤代碼,可選值為DEBUG_CHECK_GL_ERRORDEBUG_LOG_GL_CALLS,setGLWrapper可以通過(guò)自定義GLWrapper來(lái)委托 GL 接口來(lái)添加一些自定義行為,具體如下:

// DEBUG_CHECK_GL_ERROR:每次GL調(diào)用都會(huì)檢查,如果出現(xiàn)glError則會(huì)拋出異常
// DEBUG_LOG_GL_CALLS:以TAG為GLSurfaceView將日志記錄在verbose級(jí)別的日志中
setDebugFlags(int debugFlags)
// 用于調(diào)試跟蹤代碼,可自定義GLWrapper包裝GL接口并返回GL接口,可在
setGLWrapper(android.opengl.GLSurfaceView.GLWrapper glWrapper)

渲染器Renderer

這部分在前面提到過(guò),這里單獨(dú)說(shuō)一下,要想在 GL 表面上執(zhí)行渲染操作,需要實(shí)現(xiàn)Renderer對(duì)象完成實(shí)際渲染操作,通過(guò)如下方式給GLSurfaceView設(shè)置渲染器對(duì)象Renderer以及制定渲染模式,如下:

// 給GLSurfaceView設(shè)置渲染器對(duì)象Renderer
public void setRenderer(Renderer renderer)
// 設(shè)置渲染模式,僅在setRenderer之后調(diào)用生效
public void setRenderMode(int renderMode)

設(shè)置渲染器Renderer的時(shí)候,同時(shí)會(huì)創(chuàng)建獨(dú)立線程GLThread并開(kāi)啟該線程,這個(gè)線程就是獨(dú)立于 UI 線程的渲染線程。

這里就涉及到兩個(gè)線程 UI 線程和渲染線程,自然涉及到線程之間的通信,可以使用 volatilesynchronized等實(shí)現(xiàn)線程之間的通信。

如果是在 UI 線程中調(diào)用渲染線程中的操作,可以使用GLSurfaceViewqueueEvent 方法來(lái)將該操作執(zhí)行到渲染線程中,一般需要自定義GLSurfaceView的時(shí)候會(huì)用到,同樣如果在渲染線程可以通過(guò)runOnUiThread來(lái)將與 UI 相關(guān)的操作執(zhí)行到 UI 線程。

下面看下渲染器Reander的基本實(shí)現(xiàn):

public class GLES20Renderer implements Renderer {
    private static final String TAG = GLES20Renderer.class.getSimpleName();
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.i(TAG, "onSurfaceCreated");
        GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1);
    }
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        Log.i(TAG, "onSurfaceChanged");
        GLES20.glViewport(0, 0, width, height);
    }
    public void onDrawFrame(GL10 gl) {
        Log.i(TAG, "onDrawFrame");
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    }
}

坐標(biāo)映射

先來(lái)了解下 OpenGL 的世界坐標(biāo)系和與之對(duì)應(yīng)的 Android 上的紋理坐標(biāo)系,如下圖所示:

在 Android 中使用 OpenGL 就要進(jìn)行相應(yīng)坐標(biāo)的轉(zhuǎn)換,下面看下 OpenGL 坐標(biāo)系在 Android 屏幕中的映射關(guān)系,如下圖所示:

如上圖所示,左側(cè)是默認(rèn)的 OpenGL 坐標(biāo)系,右側(cè)是 OpenGL 坐標(biāo)系在 Android 屏幕上的映射,可以明顯看到圖中的三角形是變形了的,為了保證圖像比例就需要應(yīng)用 OpenGL 投影模式和相機(jī)視圖來(lái)轉(zhuǎn)換坐標(biāo),這就涉及到投影矩陣和視圖矩陣,這部分內(nèi)容會(huì)在后續(xù)的文章中介紹。

繪制三角形

通過(guò)以上內(nèi)容,Android OpenGL 算是初步入門(mén)了,按照習(xí)慣來(lái)個(gè)小案例,這里使用 OpenGL 繪制一個(gè)三角形,如下Triangle是三角形數(shù)據(jù)封裝及著色器的的使用,后續(xù)渲染直接調(diào)用draw方法進(jìn)行渲染繪制,如下:

// Triangle
class Triangle(context: Context) {
    companion object {
        // 坐標(biāo)數(shù)組中每個(gè)頂點(diǎn)的坐標(biāo)數(shù)
        private const val COORDINATE_PER_VERTEX = 3
    }
    private var programHandle: Int = 0
    private var positionHandle: Int = 0
    private var colorHandler: Int = 0
    private var vPMatrixHandle: Int = 0
    private var vertexStride = COORDINATE_PER_VERTEX * 4
    // 三角形的三條邊
    private var triangleCoordinate = floatArrayOf(     // 逆時(shí)針的順序的三條邊
        0.0f, 0.5f, 0.0f,      // top
        -0.5f, -0.5f, 0.0f,    // bottom left
        0.5f, -0.5f, 0.0f      // bottom right
    )
    // 顏色數(shù)組
    private val color = floatArrayOf(0.63671875f, 0.76953125f, 0.22265625f, 1.0f)
    private var vertexBuffer: FloatBuffer =
        // (number of coordinate values * 4 bytes per float)
        ByteBuffer.allocateDirect(triangleCoordinate.size * 4).run {
            // ByteBuffer使用本機(jī)字節(jié)序
            this.order(ByteOrder.nativeOrder())
            // ByteBuffer to FloatBuffer
            this.asFloatBuffer().apply {
                put(triangleCoordinate)
                position(0)
            }
        }
    init {
        // read shader sourceCode
        val vertexShaderCode = GLUtil.readShaderSourceCodeFromRaw(context, R.raw.vertex_shader_triangle_default)
        val fragmentShaderCode =
            GLUtil.readShaderSourceCodeFromRaw(context, R.raw.fragment_shader_triangle)
        if (vertexShaderCode.isNullOrEmpty() || fragmentShaderCode.isNullOrEmpty()) {
            throw RuntimeException("vertexShaderCode or fragmentShaderCode is null or empty")
        }
        // compile shader
        val vertexShaderHandler = GLUtil.compileShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragmentShaderHandler =
            GLUtil.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)
        // create and link program
        programHandle = GLUtil.createAndLinkProgram(vertexShaderHandler, fragmentShaderHandler)
    }
    /**
 	 *  繪制方法
 	 */
    fun draw(mvpMatrix: FloatArray) {
        GLES20.glUseProgram(programHandle)
        // 獲取attribute變量的地址索引
        // get handle to vertex shader's vPosition member
        positionHandle = GLES20.glGetAttribLocation(programHandle, "vPosition").also {
            // enable vertex attribute,默認(rèn)是disable
            GLES20.glEnableVertexAttribArray(it)
            GLES20.glVertexAttribPointer(
                it, // 著色器中第一個(gè)頂點(diǎn)屬性的位置
                COORDINATE_PER_VERTEX,
                GLES20.GL_FLOAT,
                false,
                vertexStride, // 連續(xù)的頂點(diǎn)屬性組之間的間隔
                vertexBuffer
            )
        }
        // get handle to fragment shader's vColor member
        colorHandler = GLES20.glGetUniformLocation(programHandle, "vColor").also {
            GLES20.glUniform4fv(it, 1, color, 0)
        }
        // draw triangle
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, triangleCoordinate.size / COORDINATE_PER_VERTEX)
        GLES20.glDisableVertexAttribArray(positionHandle)
    }
}

渲染器實(shí)現(xiàn)如下:

// 渲染器實(shí)現(xiàn)
class MRenderer(private var context: Context) : GLSurfaceView.Renderer {
    private val tag = MRenderer::class.java.simpleName
    private lateinit var triangle: Triangle
    private val vPMatrix = FloatArray(16) // 模型視圖投影矩陣
    private val projectionMatrix = FloatArray(16)
    private val viewMatrix = FloatArray(16)
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
        // 創(chuàng)建Surface時(shí)調(diào)用,在渲染開(kāi)始時(shí)調(diào)用,用來(lái)創(chuàng)建渲染開(kāi)始時(shí)需要的資源
        Log.d(tag, "onSurfaceCreated")
        triangle = Triangle(context)
    }
    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        // Surface改變大小時(shí)調(diào)用,設(shè)置視口
        Log.d(tag, "onSurfaceChanged")
        GLES20.glViewport(0, 0, width, height)
    }
    override fun onDrawFrame(gl: GL10?) {
        // 繪制當(dāng)前frame,用于渲染處理具體的內(nèi)容
        Log.d(tag, "onDrawFrame")
        triangle.draw(vPMatrix)
    }
}

上面都是基本的繪制操作,沒(méi)啥好說(shuō)的,其中著色器的使用流程會(huì)在后續(xù)文章中進(jìn)行介紹,這里就不貼其他代碼了,感興趣的可以直接在文末查看源代碼。

繪制效果

上面的繪制沒(méi)有使用投影矩陣和相機(jī)視圖來(lái)進(jìn)行坐標(biāo)轉(zhuǎn)換,當(dāng)橫豎屏切換到時(shí)候會(huì)到導(dǎo)致變形,這個(gè)會(huì)在下篇文章中進(jìn)行修正,看下上述代碼繪制的效果圖,如下圖所示:

以上就是Android中的OpenGL使用配置詳解的詳細(xì)內(nèi)容,更多關(guān)于Android OpenGL配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android實(shí)現(xiàn)頂部懸浮效果

    Android實(shí)現(xiàn)頂部懸浮效果

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)頂部懸浮效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Android WebView實(shí)現(xiàn)文件下載功能

    Android WebView實(shí)現(xiàn)文件下載功能

    這篇文章主要為大家詳細(xì)介紹了Android WebView實(shí)現(xiàn)文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android不同版本兼容性適配方法教程

    Android不同版本兼容性適配方法教程

    這篇文章主要介紹了Android不同版本兼容性適配方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-11-11
  • Android開(kāi)發(fā)筆記 最好使用eclipse

    Android開(kāi)發(fā)筆記 最好使用eclipse

    值得注意一點(diǎn)的是,雖然Myeclipse比eclipse功能更強(qiáng)大,但是在具體的安卓開(kāi)發(fā)過(guò)程當(dāng)中,最好還是選用eclipse,sdk跟eclipse的兼容性更好
    2012-11-11
  • 分析Android中應(yīng)用的啟動(dòng)流程

    分析Android中應(yīng)用的啟動(dòng)流程

    不知道大家有沒(méi)有好奇過(guò)點(diǎn)擊Launcher圖標(biāo)時(shí),到喚起一個(gè)應(yīng)用頁(yè)面,這個(gè)流程會(huì)是怎么樣的?那這篇文章的目的就是盡可能梳理清楚流程,能夠讓大家對(duì)整個(gè)流程有一個(gè)相對(duì)清晰的認(rèn)知。下面跟著小編一起學(xué)習(xí)學(xué)習(xí)。
    2016-08-08
  • Android 桌面圖標(biāo)右上角顯示未讀消息數(shù)字

    Android 桌面圖標(biāo)右上角顯示未讀消息數(shù)字

    本文主要介紹了Android 桌面圖標(biāo)右上角顯示未讀消息數(shù)字的方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-04-04
  • Android中js和原生交互的示例代碼

    Android中js和原生交互的示例代碼

    本篇文章主要介紹了Android中js和原生交互的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • Android編程實(shí)現(xiàn)的自定義彈窗(PopupWindow)功能示例

    Android編程實(shí)現(xiàn)的自定義彈窗(PopupWindow)功能示例

    這篇文章主要介紹了Android編程實(shí)現(xiàn)的自定義彈窗(PopupWindow)功能,結(jié)合簡(jiǎn)單實(shí)例形式分析了Android自定義彈窗實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2017-03-03
  • android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼

    android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼

    下面小編就為大家分享一篇android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Flutter手機(jī)權(quán)限檢查與申請(qǐng)實(shí)現(xiàn)方法詳解

    Flutter手機(jī)權(quán)限檢查與申請(qǐng)實(shí)現(xiàn)方法詳解

    使用flutter進(jìn)行app開(kāi)發(fā),一定會(huì)用到手機(jī)的部分權(quán)限,包括通知推送、定位、相冊(cè)、存儲(chǔ)、相機(jī)、麥克風(fēng)等。而權(quán)限的檢查和獲取,最受歡迎的就是通過(guò)permission_handler這個(gè)插件來(lái)實(shí)現(xiàn)
    2022-11-11

最新評(píng)論