【问题标题】:How to load and display an image in OpenGL ES 3.0 using C++如何使用 C++ 在 OpenGL ES 3.0 中加载和显示图像
【发布时间】:2017-06-28 11:21:25
【问题描述】:

我正在尝试使用 NDK、JNI 在 Android Studio 上制作一个简单的应用程序,以调用加载和显示图像的 C++ 代码。我已经设法创建了表面并绘制了一个简单的三角形。

现在,我正在寻找一种使用 C++ 在 OpenGL ES 3.0 中加载和显示图像的方法。我已经完成了搜索,但它们要么对我来说太复杂,要么已经过时或用 Java 编写。如果有人能用一个简单的例子指导我,那就太好了。

【问题讨论】:

    标签: opengl-es texture2d opengl-es-3.0


    【解决方案1】:

    经过一番折腾,我终于成功了。下面是我的 C++ 源代码。我使用 stb_image 库来加载图像。

    /*
     * Copyright (C) 2009 The Android Open Source Project
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    // OpenGL ES 3.0 code
    
    #include <jni.h>
    #include <android/log.h>
    
    #include <GLES3/gl3.h>
    #include <GLES3/gl3ext.h>
    #include <GLES3/gl3ext.h>
    
    #include <string>
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include "stb_image.h"
    
    #define  LOG_TAG    "libgl2jni"
    #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
    #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
    
    GLuint mTexture, VAO;// Create reference Id for the texture
    GLuint gProgram;
    GLuint gvPositionHandle;
    
    static void printGLString(const char *name, GLenum s) {
        const char *v = (const char *) glGetString(s);
        LOGI("GL %s = %s\n", name, v);
    }
    
    static void checkGlError(const char* op) {
        for (GLint error = glGetError(); error; error
                = glGetError()) {
            LOGI("after %s() glError (0x%x)\n", op, error);
        }
    }
    
    auto gVertexShader =
    "#version 300 es\n"
    "layout (location=0) in vec3 position;\n"
    "layout (location=1) in vec3 color;\n"
    "layout (location=2) in vec2 texCoord;\n"
    
    "out vec3 ourColor;\n"
    "out vec2 TexCoord;\n"
    
    "void main()\n"
    "{\n"
        "gl_Position = vec4(position,1.0f); // Add the xOffset to the x position of the vertex position\n"
        "ourColor = color;\n"
        "TexCoord= vec2(texCoord.x,1.0f-texCoord.y);\n"
    "}";
    
    auto gFragmentShader =
    
    "#version 300 es\n"
    "in vec3 ourColor;\n"
    "in vec2 TexCoord;\n"
    
    "out vec4 color;\n"
    
    "uniform sampler2D ourTexture;\n"
    
    
    "void main()\n"
    "{\n"
        "color = texture(ourTexture , TexCoord);\n"
    "}\n";
    
    GLuint loadShader(GLenum shaderType, const char* pSource) {
        GLuint shader = glCreateShader(shaderType);
        if (shader) {
            glShaderSource(shader, 1, &pSource, NULL);
            glCompileShader(shader);
            GLint compiled = 0;
            glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
            if (!compiled) {
                GLint infoLen = 0;
                glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
                if (infoLen) {
                    char* buf = (char*) malloc(infoLen);
                    if (buf) {
                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
                        LOGE("Could not compile shader %d:\n%s\n",
                                shaderType, buf);
                        free(buf);
                    }
                    glDeleteShader(shader);
                    shader = 0;
                }
            }
        }
        return shader;
    }
    
    GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { // Load and Bind Fragments to Progam and link program then return result
        GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
        if (!vertexShader) {
            return 0;
        }
    
        GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
        if (!pixelShader) {
            return 0;
        }
    
        GLuint program = glCreateProgram();
        if (program) {
            glAttachShader(program, vertexShader);
            checkGlError("glAttachShader");
            glAttachShader(program, pixelShader);
            checkGlError("glAttachShader");
            glLinkProgram(program);
            GLint linkStatus = GL_FALSE;
            glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
            if (linkStatus != GL_TRUE) {
                GLint bufLength = 0;
                glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
                if (bufLength) {
                    char* buf = (char*) malloc(bufLength);
                    if (buf) {
                        glGetProgramInfoLog(program, bufLength, NULL, buf);
                        LOGE("Could not link program:\n%s\n", buf);
                        free(buf);
                    }
                }
                glDeleteProgram(program);
                program = 0;
            }
        }
        return program;
    }
    
    
    
    bool setupGraphics(int w, int h) {
        printGLString("Version", GL_VERSION);
        printGLString("Vendor", GL_VENDOR);
        printGLString("Renderer", GL_RENDERER);
        printGLString("Extensions", GL_EXTENSIONS);
    
        LOGI("setupGraphics(%d, %d)", w, h);
        gProgram = createProgram(gVertexShader, gFragmentShader);
        if (!gProgram) {
            LOGE("Could not create program.");
            return false;
        }
        gvPositionHandle = glGetAttribLocation(gProgram, "position");
        checkGlError("glGetAttribLocation");
        LOGI("glGetAttribLocation(\"position\") = %d\n",
                gvPositionHandle);
    
        glViewport(0, 0, w, h);
        checkGlError("glViewport");
        return true;
    }
    
    GLfloat recVertices[] = {
            // Positions          // Colors          // Texture Coords
            0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,    1.0f, 1.0f,   // Top Right
            0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,    1.0f, 0.0f,   // Bottom Right
            -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // Bottom Left
            -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f    // Top Left
    };
    
    GLuint indices[] = {  // Note that we start from 0!
            0, 1, 3, // First Triangle
            1, 2, 3  // Second Triangle
    };
    void initBuffers()
    {
    
        GLuint VBOs[2], EBO; // Initialize an buffer to store all the verticles and transfer them to the GPU
        glGenVertexArrays (1,&VAO); // Generate VAO
        glGenBuffers(1, VBOs); // Generate VBO
        glGenBuffers(1, &EBO); // Generate EBO
        glBindVertexArray (VAO);// Bind the Vertex Array
    
        glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);//Bind verticles array for OpenGL to use
        glBufferData(GL_ARRAY_BUFFER, sizeof(recVertices), recVertices, GL_STATIC_DRAW);
    
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//Bind the indices for information about drawing sequence
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
        // 1. set the vertex attributes pointers
        // Position Attribute
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        // Color Attribute
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
        glEnableVertexAttribArray(1);
        //Texture Coordinate Attribute
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat)));
        glEnableVertexAttribArray(2);
    
        glBindVertexArray(0);//3. Unbind VAO
    
    }
    
    void generateTexture()
    {
    
        glGenTextures(1 , &mTexture);
        glBindTexture(GL_TEXTURE_2D, mTexture);// Bind our 2D texture so that following set up will be applied
    
        //Set texture wrapping parameter
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT);
    
        //Set texture Filtering parameter
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    
        //Load the image
        int picWidth,picHeight,n;
        unsigned char* image = stbi_load("/storage/emulated/sdcard/Lighthouse.jpg", &picWidth, &picHeight, &n,0);
        if (image == NULL ) {
            LOGI("Failed to load image: %s", stbi_failure_reason());
        }
        //Generate the image
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB , picWidth , picHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
        glGenerateMipmap(GL_TEXTURE_2D);
    
        stbi_image_free(image);// Free the reference to the image
        glBindTexture(GL_TEXTURE_2D,0); //Unbind 2D textures
    
    }
    void renderFrame() {
        static float grey;
        grey += 0.01f;
        if (grey > 1.0f) {
            grey = 0.0f;
        }
    
        generateTexture();
        glClearColor(grey+0.05f, grey-0.03f, grey+0.02f, grey-0.04f);
        checkGlError("glClearColor");
        glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        checkGlError("glClear");
    
        glUseProgram(gProgram);
        checkGlError("glUseProgram");
    
        /*glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, recVertices);
        checkGlError("glVertexAttribPointer");
        glEnableVertexAttribArray(gvPositionHandle);
        checkGlError("glEnableVertexAttribArray");
        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
        checkGlError("glDrawArrays");*/
        glActiveTexture(GL_TEXTURE0);
        checkGlError("glActiveTexture");
        glBindTexture(GL_TEXTURE_2D,mTexture);
        checkGlError("glBindTexture");
        GLint mlocation = glGetUniformLocation(gProgram,"ourTexture");
        checkGlError("glGetUniformLocation");
        glUniform1i(mlocation,0);
        checkGlError("glUniform1i");
        initBuffers();
        glBindVertexArray(VAO);
        checkGlError("glBindVertexArray");
        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,0);
    
    }
    
    extern "C" {
        JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height);
        JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv * env, jobject obj);
    };
    
    JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height)
    {
        setupGraphics(width, height);
    }
    
    JNIEXPORT void JNICALL Java_com_android_gles3jni_GLES3JNILib_step(JNIEnv * env, jobject obj)
    {
    
        renderFrame();
    }
    

    【讨论】:

    • 能否请您分享如何在 Android 应用程序中使用此 c++ 源代码。我是 NDK 的新手
    猜你喜欢
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多