一、首先看一張效果圖
立方體貼圖
二、紋理坐標(biāo)劃分
如上圖是一張2D紋理,我們需要將這個(gè)2D紋理貼到立方體上,立方體有6個(gè)面,所以上面的2D圖分成了6個(gè)面,共有14個(gè)紋理坐標(biāo)
三、立方體
上邊的立方體一共8個(gè)頂點(diǎn)坐標(biāo),范圍是[-1, 1];
我們要做的是將紋理圖貼到這6個(gè)面上面
四、頂點(diǎn)坐標(biāo)紋理坐標(biāo)關(guān)聯(lián)
我們繪制的時(shí)候使用了VBO、VAO、EBO、
vertices里面是紋理坐標(biāo)和頂點(diǎn)坐標(biāo)的對(duì)應(yīng)關(guān)系,紋理貼到哪個(gè)頂點(diǎn)上面;紋理坐標(biāo)一共十四個(gè),貼到8個(gè)頂點(diǎn)上。
indices里面是繪制的12個(gè)三角形
float DP = 0.5f;
/*頂點(diǎn) 紋理*/
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
};
五、完整代碼
有部分代碼是測(cè)試用的,不用細(xì)究奇怪的邏輯文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-803177.html
//
// 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) {
//創(chuàng)建著色器對(duì)象,type表示著色器類型,比如頂點(diǎn)著色器為GL_VERTEX_SHADER,片段著色器為GL_FRAGMENT_SHADER。返回值為一個(gè)類似引用的數(shù)字。
GLint sh = glCreateShader(type);
if (sh == 0) {
//返回值sh為0則表示創(chuàng)建著色器失敗
LOGD("glCreateShader %d failed", type);
return 0;
}
//著色器對(duì)象加載著色器對(duì)象代碼source
glShaderSource(sh,
1,//shader數(shù)量
&source,
0);//代碼長(zhǎng)度,傳0則讀到字符串結(jié)尾
//編譯著色器對(duì)象
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;
/*頂點(diǎn) 紋理*/
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 相機(jī)位置
glm::vec3(0, 0, 0), // and looks at the origin 觀察點(diǎn)坐標(biāo)
glm::vec3(0, 1, 0)); // Head is up (set to 0,-1,0 to look upside-down) 相機(jī) up 方向,即相機(jī)頭部朝向
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); // 這兩個(gè)值其實(shí)是負(fù)的方向更好理解
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;
}
六、注意點(diǎn)
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,我調(diào)試的時(shí)候沒(méi)有配置EGL_DEPTH_SIZE(即使文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-803177.html
glEnable(GL_DEPTH_TEST)調(diào)用了),導(dǎo)致繪制的立方體一直有問(wèn)題,沒(méi)有立體效果
到了這里,關(guān)于GLES學(xué)習(xí)筆記---立方體貼圖(一張圖)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!