Android OpenGL ES 2.0入门实践

本文既然是入门实践,就先从简单的2D图形开始,首先,参考两篇官方文档搭建个框架,便于写OpenGL ES相关的代码:构建 OpenGL ES 环境OpenGL ES 2.0 及更高版本中的投影和相机视图

先上代码,代码效果如下图,屏幕上半部份是Java绘制的,下半部份是C++绘制的

一、投影和相机视图

1. 关于坐标轴方向

投影和相机视图主要是设置视点和坐标轴方向,请看下面的代码

Kotlin 复制代码
override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
    ...
    // Create a camera view matrix
    Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
}

Matrix.setLookAtM 方法的第5个参数 eyeZ 为正值,视点在屏幕前方,负值则在屏幕后方,其符号会影响X轴方向,其绝对值影响绘制元素的大小,绝对值越大,视点离屏幕越远,物体越小,倒数第2个参数 upY 的符号是影响Y轴方向,如果发现绘制的元素上下或者左右翻转了,可以调整这俩参数再看看效果。上面代码摘自官方文档,eyeZ 是负值,看网上教程的时候都说Y轴朝上,X朝右,刚开始写代码的时候发现X坐标总是反的,就是左右颠倒了,才回过头来修改这里的代码。

2. 关于图像拉伸

Kotlin 复制代码
override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
    GLES20.glViewport(0, 0, width, height)

    val ratio: Float = width.toFloat() / height.toFloat()

    // create a projection matrix from device screen geometry
    Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
}

上面代码摘自官方文档,Open GL默认是在一个正方形区域绘制,手机屏幕都是长方形(严格讲是GLSurfaceView的宽高比例),使用默认坐标画出来的图形,看起来被拉长了,使用 Matrix.frustumM 方法结合GLSurfaceView的宽高比,可以调整,使画出来的图形达到预期的效果。

二、绘制2D图形

绘制图形主要参考了一位大佬的系列文章OpenGL ES之六------绘制矩形和圆形,使得鄙人快速入门。

1. 绘制几何图形

OpenGL ES的基本图元是点、线、三角形,参考上面提到的那位大佬的文章,可轻松画出矩形和圆形,最近项目中需要画圆角矩形,鄙人就在此基础上拓展了一下,基本思路就是划分成9块(如下图),绘制矩形使用的索引法,各点的索引已经在图中标出,4个角使用画圆的方式绘制,不过只画四分之一的圆

按照上图,代码中绘制矩形使用的顶点索引如下

Kotlin 复制代码
private val indices = shortArrayOf(
        0, 1, 2, 0, 2, 3, //中间矩形
        4, 5, 1, 4, 1, 0,//左侧矩形
        1, 6, 7, 1, 7, 2,//底部矩形
        3, 2, 8, 3, 8, 9,//右侧矩形
        11, 0, 3, 11, 3, 10,//顶部矩形
    )

2. 绘制图片

OpenGL ES之十------纹理贴图(展示一张图片)

3. 绘制文本

思路就是将文字转成Bitmap,再使用纹理贴图的方式绘制,将纹理贴图的Bitmap的来源改为如下代码即可

Kotlin 复制代码
val bitmap = Bitmap.createBitmap(256, 128, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawColor(Color.TRANSPARENT)

val textPaint = Paint()
textPaint.textSize = 32f
textPaint.isAntiAlias = true
textPaint.color = color
canvas.drawText(text, 16f, 64f, textPaint)

三、使用NDK实现

1. 添加依赖

OpenGL ES属于是Android原生API了,只需要在CMakeLists.txt链接一下相关库即可,GLESv2即OpenGL ES 2.0的库,EGL用于分配和管理 OpenGL ES 上下文和 Surface,但不是必须的,jnigraphics是用来访问Java层的Bitmap的,纹理贴图会用到

复制代码
target_link_libraries(
        native-lib
        log
        GLESv2
        EGL
        jnigraphics
)

使用的头文件

cpp 复制代码
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <android/bitmap.h>

2. 将绘制挪到C++

NativeLib.kt

cpp 复制代码
class NativeLib {
    companion object {
        init {
            System.loadLibrary("native-lib");
        }
    }

    external fun onSurfaceCreated()
    external fun onSurfaceChanged(width:Int, height:Int)
    external fun onDrawFrame()
}

native-lib.cpp

cpp 复制代码
#include <jni.h>
#include <android/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h> //EGL用于分配和管理 OpenGL ES 上下文和 Surface
#include "my_gl_renderer.h"
#include "log_util.h"

extern "C"
JNIEXPORT void JNICALL
Java_site_feiyuliuxing_opengltest_nativelib_NativeLib_onSurfaceCreated(JNIEnv *env, jobject thiz) {
    //onSurfaceCreated
    __android_log_print(ANDROID_LOG_INFO, "NDK GLES", "%s", glGetString(GL_VERSION));
    LOG_I("##### %s", glGetString(GL_VERSION));
    on_surface_created();
}
extern "C"
JNIEXPORT void JNICALL
Java_site_feiyuliuxing_opengltest_nativelib_NativeLib_onSurfaceChanged(
        JNIEnv *env, jobject thiz, jint width, jint height) {
    // onSurfaceChanged
    on_surface_changed(width, height);
}
extern "C"
JNIEXPORT void JNICALL
Java_site_feiyuliuxing_opengltest_nativelib_NativeLib_onDrawFrame(JNIEnv *env, jobject thiz) {
    // onDrawFrame
    on_draw_frame();
}

NativeGLRenderer.kt

Kotlin 复制代码
class NativeGLRenderer : GLSurfaceView.Renderer {
    private val nativeLib = NativeLib()

    override fun onSurfaceCreated(p0: GL10?, p1: EGLConfig?) {
        nativeLib.onSurfaceCreated()
    }

    override fun onSurfaceChanged(p0: GL10?, width: Int, height: Int) {
        nativeLib.onSurfaceChanged(width, height)
    }

    override fun onDrawFrame(p0: GL10?) {
        nativeLib.onDrawFrame()
    }
}
相关推荐
来来走走6 小时前
Android开发(Kotlin) 协程
android·java·kotlin
河铃旅鹿7 小时前
Android开发-java版:Framgent
android·java·笔记·学习
2501_9160088911 小时前
手机抓包app大全:无需root的安卓抓包软件列表
android·ios·智能手机·小程序·uni-app·iphone·webview
百锦再11 小时前
第18章 高级特征
android·java·开发语言·后端·python·rust·django
gcygeeker12 小时前
安卓 4.4.2 电视盒子 ADB 设置应用开机自启动
android·adb·电视盒子
小驰行动派12 小时前
安卓上的极简番茄钟 | 开源
android·开源
jzlhll12312 小时前
android抽屉DrawerLayout在2025的沉浸式兼容
android
基哥的奋斗历程13 小时前
Kotlin_Flow_完整使用指南
android·开发语言·kotlin
j***827013 小时前
【玩转全栈】----Django连接MySQL
android·mysql·django
雨白14 小时前
深入理解 Android DocumentFile:性能陷阱与最佳实践
android