GLES学习笔记---立方体贴图(一张图)

一、首先看一张效果图

立方体贴图

二、纹理坐标划分

如上图是一张2D纹理,我们需要将这个2D纹理贴到立方体上,立方体有6个面,所以上面的2D图分成了6个面,共有14个纹理坐标

三、立方体

上边的立方体一共8个顶点坐标,范围是[-1, 1];

我们要做的是将纹理图贴到这6个面上面

四、顶点坐标纹理坐标关联

我们绘制的时候使用了VBO、VAO、EBO、

复制代码
vertices里面是纹理坐标和顶点坐标的对应关系,纹理贴到哪个顶点上面;纹理坐标一共十四个,贴到8个顶点上。

indices里面是绘制的12个三角形

cpp 复制代码
float DP = 0.5f;
                        /*顶点               纹理*/
    float vertices[] = {-DP, -DP, DP,     0.25,  0.333,  //0
                         DP, -DP, DP,     0.50,  0.333,  //1
                         DP,  DP, DP,     0.50,  0.666,  //2
                        -DP,  DP, DP,     0.25,  0.666,  //3
                        -DP, -DP, -DP,    1.00,  0.333,  //4
                         DP, -DP, -DP,    0.75,  0.333,  //5
                         DP,  DP, -DP,    0.75,  0.666,  //6
                        -DP,  DP, -DP,    1.00,  0.666,  //7

                        -DP, -DP, -DP,    0.25,    0,    //4  8
                        DP, -DP, -DP,      0.5,    0,    //5  9
                        DP,  DP, -DP,      0.5,    1,    //6  10
                        -DP,  DP, -DP,    0.25,    1,    //7  11

                        -DP, -DP, -DP,       0,  0.333,  //4  12
                        -DP,  DP, -DP,       0,  0.666,  //7  13
                        };

    unsigned int indices[] = {
            0, 1, 2, 0, 2, 3,  // front
            1, 2, 5, 2, 5, 6,  // right
            4, 5, 6, 4, 6, 7,  // back

            0, 3, 12, 3, 12, 13, // left

            0, 1, 8, 1, 8, 9,  // bottom
            2, 3, 10, 3, 10, 11, // top
    };

五、完整代码

有部分代码是测试用的,不用细究奇怪的逻辑

cpp 复制代码
//
// Created by fengcheng.cai on 2023/12/15.
//
#define EGL_EGLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES

#include "com_sprd_opengl_test_MyNdk4.h"
#include <ggl.h>
#include <string.h>
#include <unistd.h>
#include <android/bitmap.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#define LOG_TAG "MyNdk4"

struct GL_Context4 {
    GLint program;
    EGLDisplay display;
    EGLSurface winSurface;
    EGLContext context;
    ANativeWindow *nw;
    AImageReader *reader;
};
static GL_Context4 gl_cxt;

static char *vertexSimpleShape = "#version 300 es\n"
                                 "layout (location = 0) in vec4 aPosition;\n"
                                 "layout (location = 1) in vec2 aTexCoord;\n"
                                 "uniform mat4 u_MVPMatrix;\n"
                                 "out vec2 TexCoord;\n"
                                 "void main() {\n"
                                 "     gl_Position = u_MVPMatrix * aPosition;\n"
                                 "     TexCoord = aTexCoord;\n"
                                 "}\n";

static char *fragSimpleShape = "#version 300 es\n"
                               "  precision  mediump float;\n"
                               "  in vec2 TexCoord;\n"
                               "  out vec4 FragColor;\n"
                               "  uniform sampler2D ourTexture;\n"
                               "  void main() {\n"
                               "       FragColor = texture(ourTexture, TexCoord);\n"
                               "  }\n";

