Android使用NDK OpenGL ES3.0绘制一个三角形
【
尊重原创,转载请注明出处
】
https://blog.csdn.net/guyuealian/article/details/82021607
网上已经有很多OpenCV的教程,不过大都是基于Java层调用openGL接口,若使用Java层openGL接口绘制三角形,还是比较简单的,但要是使用NDK C++ 实现,还是有点复杂。
本文将使用Android NDK开发,利用C++的 OpenGL ES3.0绘制一个三角形。绘制三角形的C/C++源码大部分是参考:《
OPENGL ES 3.0编程指南
》第二章的代码,但该书只有源码,没有工程项目,是用Android.mk配置,要做成Android Studio Demo还是要花点力气的。本博客的OpenGL的开发,其配置文件使用CMakeLists.txt,Android Studio 2.3以上NDK开发很容易啦,其配置方法使用CMakeLists.txt会比使用Android.mk更容易。
这里不具体分析绘制三角形的代码实现过程了,毕竟《
OPENGL ES 3.0编程指南
》这本书已经很详细啦。
本项目源码下载地址:
https://github.com/PanJinquan/openGL-Demo
,要是觉得不错,给个”
Star
“哈
开发环境:
-
(1)Android Studio 2.3.3 以上
-
(2)android-ndk-r10d 以上,下载地址:
https://developer.android.google.cn/ndk/downloads/index.html
1、新建项目:
新建Android工程一定要勾选“Include C++ support”,这样新建的Android工程会直接支持NDK开发,避免各种配置问题,如果提示没有NDK,请下载NDK,并在工程“Project Structure”中导入即可。
我的工程目录是这样的:
2、新建RendererJNI类
package opengl.panjq.com.opengl_demo;
import android.opengl.GLSurfaceView.Renderer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.util.Log;
public class RendererJNI implements GLSurfaceView.Renderer {
static {
System.loadLibrary("gltest-lib");
private AssetManager mAssetMgr = null;
private final String mLogTag = "ndk-build";
public native void glesInit();
public native void glesRender();
public native void glesResize(int width, int height);
public native void readShaderFile(AssetManager assetMgr);
public RendererJNI(Context context) {
mAssetMgr = context.getAssets();
if (null == mAssetMgr) {
Log.e(mLogTag, "getAssets() return null !");
* 当创建 GLSurfaceView时,系统调用这个方法.使用这个方法去执行只需要发生一次的动作,
* 例如设置OpenGL环境参数或者初始化OpenGL graphic 对象.
* @param gl
* @param config
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
readShaderFile(mAssetMgr);
glesInit();
* 当GLSurfaceView 几何学发生改变时系统调用这个方法.包括 GLSurfaceView 的大小发生改变或者横竖屏发生改变.
* 使用这个方法去响应GLSurfaceView 容器的改变
* @param gl
* @param width
* @param height
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glesResize(width, height);
* 执行渲染工作:当系统每一次重画 GLSurfaceView 时调用.使用这个方法去作为主要的绘制和重新绘制graphic 对象的执行点.
* @param gl
@Override
public void onDrawFrame(GL10 gl) {
glesRender();
3、修改MainActivity.java文件
package opengl.panjq.com.opengl_demo;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.app.ActivityManager;
import android.content.pm.ConfigurationInfo;
import android.util.Log;
import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;
public class MainActivity extends AppCompatActivity {
private final int CONTEXT_CLIENT_VERSION = 3;
private GLSurfaceView mGLSurfaceView;
RendererJNI mRenderer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
mRenderer=new RendererJNI(this);
if (detectOpenGLES30()) {
// 设置OpenGl ES的版本
mGLSurfaceView.setEGLContextClientVersion(CONTEXT_CLIENT_VERSION);
// 设置与当前GLSurfaceView绑定的Renderer
mGLSurfaceView.setRenderer(mRenderer);
// 设置渲染的模式
mGLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
} else {
Log.e("opengles30", "OpenGL ES 3.0 not supported on device. Exiting...");
finish();
setContentView(mGLSurfaceView);
@Override
protected void onResume() {
super.onResume();
mGLSurfaceView.onResume();
@Override
protected void onPause() {
super.onPause();
mGLSurfaceView.onPause();
private boolean detectOpenGLES30() {
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
return (info.reqGlEsVersion >= 0x30000);
4.新建C++ JNI文件
RendererJNI.h头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class opengl_panjq_com_opengl_demo_RendererJNI */
#ifndef _Included_opengl_panjq_com_opengl_demo_RendererJNI
#define _Included_opengl_panjq_com_opengl_demo_RendererJNI
#ifdef __cplusplus
extern "C" {
#endif
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesInit
* Signature: ()V
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesInit
(JNIEnv *, jobject);
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesRender
* Signature: ()V
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesRender
(JNIEnv *, jobject);
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesResize
* Signature: (II)V
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesResize
(JNIEnv *, jobject, jint, jint);
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_readShaderFile
(JNIEnv *env, jobject self, jobject assetManager);
#ifdef __cplusplus
#endif
#endif
RendererJNI.cpp源文件
这里提供一个方法char* readShaderSrcFile(char *shaderFile, AAssetManager *pAssetManager),用于获取assets资源文件*.glsl文件:
char *pVertexShader = readShaderSrcFile("shader/vs.glsl", g_pAssetManager);
char *pFragmentShader = readShaderSrcFile("shader/fs.glsl", g_pAssetManager);
当然,也可以写死在文件中,如:
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";
再用LoadShader加载:
vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
完整的代码如下
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "RendererJNI.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <GLES3/gl3.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
#define LOG_TAG "ndk-build"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
GLint g_programObject;
jint g_width;
jint g_height;
AAssetManager* g_pAssetManager = NULL;
char* readShaderSrcFile(char *shaderFile, AAssetManager *pAssetManager)
AAsset *pAsset = NULL;
char *pBuffer = NULL;
off_t size = -1;
int numByte = -1;
if (NULL == pAssetManager)
LOGE("pAssetManager is null!");
return NULL;
pAsset = AAssetManager_open(pAssetManager, shaderFile, AASSET_MODE_UNKNOWN);
//LOGI("after AAssetManager_open");
size = AAsset_getLength(pAsset);
LOGI("after AAssetManager_open");
pBuffer = (char *)malloc(size+1);
pBuffer[size] = '\0';
numByte = AAsset_read(pAsset, pBuffer, size);
LOGI("%s : [%s]", shaderFile, pBuffer);
AAsset_close(pAsset);
return pBuffer;
GLuint LoadShader ( GLenum type, const char *shaderSrc )
GLuint shader;
GLint compiled;
// Create the shader object
shader = glCreateShader ( type );
if ( shader == 0 )
return 0;
// Load the shader source
glShaderSource ( shader, 1, &shaderSrc, NULL );
// Compile the shader
glCompileShader ( shader );
// Check the compile status
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
if ( !compiled )
GLint infoLen = 0;
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
if ( infoLen > 1 )
char *infoLog = (char *)malloc ( sizeof ( char ) * infoLen );
glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
LOGE("Error compiling shader:[%s]", infoLog );
free ( infoLog );
glDeleteShader ( shader );
return 0;
return shader;
//*********************************************************************************
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesInit
(JNIEnv *pEnv, jobject obj){
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";
char *pVertexShader = readShaderSrcFile("shader/vs.glsl", g_pAssetManager);
char *pFragmentShader = readShaderSrcFile("shader/fs.glsl", g_pAssetManager);
GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;
// Load the vertex/fragment shaders
//vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
//fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
vertexShader = LoadShader ( GL_VERTEX_SHADER, pVertexShader );
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, pFragmentShader );
// Create the program object
programObject = glCreateProgram ( );
if ( programObject == 0 )
return;
glAttachShader ( programObject, vertexShader );
glAttachShader ( programObject, fragmentShader );
// Link the program
glLinkProgram ( programObject );
// Check the link status
glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
if ( !linked )
GLint infoLen = 0;
glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
if ( infoLen > 1 )
char *infoLog = (char *)malloc ( sizeof ( char ) * infoLen );
glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
LOGE("Error linking program:[%s]", infoLog );
free ( infoLog );
glDeleteProgram ( programObject );
return;
// Store the program object
g_programObject = programObject;
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesRender
* Signature: ()V
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesRender
(JNIEnv *pEnv, jobject obj){
GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
// Set the viewport
glViewport ( 0, 0, g_width, g_height );
// Clear the color buffer
glClear ( GL_COLOR_BUFFER_BIT );
// Use the program object
glUseProgram ( g_programObject );
// Load the vertex data
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
glEnableVertexAttribArray ( 0 );
glDrawArrays ( GL_TRIANGLES, 0, 3 );
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesResize
* Signature: (II)V
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesResize
(JNIEnv *pEnv, jobject obj, jint width, jint height){
g_width = width;
g_height = height;
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_readShaderFile
(JNIEnv *env, jobject self, jobject assetManager){
if (assetManager && env)
//LOGI("before AAssetManager_fromJava");
g_pAssetManager = AAssetManager_fromJava(env, assetManager);
//LOGI("after AAssetManager_fromJava");
if (NULL == g_pAssetManager)
LOGE("AAssetManager_fromJava() return null !");
LOGE("assetManager is null !");
5、修改CMakeLists.txt文件
OpenGL ES开发需要把OpenGL的相关依赖库导入进来,其方法很简单,直接在target_link_libraries中添加GLESv2 或者GLESv3都可以,由于需要在NDK使用AAssetManager操作asset资源,因此需要在target_link_libraries中,也把android添加进来,否则会出错:Error: undefined reference to 'AAssetManager_fromJava'。
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
include_directories(${CMAKE_SOURCE_DIR} src/main/cpp)
add_library( # Sets the name of the library.
gltest-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/RendererJNI.cpp )
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
gltest-lib
android # 错误:Error: undefined reference to 'AAssetManager_fromJava'
GLESv3 # 把opengl库文件添加进来,GLESv3
# Links the target library to the log library
# included in the NDK.
${log-lib} )
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
Run,Run,Run,效果图:
My OpenGL Playground
使用 NDK 编写 OpenGL ES 3.0
正在找工作啊,你们有工作给我吗~~~~redknot@126.com 有的话联系我啊~~~~
使用 DrawArrays 的方法,绘制三角形。并使用 Uniform 变量传递了一个 Float 变量,改变三角形大小。
使用 glDrawElements 绘制四面体,并着色
使用矩阵相乘的方法,将变换混合。
加入透视投影变换
纹理贴图,加入了 libpng 作为文件解析库。
调整环境光的亮度,让物体表面变得暗淡
调整环境光的颜色,让物体反射指定的光
Android OpenGLES 3.0 开发系统性学习教程
备注: 请使用 Android Studio 4.1+ ,NDK r21,其中一些 Case 的 3D 效果是通过手势触发(转动和缩放)
OpenGL ES 3.0 开发(08):坐标系统
OpenGL ES 3.0 开发(09):光照基础
OpenGL ES 3.0 开发(10):深度测试
OpenGL ES 3.0 开发(11):模板测试
OpenGL ES 3.0 开发(12):混合
OpenGL ES 3.0 开发(13):实例化(Instancing)
OpenGL ES 3.0 开发(14):粒子(Particles)
OpenGL ES 3.0 开发(15):立方体贴图(天空盒)
OpenGL ES 3.0 开发(16):相机预览
OpenGL ES 3.0 开发(17):相机基础滤镜
OpenGL
Android使用NDK OpenGL ES3.0绘制一个三角形
网上已经有很多OpenCV的教程,不过大都是基于Java层调用openGL接口,若使用Java层openGL接口绘制三角形,还是比较简单的,但要是使用NDK C++ 实现,还是有点复杂。
本文将使用Android NDK开发,利用C++的 OpenGL ES3.0绘制一个三角形。绘制三角形的C/C++源码大部分是参考:《OPENGL ES 3.0编程指南&nb
利用opengl进行yuv的渲染,主要原理利用显卡的加速运算,是把YUV转换成 RGBA ,然后交给gl渲染, 即opengl最终需要的数据还是 RGBA, 我们可以采用cpu软件jisua
编译Android平台上的freetype
https://www.cnblogs.com/freedreamnight/p/14930341.html这篇文章写的十分详细,要注意的是,他这里用的是静态库,我自己使用的是动态库,只需要删除–enable-static这个参数就行了。
集成freetype到项目中
在项目app/src/main/cpp,把头文件放入对应的目录,其实不用在意,.
1.1 OpenGL ES 3.0
OpenGL ES 3.0实现了具有可编程着色功能的图形管线,由两个规范组成:OpenGL ES 3.0 API规范和OpenGL ES着色语言3.0规范。
图1-1展示了OpenGL ES 3.0 图形管线。图中带有阴影的方框表示OpenGL ES 3.0中管线的可编程阶段。
图1-1 OpenGL ES 3.0 图形管线
1.1.1 顶点着色器
顶点着色器实现了顶点操作的通用可编程方法。
顶点着色器的输入包括:
1 着色器程序代码
2 顶点输入
3 统一.
打算一边学习一边整理学习笔记,我的开发环境是Android studio 2.1.3,不过有个问题是Android studio自带的模拟器只能支持es2.0
无法使用es3.0 所以3.0只能在真机上调试,手机必须是4.3或者是以上系统,我试过4.3的三星s3和 6
早就听过大名鼎鼎的 OpenGL,却迟迟没有实践学习,有些惭愧。今天开始通过实践+博文方式学习掌握 OpenGL。此文对于 OpenGL 的学习分为以下部分:
OpenGL 基础概念
OpenGL 坐标系理解
OpenGL 渲染管线
OpenGL 着色语言
OpenGL 基础概念
OpenGL
OpenGL 即 Open Graphics Library,是一个功能强大、调用方便的底层图形库...
OpenGL ES的基本流程和概念
这个系列我们一起对OpenGL ES进行重新学习实践,掌握OpenGL ES 3.0,编写迷人的OpenGL ES 3.0的程序。
下面开始今天的主题。
一、OpenGL ES的简介
OpenGL(Open Graphics Library)是一个跨平台图像程序接口,用于二维和三位图片的渲染。OpenGL ES(Open Graphic Library Embedded Systems)是OpenGL的一个子集,用
在前面几张中你已经看看到,着色器是OpenGL ES 3.0 API 的一个基础核心概念,每个OpenGL ES 3.0 程序都需要一个顶点着色器和一个片段着色器,以渲染有意义的图片,考虑到着色器是API概念的核心,我们希望确保你在深入了解图形API的更多细节之前,掌握编写着色器的基础知识
本章的目标是确保你理解着色器语言中的如下概念
变量和变量类型
向量和矩阵的构造选择
结构和数组
运算符,控制流和函数
输入/输出变量,统一变量,统一变量块和布局限定符
预处理器和指令
统一变量和插