系列文章目录
通俗易懂的 OpenGL ES 3.0(一)入门必备知识!!
通俗易懂的 OpenGL ES 3.0(二)渲染三角形
前言
额。 好久好久没有更新了,近期有空会加更几篇。 聊聊openGl ES 3.0 NDK集成,记录一些个人的见解,以及理解吧,希望对大家有所帮助。
最终效果
画一个基佬紫背景
NDK ?
在集成opengl之前,先简单的了解下,什么是ndk,什么是jni,和为什么要用c++去写opengl
- ndk: 生成so库的工具包,帮助开发者快速开发C(或C++)的动态库,总的来说就一工具包。
- jni : java 本地接口, 你要调用c/c++ 就要写着玩意。跟接口很像。
简单例子:NativeImpl.java
public class NativeImpl {
static {
System.loadLibrary("native-lib");
}
public static native String stringFromJNI();
}
native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_lai_opengldemo_NativeImpl_stringFromJNI(
JNIEnv *env,
jclass clazz) {
std::string hello = "Hello NativeImpl from C++";
return env->NewStringUTF(hello.c_str());
}
其中方法名是有讲究的: Java _包名 _ 类名_Java需要调用的方法名
当然有强迫症,这种方法命名很难受,也可以通过获取 JNIEnv 通过RegisterNatives注册本地方法。但不在讨论范围就不细说了。
- 为什么要在c/c++写openGl : 到了后面有很多底层库都是c/c++写的,比如ffmpeg、openCV等,为了避免大量的java层交互传输浪费时间就在同一层级写了
集成opengl
File=>NEW=>NEW Project… 选
然后一路next finish 。看到什么 Gradle sync failed: NDK not configured 啥的,那就自个百度谷歌 配配环境,好了之后重新出发运行,不出意外就会看到这个。
cmake 引入opengl 3
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
GLESv3)
现在就可以愉快的玩耍了
使用 GLSurfaceView 呈现opengl 的绘制内容。gl环境不用自己搭建先。
具体的解释可以看上篇
通俗易懂的 OpenGL ES 3.0(二)渲染三角形
<android.opengl.GLSurfaceView
android:id="@+id/gl_surface"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
mainActivity,合适的方法回调做合适的事情,这好理解把 =v=!
gl_surface.setEGLContextClientVersion(3)
gl_surface.setRenderer(object : GLSurfaceView.Renderer{
override fun onDrawFrame(gl: GL10?) {
NativeImpl.draw(width,height);
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
NativeImpl.OnSurfaceChanged(width,height)
}
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
NativeImpl.init()
}
});
gl_surface.renderMode = GLSurfaceView.RENDERMODE_CONTINUOUSLY
NativeImpl 就是我们要实现JNI
public class NativeImpl {
static {
System.loadLibrary("native-lib");
}
public static native String stringFromJNI();
//初始化
public static native void init();
//创建
public static native void OnSurfaceChanged(int width,int height);
//绘制
public static native void draw(int width,int height);
}
对应的 native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_lai_opengldemo_NativeImpl_stringFromJNI(
JNIEnv *env,
jclass clazz) {
std::string hello = "Hello NativeImpl from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_init(JNIEnv *env, jclass instance) {
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_OnSurfaceChanged(JNIEnv *env, jclass instance,jint width, jint height) {
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_draw(JNIEnv *env, jclass instance,jint width, jint height) {
}
绘制个背景色,新建.h 和cpp
//
// Created by Lai on 2020/11/21.
//
#ifndef OPENGLDEMO_BGDEMO_H
#define OPENGLDEMO_BGDEMO_H
#include <GLES3/gl3.h>
class BgDemo {
public:
BgDemo(){
m_ProgramObj = 0;
m_VertexShader = 0;
m_FragmentShader = 0;
};
void Init();
void draw(int screenW, int screenH);
void OnSurfaceChanged(int width, int height);
GLuint m_ProgramObj;
GLuint m_VertexShader;
GLuint m_FragmentShader;
};
#endif //OPENGLDEMO_BGDEMO_H
实现 .cpp
//
// Created by Lai on 2020/11/7.
//
#include "../util/logUtil.h"
#include "../util/GLUtil.h"
#include "BgDemo.h"
#include <GLES3/gl3.h>
void BgDemo::draw(int screenW, int screenH) {
//LOGCATE("TriangleSample::Draw");
if(m_ProgramObj == 0)
return;
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0, 0.5, 1.0, 1.0);
}
void BgDemo::Init() {
if (m_ProgramObj != 0) return;
if(m_ProgramObj != 0)
return;
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"gl_PointSize = 50.0; \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";
LOGCATE("init BgDemo");
m_ProgramObj = GLUtil::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
}
void BgDemo::OnSurfaceChanged(int width, int height) {
LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height);
glViewport(0, 0, width, height);
}
然后在对应的 native-lib.cpp 填上各自的实现
BgDemo *triangleDemo = NULL;
extern "C" JNIEXPORT jstring JNICALL
Java_com_lai_opengldemo_NativeImpl_stringFromJNI(
JNIEnv *env,
jclass clazz) {
std::string hello = "Hello NativeImpl from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_init(JNIEnv *env, jclass instance) {
if (triangleDemo == NULL) {
triangleDemo = new BgDemo();
}
triangleDemo ->Init();
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_OnSurfaceChanged(JNIEnv *env, jclass instance,jint width, jint height) {
triangleDemo->OnSurfaceChanged(width,height);
}
extern "C" JNIEXPORT void JNICALL
Java_com_lai_opengldemo_NativeImpl_draw(JNIEnv *env, jclass instance,jint width, jint height) {
triangleDemo->draw(width,height);
}
一个基佬紫背景就出来了
可能遇到的问题
如果遇到在编写的过程当中 include 一些库时无法使用,编辑器爆红
检查 CMakeLists.text 文件是否有引入该库
确保引入了之后 Android studio 的 build=>Refresh Linked C++ Projects 构建刷新一下
opengl函数提示undefined reference
原因就是找不到什么实现啥的
看看你的 build.gradle ->Android->defaultConfig->minSdkVersion
最小sdk是否小于18,SDK18之后才支持GLESv3
自个编写的函数提示undefined reference
例如 有一个工具类
// util/GLUtil.h
#ifndef OPENGLDEMO_GLUTIL_H
#define OPENGLDEMO_GLUTIL_H
#include <GLES3/gl3.h>
class GLUtil {
static void test();
}
#endif //OPENGLDEMO_GLUTIL_H
// util/GLUtil.cpp
#include "GLUtil.h"
void GLUtil::test() {
LOGCATE("TEST!!!!!");
}
然后在其他类里面去调用这个静态工具类方法
GLUtil::test()
如果 函数提示undefined reference,排除了其他的错误。可以看看CMakeLists.text
使用 include_directories 指定下编译目录
比如我的GLUtil是在util目录下的
确保add_library有包含你要编辑的类,如果全局指令编译文件的。
ps:如果是用全局指令包括需要编译的文件
file(GLOB_RECURSE ALL_SOURCE "*.cpp" "*.c" "*.h")
新增文件之后,请一定要改一下CMakeLists,随便动动就行,加个空格或者之类的,意思就是要文件重新编译,不然它以为你没改过文件。
完整的CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
file(GLOB_RECURSE ALL_SOURCE "*.cpp" "*.c" "*.h")
include_directories(
util
demo
)
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).
#自动添加目录下的C文件
${ALL_SOURCE} )
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 )
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
GLESv3
)
总结
本来想讲讲VBO VAO,但是文章的篇幅过长了,放到下章吧。如果对你有帮助点个赞咯 =v=