static GLint initShader(const char *source, GLint type) {
    //创建着色器对象,type表示着色器类型,比如顶点着色器为GL_VERTEX_SHADER,片段着色器为GL_FRAGMENT_SHADER。返回值为一个类似引用的数字。
    GLint sh = glCreateShader(type);
    if (sh == 0) {
        //返回值sh为0则表示创建着色器失败
        LOGD("glCreateShader %d failed", type);
        return 0;
    }
    //着色器对象加载着色器对象代码source
    glShaderSource(sh,
                   1,//shader数量
                   &source,
                   0);//代码长度,传0则读到字符串结尾

    //编译着色器对象
    glCompileShader(sh);

    //以下为打印出编译异常信息
    GLint status;
    glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
    if (status == 0) {
        LOGD("glCompileShader %d failed", type);
        LOGD("source %s", source);
        auto *infoLog = new GLchar[512];
        GLsizei length;
        glGetShaderInfoLog(sh, 512, &length, infoLog);

        LOGD("ERROR::SHADER::VERTEX::COMPILATION_FAILED %s", infoLog);
        return 0;
    }

    LOGD("glCompileShader %d success", type);
    return sh;
}

JNIEXPORT void JNICALL Java_com_sprd_opengl_test_MyNdk4_init
        (JNIEnv *env, jobject obj, jobject surface) {
    // egl ------------------------------------------------------------------- start
    LOGD("init");

    ANativeWindow *nwin = ANativeWindow_fromSurface(env, surface);
    gl_cxt.nw = nwin;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (display == EGL_NO_DISPLAY) {
        LOGD("egl display failed");
        return;
    }

    if (EGL_TRUE != eglInitialize(display, 0, 0)) {
        LOGD("eglInitialize failed");
        return;
    }

    EGLConfig eglConfig;
    EGLint configNum;
    EGLint configSpec[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 8,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_RECORDABLE_ANDROID, EGL_TRUE,
            EGL_NONE
    };

    if (EGL_TRUE != eglChooseConfig(display, configSpec, &eglConfig, 1, &configNum)) {
        LOGD("eglChooseConfig failed");
        return;
    }

    EGLSurface winSurface = eglCreateWindowSurface(display, eglConfig, nwin, 0);
    if (winSurface == EGL_NO_SURFACE) {
        LOGD("eglCreateWindowSurface failed");
        return;
    }

    const EGLint ctxAttr[] = {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
    };

    EGLContext context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, ctxAttr);
    if (context == EGL_NO_CONTEXT) {
        LOGD("eglCreateContext failed");
        return;
    }

    if (EGL_TRUE != eglMakeCurrent(display, winSurface, winSurface, context)) {
        LOGD("eglMakeCurrent failed");
        return;
    }
    gl_cxt.display = display;
    gl_cxt.winSurface = winSurface;
    gl_cxt.context = context;

    // egl ------------------------------------------------------------------- end

    // shader ------------------------------------------------------------------- start
    GLint vsh = initShader(vertexSimpleShape, GL_VERTEX_SHADER);
    GLint fsh = initShader(fragSimpleShape, GL_FRAGMENT_SHADER);

    GLint program = glCreateProgram();
    if (program == 0) {
        LOGD("glCreateProgram failed");
        return;
    }

    glAttachShader(program, vsh);
    glAttachShader(program, fsh);

    glLinkProgram(program);
    GLint status2 = 0;
    glGetProgramiv(program, GL_LINK_STATUS, &status2);
    if (status2 == 0) {
        LOGD("glLinkProgram failed");
        return;
    }
    gl_cxt.program = program;
    LOGD("glLinkProgram success");
    // shader ------------------------------------------------------------------- end
}

