NDK-第一个OpenGL示例
Posted itzyjr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NDK-第一个OpenGL示例相关的知识,希望对你有一定的参考价值。
代码结构如下:
一、Java层
LammyGLSurfaceView.java(用于展示渲染的OpenGL模型)
package com.example.lammy.openglstudy;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
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);// 设置OpenGL渲染器
}
}
LammyRender.java(定义OpenGL渲染器)
package com.example.lammy.openglstudy;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class LammyRenderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// gl.glClearColor(0.1f , 0.4f,0.6f , 1f);
Log.loge("onSurfaceCreated ...........");
Native.InitOpenGL();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// gl.glViewport(0,0,width ,height);
Log.loge("onSurfaceChanged ...........");
Native.OnViewportChanged((float)width ,(float) height);
}
@Override
public void onDrawFrame(GL10 gl) {
// gl.glClear(gl.GL_COLOR_BUFFER_BIT);
// Log.loge("onDrawFrame ...........");
Native.RenderOneFrame();
}
}
Log.java(打印日志)
package com.example.lammy.openglstudy;
public class Log{
public static void loge(String s){
android.util.Log.e("lammy-java-log:" , s );
}
}
MainActivity.java(主入口程序)
package com.example.lammy.openglstudy;
import android.os.Bundle;
import android.os.Environment;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private LammyGLSurfaceView lammyGLSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lammyGLSurfaceView = new LammyGLSurfaceView(this);
setContentView(lammyGLSurfaceView);
Log.loge(Environment.getExternalStorageState());
}
}
Native.java(加载本地库并声明要调用的C函数)
package com.example.lammy.openglstudy;
import android.content.res.AssetManager;
public class Native {
static {
System.loadLibrary("native-lib");// 注意名称与CMakeLists.txt中一致
}
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();
}
二、C++层
导入GLM库(glm是数学库,用于处理矩阵):https://sourceforge.net/projects/ogl-math/
导入时候只要将整个文件拷贝至cpp文件。要注意在CMakeLists.txt文件中配置头文件路径。
ggl.h(打印日志)
#ifndef OPENGLSTUDY_GGL_H
#define OPENGLSTUDY_GGL_H
#endif
#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:"
#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
opengl.cpp(通过AAssetManager指针从JNI层读取文件)
#include "ggl.h"
#include "scene.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(¤t, 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();
}
scene.h(绘制场景头文件)
#ifndef OPENGLSTUDY_SCENE_H
#define OPENGLSTUDY_SCENE_H
#endif
#include "ggl.h"
void Init();// 初始化OpenGL数据
void SetViewPortSize(float width , float height);// 设置视口并更新透视矩阵
void Draw();// 完成绘制
scene.cpp(实现真正的场景绘制)
#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;
// 从assets目录加载顶点着色器代码
unsigned char *shaderCode = LoadFileContent("test.vs", fileSize);
GLuint vsShader = CompileShader(GL_VERTEX_SHADER, (char *) shaderCode);
delete shaderCode;
// 从assets目录加载片段着色器代码
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);
}
utils.h(完成创建纹理,程序,连接程序工具类)
#ifndef OPENGLSTUDY_UTILS_H
#define OPENGLSTUDY_UTILS_H
#endif
#include "ggl.h"
unsigned char * LoadFileContent(const char *path , int &fileSize);
GLuint CompileShader(GLenum shaderType , const char * shaderCode)我的OpenGL学习进阶之旅NDK开发中find_library查找的系统动态库在哪里?
NDK OpenGL 未定义对 glVertexPointer 的引用
Android 逆向Android 进程注入工具开发 ( Visual Studio 开发 Android NDK 应用 | Visual Studio 中 SDK 和 NDK 安装位置 )(代码片段
我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情