Android使用GLSurfaceView搭建OpenGL环境

Android使用GLSurfaceView搭建OpenGL环境

流程

  1. 新建Android工程,需要配置支持jni。
  2. 新建一个类继承自GLSurfaceView实现Render
  3. 通过jni控制渲染

渲染的步骤

初始化

  1. 编写vertex shader、fragment shader程序.
  2. 使用glCreateShader创建shader.
  3. 给创建好的shader加载shader程序
  4. 编译shader,并查看是否报错
  5. 创建program
  6. attach之前shader到program
  7. link program并查看是否报错
    以上初始化步骤非常类似c语言的编译链接过程。

绘制

  1. 获取vertex shader中定义的attribute
  2. 将数据传给该attribute
  3. 使用glDrawArray绘制

实战:在Android屏幕上画一个三角形

自定义View继承GLSurfaceView

public class GL2JNIView extends GLSurfaceView {
    private static final String TAG = "GL2JNIView";

    public GL2JNIView(Context context) {
        this(context, null);
    }

    public GL2JNIView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public void init() {
        Log.d(TAG, "init: ");
        setEGLContextFactory(new ContextFactory());
        setRenderer(new Render());
    }
    private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
        private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
            Log.w(TAG, "creating OpenGL ES 2.0 context");
            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
            EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
            return context;
        }

        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
            egl.eglDestroyContext(display, context);
        }
    }

    public static class Render implements GLSurfaceView.Renderer {
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            Log.d(TAG, "onSurfaceCreated: ");
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            Log.d(TAG, "onSurfaceChanged: width=" + width + ",height=" + height);
            String version = gl.glGetString(GL10.GL_VERSION);
            Log.d(TAG, "version: "+ version);
            GL2JNILib.init(width, height);
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            Log.i(TAG, "onDrawFrame: ");
            GL2JNILib.step();
        }
    }
}

jni层

public class GL2JNILib {
    public static native void init(int width,int height);
    public static native void step();
}

c++


#include "gl2jni.h"
#include <GLES2/gl2.h>
#include <android/log.h>

#define TAG  "EGL"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
extern "C" {

auto gVertexShader =
        "attribute vec4 vPosition;\n"
        "void main() {\n"
        "  gl_Position = vPosition;\n"
        "}\n";

auto gFragmentShader =
        "precision mediump float;\n"
        "void main() {\n"
        "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
        "}\n";

const GLfloat gTriangleVertices[] = { 0.0f, 0.5f,
                                      -0.5f, -0.5f,
                                      0.5f, -0.5f };

static void checkGlError(const char * op){
    GLenum error = GL_NO_ERROR;
    for(error =glGetError();error;error = glGetError()){
        LOGE("after %s glGetError:0x%d",op,error);
    }
}
GLuint loadShader(GLenum shaderType, const char *pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        // 1. load source
        glShaderSource(shader, 1, &pSource, nullptr);
        // 2. compile source.
        glCompileShader(shader);
        GLint compiled = 0;
        // 3. Get compiled result.
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);

        if (!compiled) {
            // if compile failed We should get error msg length  then print it .
            GLint errorLength = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errorLength);
            if (errorLength) {
                char *msg = new char[errorLength];
                glGetShaderInfoLog(shader, errorLength, nullptr, msg);
                LOGE("We couldn't compile this shader,%s", msg);
                delete[] msg;
            }
            glDeleteShader(shader);
            shader = 0;
        }
    }
    return shader;
}

GLuint createGlProgram(const char *pVertexShaderSource, const char *pFragmentShaderSource) {
    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexShaderSource);
    if (!vertexShader) {
        return 0;
    }
    GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, pFragmentShaderSource);
    if (!fragmentShader) {
        return 0;
    }
    GLuint  glProgram =glCreateProgram();
    if(glProgram){
        glAttachShader(glProgram,vertexShader);
        checkGlError("attach vertexShader");
        glAttachShader(glProgram,fragmentShader);
        checkGlError("attach fragmentShader");
        glLinkProgram(glProgram);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(glProgram,GL_LINK_STATUS,&linkStatus);
        if(linkStatus != GL_TRUE){
            GLint errorLength = 0;
            glGetProgramiv(glProgram,GL_INFO_LOG_LENGTH,&errorLength);
            if(errorLength){
                char * errorMsg = new char [errorLength];
                glGetProgramInfoLog(glProgram,errorLength, nullptr,errorMsg);
                LOGE("Link program is error %s",errorMsg);
                delete[] errorMsg;
            }
            glDeleteProgram(glProgram);
            glProgram = 0;
        }
    }
    return glProgram;
}

GLuint  gProgram;
GLuint  gPosition;
JNIEXPORT void JNICALL
Java_com_blueberry_glexampe_GL2JNILib_init(JNIEnv *env, jclass clazz, jint width, jint height) {
    auto version = glGetString(GL_VERSION);
    auto vendor = glGetString(GL_VENDOR);
    auto renderer = glGetString(GL_RENDERER);
    auto extension = glGetString(GL_EXTENSIONS);
    LOGD("glversion is : %s", version);
    LOGD("glvender is : %s", vendor);
    LOGD("glrender is : %s", renderer);
    LOGD("glextension is : %s", extension);
    // We have created glContext in java layer before.
    gProgram = createGlProgram(gVertexShader, gFragmentShader);
    if (!gProgram) {
        LOGE("could not create program.");
        return;
    }
    gPosition =glGetAttribLocation(gProgram,"vPosition");
    checkGlError("get attribLocation");
    glViewport(0,0,width,height);
}

JNIEXPORT void JNICALL
Java_com_blueberry_glexampe_GL2JNILib_step(JNIEnv *env, jclass clazz) {
    static float  grey = 0;
    grey += 0.01f;
    if(grey > 1.0){
        grey = 0.0;
    }
    glClearColor(grey,grey,grey,1.0f);
    checkGlError("glClearColor");
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    checkGlError("glClear bufferBit | color buffer.");
    glUseProgram(gProgram);
    checkGlError("use program.");
    // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml
    glVertexAttribPointer(gPosition,
                          2,   // 一个顶点所拥有的数据个数
                          GL_FLOAT, // 数据类型
                          GL_FALSE, // 是否需要把数据归一化到 -1,1之间
                          0,gTriangleVertices);
    checkGlError("atrrib pointer.");
    glEnableVertexAttribArray(gPosition);
    checkGlError("glEnabled Vertext attrib array.");
    glDrawArrays(GL_TRIANGLES,0,3);
    checkGlError("glDrawArrays error.");
}
}

CMakeLists需要依赖EGL,GLESv2

cmake_minimum_required(VERSION 3.4.1)

# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall")

add_library(gl2jni SHARED
            gl_code.cpp)

# add lib dependencies
target_link_libraries(gl2jni
                      android
                      log 
                      EGL
                      GLESv2)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值