android studio搭建简单jni层的opengl开发框架

编程入门 行业动态 更新时间:2024-10-27 23:17:44

android studio搭建简单jni层的opengl开发<a href=https://www.elefans.com/category/jswz/34/1770644.html style=框架"/>

android studio搭建简单jni层的opengl开发框架

 

目录

1、上层的创建

2、jni层的配置

创建头文件ggl.h

jni函数接口 assetsManager jni层读取文件

utils 创建纹理,程序,连接程序工具类

scene.h 里实现真正的绘制,

glm库的导入

cmake中配置环境

app gradle 配置

着色器

demo下载


opengl学习了好久了,之前一直再java层开发,但随着对性能的要求,一些特效和编解码都需要再底层来实现,为了避免大量的java层和上层数据的传输浪费时间,就需要将所以的处理都放在底层,上层只有一些UI操作。

1、上层的创建

上层很简单,就是创建一个render 和 一个 glsurfaceview,然后将render 设置给glsurfaceview。

surfaceview

public class LammyGLSurfaceView extends GLSurfaceView {private LammyRenderer lammyRenderer;public LammyGLSurfaceView(Context context) {super(context);init();}public LammyGLSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);init();}private void  init(){lammyRenderer = new LammyRenderer();Native.InitAssetManager(getContext().getAssets());// 这里申请 2 版本环境,若想3 则需要在 jni层面去做setEGLContextClientVersion(2);setRenderer(lammyRenderer);}}

renderer

class LammyRenderer implements GLSurfaceView.Renderer {@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {
//        gl.glClearColor(0.1f , 0.4f,0.6f , 1f);Log.loge("onSurfaceCreated ...........");Native.InitOpenGL();}@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {
//        gl.glViewport(0,0,width ,height);Log.loge("onSurfaceChanged ...........");Native.OnViewportChanged((float)width ,(float) height);}@Overridepublic void onDrawFrame(GL10 gl) {
//        gl.glClear(gl.GL_COLOR_BUFFER_BIT);//      Log.loge("onDrawFrame ...........");Native.RenderOneFrame();}}

然后就是natvie类,实现jni接口的类

public class Native {static {System.loadLibrary("native-lib");}public static native void InitAssetManager(AssetManager am);public static native void InitOpenGL();public static native void OnViewportChanged(float width, float height);public static native void RenderOneFrame();}

2、jni层的配置

创建头文件ggl.h

包含opengl 和 一些要重用到的库和android log,这样每次只需要每次导入ggl.h,而不需要写一大堆导入库

ggl.h

#include <jni.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <string>
#include <sstream>
#include <vector>
#include <functional>
#include <map>
#include "glm/glm/glm.hpp"#define __DEBUG__ANDROID__ON
//write debug images
#ifdef  __DEBUG__ANDROID__ON
#include <android/log.h>
// Define the LOGI and others for print debug infomation like the log.i in java
#define LOG_TAG    "lammy-jni-log:"
//#undef LOG
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)
#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__)
#define LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__)
#endif

jni函数接口 assetsManager jni层读取文件


#include "ggl.h"
#include "scene.h"
#include "model.h"
AAssetManager* aAssetManager = nullptr;unsigned char * LoadFileContent(const char *path , int &filesSize){unsigned char * fileContent = nullptr;filesSize = 0 ;AAsset * asset = AAssetManager_open(aAssetManager, path , AASSET_MODE_UNKNOWN);if(asset== nullptr){LOGE("LoadFileContent asset is null, load shader error ");return  nullptr;}filesSize = AAsset_getLength(asset);fileContent = new unsigned char[filesSize];AAsset_read(asset , fileContent,filesSize);fileContent[filesSize]='\0';AAsset_close(asset);LOGE("LoadFileContent success ...%s",path);return fileContent;}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_lammy_openglstudy_Native_InitAssetManager(JNIEnv *env, jclass type, jobject am) {aAssetManager = AAssetManager_fromJava(env , am);
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_lammy_openglstudy_Native_InitOpenGL(JNIEnv *env, jclass type) {//    glClearColor(0.1 , 0.4,0.6 , 1);Init();//   InitModel(aAssetManager , "model/Cube.obj" );
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_lammy_openglstudy_Native_OnViewportChanged(JNIEnv *env, jclass type, jfloat width,jfloat height) {
//    glViewport(0,0,width ,height);SetViewPortSize(width ,height);}float GetFrameTime(){static unsigned  long long lastTime = 0,currentTime =0;timeval current;gettimeofday(&current , nullptr);// 将时间转化为毫秒currentTime = current.tv_sec * 1000 + current.tv_usec/1000;unsigned  long long frameTime = lastTime == 0?0:currentTime - lastTime;lastTime = currentTime;return float(frameTime)/1000.0f;
}extern "C"
JNIEXPORT void JNICALL
Java_com_example_lammy_openglstudy_Native_RenderOneFrame(JNIEnv *env, jclass type) {//    glClear(GL_COLOR_BUFFER_BIT);Draw();
}
InitAssetManager java层传入assetManager,再底层可以利用该对象读取 assets里的文件。利用LoadFileContent即可读取内容。如着色器,或者图片。下一篇会专门讲到读取文件的方法。

utils 创建纹理,程序,连接程序工具类

utils.h

#include "ggl.h"unsigned char * LoadFileContent(const char *path , int &fileSize);GLuint CompileShader(GLenum shaderType , const char * shaderCode);GLuint CreateProgram(GLuint vsShader , GLuint fsShader);GLuint CreateTextureFromBMP(const char * bmpPath);GLuint CreateTexture2D(unsigned char *pixelData, int Width, int height ,GLenum type);

utils.cpp

#include "utils.h"GLuint CompileShader(GLenum shaderType , const char * shaderCode){GLuint shader = glCreateShader(shaderType);glShaderSource(shader, 1 , &shaderCode, nullptr);//1 表示多少句代码,所有代码都放着。第三个表示如果多句代码,//则要与前面的代码的长度。glCompileShader(shader);GLint compileResult = GL_TRUE;// 查看编译状态glGetShaderiv(shader,GL_COMPILE_STATUS, &compileResult);if(compileResult == GL_FALSE){char szLog[1024] = {0};GLsizei  logLen = 0;// 存储日志长度glGetShaderInfoLog(shader , 1024 , &logLen , szLog);//1024 为日志的最大长度LOGE("compile error , log: %s" , szLog);LOGE("compile error ,shader %s" , shaderCode);glDeleteShader(shader);return  0;}return shader;}GLuint CreateProgram(GLuint vsShader , GLuint fsShader){GLuint program = glCreateProgram();glAttachShader(program, vsShader);glAttachShader(program, fsShader);glLinkProgram(program);glDetachShader(program, vsShader);glDetachShader(program, fsShader);GLint nResult;glGetProgramiv(program , GL_LINK_STATUS, &nResult);if(nResult == GL_FALSE){char log[1024] = {0};GLsizei  len = 0;// 存储日志长度glGetShaderInfoLog(program , 1024 , &len , log);//1024 为日志的最大长度LOGE("create program error , log: %s" , log);glDeleteProgram(program);return  0;}LOGE("create program success  " );return program;
}GLuint CreateTexture2D(unsigned char *pixelData, int width, int height ,GLenum type){GLuint texture;glGenTextures(1 , &texture);glBindTexture(GL_TEXTURE_2D, texture);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 表示图像放大时候,使用线性过滤glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// 表示图像缩小时候,使用线性过滤glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glTexImage2D(GL_TEXTURE_2D, 0 , type, width ,height, 0, type,GL_UNSIGNED_BYTE, pixelData);//GL_RGBAglBindTexture(GL_TEXTURE_2D, 0);return texture;
}unsigned  char* DecodeBMP(unsigned char * bmpFileData, int &width ,int &height){if(0x4D42 == *((unsigned short*)bmpFileData)){ // 数据头是否为0x4D42 判断是否是 24位的位图,// 读格式头int pixelDataOffset = * ((int *)(bmpFileData + 10));// 取出 像素数据在内存块的偏移地址width = *((int *)(bmpFileData + 18));height= *((int *)(bmpFileData + 22));unsigned char *pixelData = bmpFileData + pixelDataOffset;// 位图 像素数据 是 bgr排布的,所以 更换 r b的位置for(int i =0 ; i < width * height * 3 ; i += 3){unsigned char temp = pixelData[i];pixelData[i] = pixelData[i + 2];pixelData[i+2] = temp;}LOGE("DecodeBMP success " );return pixelData;}LOGE("DecodeBMP error " );return nullptr;
}GLuint CreateTextureFromBMP(const char * bmpPath){int nFileSize = 0;unsigned char *bmpFileContent = LoadFileContent(bmpPath, nFileSize);if(bmpFileContent==NULL){return 0;}int bmpWidth= 0,bmpHeight =0;unsigned char *pixelData = DecodeBMP(bmpFileContent,bmpWidth,bmpHeight);if(pixelData==NULL){delete[] bmpFileContent;LOGE("CreateTextureFromBMP error " );return 0;}GLuint texture = CreateTexture2D(pixelData, bmpWidth, bmpHeight,GL_RGB);delete [] bmpFileContent;LOGE("CreateTextureFromBMP success " );return texture;
}

scene.h 里实现真正的绘制,

这里绘制的是三角形。

//
// Created by zhangpeng30 on 2019/3/19.
//#include "scene.h"
#include "ggl.h"
#include "utils.h"
#include "glm/glm/gtc/matrix_transform.hpp"
#include "glm/glm/ext.hpp"
#include "glm/glm/detail/_noise.hpp"// 将数据从cpu放到 gpu
GLuint vbo, ebo;
GLuint program;
GLint positionLocation,modelMatrixLocation,viewMatrixLocation,projectMatrixLocation, colorLoction;
GLint texcoordLocation,textureLocation;
GLint texture;
// 不初始化就是单位矩阵
glm::mat4 modelMatrix ,viewMatrix, projectMatrix;
void Init(){float data[] = {-0.2f,-0.2f,0.0f , 1.0f,1.0f ,1.0f ,1.0f ,1.0f ,0.0f, 0.0f,0.2f, -0.2f ,0.0f , 1.0f,0.0f, 1.0f , 0.0f, 1.0f,1.0f,0.0f,0.0f, 0.2f , 0.0f , 1.0f, 1.0f, 0.0f , 0.0f, 1.0f,0.5f,1.0f};glGenBuffers(1, &vbo); // 1 表示需要一个vbo , 后面的vbo 指向显存块glBindBuffer(GL_ARRAY_BUFFER , vbo);//绑定显存地址glBufferData(GL_ARRAY_BUFFER, sizeof(float)*30 , data , GL_STATIC_DRAW);
//  最后一个参数,表示 放入显卡 不会修改 ,这里数据跑到显卡了glBindBuffer(GL_ARRAY_BUFFER,0);// 设置当前buffer为0 即解绑/**     利用element绘制 ebo来控制绘制点的顺序                        **/unsigned short indexes[] = {0, 1, 2};glGenBuffers(1, &ebo);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER , ebo);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*3, indexes,GL_STATIC_DRAW);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER , 0);int fileSize = 0;unsigned  char * shaderCode = LoadFileContent("test.vs",fileSize);GLuint vsShader = CompileShader(GL_VERTEX_SHADER,(char *)shaderCode);delete shaderCode;shaderCode = LoadFileContent("test.fs.glsl", fileSize);GLint fsShader = CompileShader(GL_FRAGMENT_SHADER , (char *)shaderCode);program = CreateProgram(vsShader , fsShader);glDeleteShader(vsShader);glDeleteShader(fsShader);// attribute 的插槽 和 uniform插槽 不一样,并且都是从0 开始的positionLocation = glGetAttribLocation(program, "position");colorLoction = glGetAttribLocation(program, "color");modelMatrixLocation = glGetUniformLocation(program , "ModelMatrix");viewMatrixLocation = glGetUniformLocation(program , "ViewMatrix");projectMatrixLocation = glGetUniformLocation(program , "ProjectionMatrix");textureLocation = glGetUniformLocation(program , "U_texture");texcoordLocation = glGetAttribLocation(program , "texcoord");glm::mat4 model;modelMatrix = glm::translate(model , glm::vec3(0.0f, 0.0f, -0.6f));texture = CreateTextureFromBMP("test2.bmp");
}
void SetViewPortSize(float width , float height){glViewport(0,0,width,height);// 参数分别为,视角,宽高比、最近看到的距离、最远看到的距离projectMatrix = glm::perspective(45.0f, width/height , 0.1f , 1000.0f);
}
void Draw(){glClearColor(0.1f,0.4f,0.6f,1.0f);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glUseProgram(program);glUniformMatrix4fv(modelMatrixLocation , 1 , GL_FALSE , glm::value_ptr(modelMatrix));glUniformMatrix4fv(viewMatrixLocation , 1 , GL_FALSE , glm::value_ptr(viewMatrix));glUniformMatrix4fv(projectMatrixLocation , 1 , GL_FALSE , glm::value_ptr(projectMatrix));glBindTexture(GL_TEXTURE_2D, texture);glUniform1i(textureLocation,0);glBindBuffer(GL_ARRAY_BUFFER, vbo);glEnableVertexAttribArray(positionLocation);glEnableVertexAttribArray(texcoordLocation);glEnableVertexAttribArray(colorLoction);// 参数说明: GL_FALSE 表示是否需要将数据映射到0-1,这里本来是浮点,不需要;//0 表示vbo 中数据的起始位置glVertexAttribPointer(positionLocation , 4 , GL_FLOAT , GL_FALSE , sizeof(float)*10, 0);glVertexAttribPointer(colorLoction , 4 , GL_FLOAT , GL_FALSE , sizeof(float)*10, (void *)(sizeof(float)*4));glVertexAttribPointer(texcoordLocation , 2 , GL_FLOAT , GL_FALSE , sizeof(float)*10, (void *)(sizeof(float)*8));//    glDrawArrays(GL_TRIANGLES, 0 , 3);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ebo);glDrawElements(GL_TRIANGLES , 3 , GL_UNSIGNED_SHORT, 0 );glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);glBindBuffer(GL_ARRAY_BUFFER, 0);glUseProgram(0);
}

vbo是存储定点信息,我们需要将定点数组从cpu 移到gpu显存。

ebo 是显卡上另外的一种插槽,是控制绘制定点顺序的。

glm库的导入

下载地址,导入时候只要将整个文件拷贝至cpp文件,注意在cmakelist文件中配置头文件路径

glm是数学库,用于处理矩阵的。需要注意的是矩阵是具有叠加性的。

如先平移 后旋转, 和先旋转后平移,得到的结果是不一样的。

cmake中配置环境

# For more information about using CMake with Android Studio, read the
# documentation: .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/cpp/glm)
include_directories(${CMAKE_SOURCE_DIR}/src/cpp/glm/glm)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/opengl.cppsrc/main/cpp/scene.cppsrc/main/cpp/utils.cppsrc/main/cpp/model.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.native-libGLESv1_CMGLESv2android# Links the target library to the log library# included in the NDK.${log-lib})

 

1、opengl 导入 GLESv1_CM、GLESv2、 

2、要用到assetmanager 所以导入android 

3、配置glm的头文件路径

 

node: 如果使用的是opengles 3.0版本,则需要导入GLESv3,否则就会报一些函数为定义的错误:

如调用:

glDrawBuffers(2,buffers);

报错:

undefined reference to `glDrawBuffers'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

app gradle 配置

主要是要加上 cpp文件以c++11 来编译这条

apply plugin: 'com.android.application'android {compileSdkVersion 27defaultConfig {applicationId "com.example.lammy.openglstudy"minSdkVersion 23targetSdkVersion 27versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"ndk{abiFilters 'armeabi-v7a'//,'arm64-v8a','armeabi'}externalNativeBuild {cmake {cppFlags "-std=c++11 -frtti -fexceptions "arguments "-DANDROID_TOOLCHAIN=gcc"arguments "-DANDROID_ABI=armeabi-v7a"arguments "-DCMAKE_BUILD_TYPE=Release"}}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}externalNativeBuild {cmake {path "CMakeLists.txt"}}
}dependencies {implementation fileTree(dir: 'libs', include: ['*.jar'])implementation 'com.android.support:appcompat-v7:27.1.1'implementation 'com.android.support.constraint:constraint-layout:1.1.3'testImplementation 'junit:junit:4.12'androidTestImplementation 'com.android.support.test:runner:1.0.2'androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

着色器

着色器是绘制的基础,这里给出2个简单的着色器

定点着色器

attribute vec4 position;
attribute vec4 color;
varying vec4 V_Color;// 模型视口
uniform mat4 ModelMatrix;uniform mat4 ViewMatrix;
uniform mat4 ProjectionMatrix;attribute vec2 texcoord;
varying vec2 V_Texcoord;/***
*   gpu 是有很多个核,因此计算每个点到屏幕的位置是 并行计算的
*/
void main(){V_Color = color;gl_Position = ProjectionMatrix*ViewMatrix*ModelMatrix*position;//V_Texcoord = texcoord;
}

fragment着色器

//#version 120
# ifdef GL_ES // 如果是es的环境
precision mediump float;
varying vec4 V_Color;
uniform sampler2D U_texture;
varying vec2 V_Texcoord;
#endif
/**
* 也是多个块 运算的 并行运算
*/
void main() {//    gl_FragColor= vec4(1.0, 1.0 , 0.0, 1.0);gl_FragColor= V_Color * texture2D(U_texture, V_Texcoord);
//    gl_FragColor=  texture2D(U_texture, V_Texcoord);
}

demo下载

这里给出demo,方便大家学习。demo的执行效果如下

更多推荐

android studio搭建简单jni层的opengl开发框架

本文发布于:2024-03-05 15:24:42,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1712668.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:框架   简单   studio   android   jni

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!