static void printMat4(glm::mat4 matrix) {
    LOGD("\nll\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n",
             matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
             matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
             matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
             matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
}

static void printVec4(glm::vec4 vec) {
    LOGD("\nll\n%f, %f, %f, %f\n",
         vec[0], vec[1], vec[2], vec[3]);
}

JNIEXPORT void JNICALL Java_com_sprd_opengl_test_MyNdk4_process
        (JNIEnv *env, jobject obj, jobject bitmap,  jint surfaceW, jint surfaceH) {
    glUseProgram(gl_cxt.program);
    AndroidBitmapInfo bitmapInfo;
    if (AndroidBitmap_getInfo(env, bitmap, &bitmapInfo) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! ");
        return;
    }
    void *bmpPixels;
    int width = bitmapInfo.width;
    int height = bitmapInfo.height;
    LOGD("process format: %d, stride: %d", bitmapInfo.format, bitmapInfo.stride);
    AndroidBitmap_lockPixels(env, bitmap, &bmpPixels);

    unsigned int textureId;
    glGenTextures(1, &textureId);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textureId);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


    LOGD("process2  4");
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmpPixels);
    unsigned char *pOri = (unsigned char *)bmpPixels;
    LOGD("process2  5     %d, %d, %d, %d, %d, %d, %d, %d", *(pOri), *(pOri+1), *(pOri+2), *(pOri+3),
         *(pOri+114), *(pOri+115), *(pOri+116), *(pOri+117));
    glBindTexture(GL_TEXTURE_2D, 0);
    AndroidBitmap_unlockPixels(env, bitmap);

    float DP = 0.5f;
                        /*顶点               纹理*/
    float vertices[] = {-DP, -DP, DP,     0.25,  0.333,  //0
                         DP, -DP, DP,     0.50,  0.333,  //1
                         DP,  DP, DP,     0.50,  0.666,  //2
                        -DP,  DP, DP,     0.25,  0.666,  //3
                        -DP, -DP, -DP,    1.00,  0.333,  //4
                         DP, -DP, -DP,    0.75,  0.333,  //5
                         DP,  DP, -DP,    0.75,  0.666,  //6
                        -DP,  DP, -DP,    1.00,  0.666,  //7

                        -DP, -DP, -DP,    0.25,    0,    //4  8
                        DP, -DP, -DP,      0.5,    0,    //5  9
                        DP,  DP, -DP,      0.5,    1,    //6  10
                        -DP,  DP, -DP,    0.25,    1,    //7  11

                        -DP, -DP, -DP,       0,  0.333,  //4  12
                        -DP,  DP, -DP,       0,  0.666,  //7  13
                        };

    unsigned int indices[] = {
            0, 1, 2, 0, 2, 3,  // front
            1, 2, 5, 2, 5, 6,  // right
            4, 5, 6, 4, 6, 7,  // back

            0, 3, 12, 3, 12, 13, // left

            0, 1, 8, 1, 8, 9,  // bottom
            2, 3, 10, 3, 10, 11, // top
    };
    bool looper = true;
    int count = 0;
    float angleX = 0.0f;
    float angleY = 0.0f;
    float angleZ = 0.0f;
