通俗易懂的 OpenGL ES 3.0(三)NDK集成opengl

系列文章目录

通俗易懂的 OpenGL ES 3.0(一)入门必备知识!!

通俗易懂的 OpenGL ES 3.0(二)渲染三角形


前言

额。 好久好久没有更新了,近期有空会加更几篇。 聊聊openGl ES 3.0 NDK集成,记录一些个人的见解,以及理解吧,希望对大家有所帮助。

最终效果

演示demo

画一个基佬紫背景

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=

演示demo

参考

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用NDKOpenGL ES 3.0来绘制一个角形可以分为以下几个步骤: 1. 首先,创建一个安卓项目,并配置NDK环境。 2. 在项目的jni目录下,创建一个C/C++源文件triangle.c。 3. 在triangle.c文件中,引入相关的头文件,包括<jni.h>和<GLES3/gl3.h>。 4. 在triangle.c文件中,实现一个JNI函数,用于绘制角形。函数的参数为Surface对象。 5. 在JNI函数中,通过EGL和GLES初始化OpenGL环境,并创建一个EGLSurface用于后续的绘制操作。 6. 在JNI函数中,创建一个顶点数组和顶点缓冲,并将顶点数据存入顶点缓冲。 7. 在JNI函数中,编写着色器代码,包括顶点着色器和片段着色器,并编译和链接它们。 8. 在JNI函数中,通过glClearColor()函数设置清空屏幕时的颜色。 9. 在JNI函数中,通过glClear()函数清空屏幕,并启用深度测试。 10. 在JNI函数中,通过glViewport()函数设置视口大小。 11. 在JNI函数中,通过glUseProgram()函数使用着色器程序。 12. 在JNI函数中,通过glVertexAttribPointer()函数设置顶点数据的属性,并启用顶点属性。 13. 在JNI函数中,通过glDrawArrays()函数绘制角形。 14. 在JNI函数中,通过eglSwapBuffers()函数交换绘制的缓冲区。 15. 在JNI函数中,清理OpenGL环境,并释放资源。 16. 在Java层的MainActivity中,通过JNI调用C/C++函数进行绘制。 以上是绘制一个角形的大致步骤。具体的细节和代码实现可以参考相关的OpenGL ES 3.0NDK的文档和示例代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值