#define MAX_LEN 512
    float near[MAX_LEN] = {0.0f};
    for (int i = 0; i < MAX_LEN / 2; i++) {
        near[i] = 1.0f + 1.0f * i / (MAX_LEN / 2);
    }
    for (int i = 0; i < MAX_LEN / 2; i++) {
        near[i + MAX_LEN / 2] = 2.0f - 1.0f * i / (MAX_LEN / 2);
    }

    int sizeNear = sizeof(near) / sizeof(float);
    while(looper) {
        angleX += 0.5f;
        angleY += 0.6f;
        angleZ += 0.8f;
        glm::mat4 modelM = glm::mat4(1.0f);
        modelM = glm::scale(modelM, glm::vec3(1.0f, 1.0f, 1.0f));
        modelM = glm::rotate(modelM, glm::radians(angleX), glm::vec3(1.0f, 0.0f, 0.0f));
        modelM = glm::rotate(modelM, glm::radians(angleY), glm::vec3(0.0f, 1.0f, 0.0f));
        modelM = glm::rotate(modelM, glm::radians(angleZ), glm::vec3(0.0f, 0.0f, 1.0f));
        modelM = glm::translate(modelM, glm::vec3(0.0f, 0.0f, 0.0f));
        LOGD("modelM:");
        printMat4(modelM);

        glm::mat4 viewM = glm::lookAt(
                glm::vec3(0, 0, 2.88), // Camera is at (0,0,1), in World Space 相机位置
                glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
                glm::vec3(0, 1, 0));  // Head is up (set to 0,-1,0 to look upside-down) 相机 up 方向,即相机头部朝向
        LOGD("viewM:");
        printMat4(viewM);

        glm::mat4 mv = viewM*modelM;
        printVec4(mv*glm::vec4(-1.0, -1.0, 0, 1));
        printVec4(mv*glm::vec4(1.0, 1.0, 0, 1));
        printVec4(mv*glm::vec4(-1.0, 1.0, 0, 1));
        printVec4(mv*glm::vec4(1.0, -1.0, 0, 1));


        float ratio = 1.0f * width / height;
        LOGD("ratio: %f, width: %d, height: %d, surfaceW: %d, surfaceH: %d", ratio, width, height, surfaceW, surfaceH);
        glm::mat4 prjM;
        if (1.0f * height / width > 1.0f * surfaceH / surfaceW) {
            prjM = glm::ortho(-1.0f * width / height, 1.0f * width / height, -1.0f, 1.0f, 0.0f, 100.0f); //ratio 一般表示视口的宽高比,width/height
        } else {
            prjM = glm::ortho(-1.0f, 1.0f,
                              -1.0f * surfaceH / (1.0f*surfaceW*height/width), 1.0f * surfaceH / (1.0f*surfaceW*height/width),
                              3.0f, 100.0f);
        }

        prjM = glm::ortho(-1.0f, 1.0f,
                          -1.0f, 1.0f,
                          1.5f, 100.0f);  // 这两个值其实是负的方向更好理解

        printMat4(prjM);


//    prjM = glm::perspective(glm::radians(45.0f), 1.0f * surfaceW / surfaceH, 2.6f, 100.f); //ratio 一般表示视口的宽高比,width/height,
//    LOGD("prjM:");
//    printMat4(prjM);

        prjM = glm::frustum(-1.0f, 1.0f,
                        -1.0f, 1.0f,
                        near[count%sizeNear], 100.f);
        LOGD("prjM:");
        printMat4(prjM);



        glm::mat4 mvp = prjM*viewM*modelM;
        printVec4(mvp*glm::vec4(-DP, -DP, DP, 1));
        printVec4(mvp*glm::vec4(-DP, -DP, -DP, 1));

        //mvp = glm::mat4(1.0f);
        GLint mvpLoc = glGetUniformLocation(gl_cxt.program, "u_MVPMatrix");
        glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, (GLfloat *)&mvp[0][0]);

        // optimal
        unsigned int VBO, EBO, VAO;
        glGenVertexArrays(1, &VAO);
        glBindVertexArray(VAO);

        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)((0 + 3)*sizeof(float)));
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);

        glGenBuffers(1, &EBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

        glBindVertexArray(0);


        glBindVertexArray(VAO);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        glEnable(GL_TEXTURE_2D);
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

        // draw to screen
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureId);
        glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(int), GL_UNSIGNED_INT, (void*)0);
        glBindTexture(GL_TEXTURE_2D, 0);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        glBindVertexArray(0);

        eglSwapBuffers(gl_cxt.display, gl_cxt.winSurface);

        count++;
        usleep(15 * 1000);
        if (count == 99999) {
            looper = false;
        }
    }


    LOGD("process2 X");
}

JNIEXPORT void JNICALL Java_com_sprd_opengl_test_MyNdk4_uninit
        (JNIEnv *env, jobject obj) {
    LOGD("uninit");
    eglDestroySurface(gl_cxt.display, gl_cxt.winSurface);
    eglDestroyContext(gl_cxt.display, gl_cxt.context);
    eglMakeCurrent(gl_cxt.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglTerminate(gl_cxt.display);

    gl_cxt.winSurface = EGL_NO_SURFACE;
    gl_cxt.display = EGL_NO_DISPLAY;
    gl_cxt.context = EGL_NO_CONTEXT;
}

六、注意点

cpp 复制代码
EGLint configSpec[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, 8,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_RECORDABLE_ANDROID, EGL_TRUE,
            EGL_NONE
    };


glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

一定要配置 EGL_DEPTH_SIZE,我调试的时候没有配置EGL_DEPTH_SIZE(即使

复制代码
glEnable(GL_DEPTH_TEST)调用了),导致绘制的立方体一直有问题,没有立体效果
相关推荐
每次的天空34 分钟前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭1 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日2 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安2 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑2 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟6 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡8 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi008 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
哈市雪花8 小时前
相机:Camera原理讲解(使用OpenGL+QT开发三维CAD)
qt·3d·交互·相机·图形学·opengl·视角
zhangphil9 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android