立方图就是一个由6个单独2D纹理面组成的纹理,通常,生成环境贴图所用的立方图通过在场景中央放置一个摄像机,从6个轴的方向(+X,-X,+Y,-Y,+Z,-Z)捕捉场景图像并将结果保存在立方体的每个面来生成。
立方图纹素的读取通过使用一个3D向量(s,t,r)作为纹理坐标,在立方图中查找。纹理坐标(s,t,r)代表着3D向量的(x,y,z)分量。这个3D向量首先用于选择立方图中需要读取的一个面,然后该坐标投影到2D坐标(s,t),从该面上读取。
(1)加载像素数据 GLuint CreateSimpleTextureCubemap() { GLuint textureId; GLubyte cubePixels[6][3] = { 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 255, }; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_CUBE_MAP, textureId); // 加载+X面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[0]); // 加载-X面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[1]); // 加载+Y面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[2]); // 加载-Y面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[3]); // 加载+Z面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[4]); // 加载-Z面的像素数据 glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[5]); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return textureId; } (2)查找纹理 // 使用了法向量来查找纹理 outColor = texture(s_texture, v_normal);
需要得到球的顶点坐标,顶点法向量,三角形索引信息
将程序中的球顶点坐标打印出来,前40个顶点坐标为:
x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 0 x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 1 x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 2 x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 3 x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 4 x = 0.000000, y = 1.000000, z = -0.000000, i = 0, j = 5 x = 0.000000, y = 1.000000, z = -0.000000, i = 0, j = 6 x = 0.000000, y = 1.000000, z = -0.000000, i = 0, j = 7 x = 0.000000, y = 1.000000, z = -0.000000, i = 0, j = 8 x = 0.000000, y = 1.000000, z = -0.000000, i = 0, j = 9 x = -0.000000, y = 1.000000, z = -0.000000, i = 0, j = 10 x = -0.000000, y = 1.000000, z = -0.000000, i = 0, j = 11 x = -0.000000, y = 1.000000, z = -0.000000, i = 0, j = 12 x = -0.000000, y = 1.000000, z = -0.000000, i = 0, j = 13 x = -0.000000, y = 1.000000, z = -0.000000, i = 0, j = 14 x = -0.000000, y = 1.000000, z = 0.000000, i = 0, j = 15 x = -0.000000, y = 1.000000, z = 0.000000, i = 0, j = 16 x = -0.000000, y = 1.000000, z = 0.000000, i = 0, j = 17 x = -0.000000, y = 1.000000, z = 0.000000, i = 0, j = 18 x = -0.000000, y = 1.000000, z = 0.000000, i = 0, j = 19 x = 0.000000, y = 1.000000, z = 0.000000, i = 0, j = 20 x = 0.000000, y = 0.951057, z = 0.309017, i = 1, j = 0 x = 0.095492, y = 0.951057, z = 0.293893, i = 1, j = 1 x = 0.181636, y = 0.951057, z = 0.250000, i = 1, j = 2 x = 0.250000, y = 0.951057, z = 0.181636, i = 1, j = 3 x = 0.293893, y = 0.951057, z = 0.095491, i = 1, j = 4 x = 0.309017, y = 0.951057, z = -0.000000, i = 1, j = 5 x = 0.293893, y = 0.951057, z = -0.095492, i = 1, j = 6 x = 0.250000, y = 0.951057, z = -0.181636, i = 1, j = 7 x = 0.181636, y = 0.951057, z = -0.250000, i = 1, j = 8 x = 0.095491, y = 0.951057, z = -0.293893, i = 1, j = 9 x = -0.000000, y = 0.951057, z = -0.309017, i = 1, j = 10 x = -0.095491, y = 0.951057, z = -0.293893, i = 1, j = 11 x = -0.181636, y = 0.951057, z = -0.250000, i = 1, j = 12 x = -0.250000, y = 0.951057, z = -0.181636, i = 1, j = 13 x = -0.293893, y = 0.951057, z = -0.095492, i = 1, j = 14 x = -0.309017, y = 0.951057, z = 0.000000, i = 1, j = 15 x = -0.293893, y = 0.951057, z = 0.095492, i = 1, j = 16 x = -0.250000, y = 0.951057, z = 0.181636, i = 1, j = 17 x = -0.181636, y = 0.951057, z = 0.250000, i = 1, j = 18 x = -0.095491, y = 0.951057, z = 0.293893, i = 1, j = 19 x = 0.000000, y = 0.951057, z = 0.309017, i = 1, j = 20
// 生成球体 // myesGenSphere(20, 0.75f, &userData->vertices, &userData->normals, NULL, &userData->indices); int myesGenSphere(int numSlices, float radius, GLfloat **vertices, GLfloat **normals, GLfloat **texCoords, GLuint **indices) { int i, j; int numParallels = numSlices / 2; int numVertices = (numParallels + 1)*(numSlices + 1); int numIndices = numParallels * numSlices * 6; float angleStep = (2.0f * ES_PI) / ((float) numSlices); if (vertices != NULL) { *vertices = (GLfloat *)malloc(sizeof(GLfloat)*3*numVertices); } if (normals != NULL) { *normals = (GLfloat *)malloc(sizeof(GLfloat)*3*numVertices); } if (texCoords != NULL) { *texCoords = (GLfloat *)malloc(sizeof(GLfloat)*2*numVertices); } if (indices != NULL) { *indices = (GLuint *)malloc(sizeof(GLuint) * numIndices); } for (i = 0; i < numParallels + 1; i++) { for (j = 0; j < numSlices + 1; j++) { int vertex = (i*(numSlices + 1) + j) * 3; if (vertices) { // 获得球体的顶点坐标 (*vertices)[vertex + 0] = radius * sinf(angleStep*(float)i) * sinf(angleStep*(float)j); (*vertices)[vertex + 1] = radius * cosf(angleStep * (float)i); (*vertices)[vertex + 2] = radius * sinf(angleStep * (float) i) * cosf(angleStep * (float) j); } if (normals) { // 获得球体的法向量 (*normals)[vertex + 0] = (*vertices)[vertex + 0] / radius; (*normals)[vertex + 1] = (*vertices)[vertex + 1] / radius; (*normals)[vertex + 2] = (*vertices)[vertex + 2] / radius; } if (texCoords) { int texIndex = (i * (numSlices + 1) + j)*2; (*texCoords)[texIndex + 0] = (float)j / (float)numSlices; (*texCoords)[texIndex + 1] = (1.0f - (float)i) / (float)(numParallels - 1); } } } if (indices != NULL) { GLuint *indexBuf = (*indices); for (i = 0; i < numParallels; i++) { for (j = 0; j < numSlices; j++) { // 获得index *indexBuf++ = i * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1); *indexBuf++ = i * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1); *indexBuf++ = i * (numSlices + 1) + (j + 1); } } } return numIndices; }
#include <stdlib.h> #include "esUtil.h" typedef struct { GLuint programObject; GLint samplerLoc; GLuint textureId; int numIndices; GLfloat *vertices; GLfloat *normals; GLuint *indices; } myUserData; GLuint CreateSimpleTextureCubemap() { GLuint textureId; GLubyte cubePixels[6][3] = { 255, 0, 0, 0, 255, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 255, 0, 255, }; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_CUBE_MAP, textureId); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[0]); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[1]); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[2]); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[3]); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[4]); glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, &cubePixels[5]); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); return textureId; } int Init(MYESContext *myesContext) { myUserData *userData = (myUserData *)myesContext->userData; char vShaderStr[] = "#version 300 es \n" "layout(location = 0) in vec4 a_position; \n" "layout(location = 1) in vec3 a_normal; \n" "out vec3 v_normal; \n" "void main() \n" "{ \n" " gl_Position = a_position; \n" " v_normal = a_normal; \n" "} \n"; char fShaderStr[] = "#version 300 es \n" "precision mediump float; \n" "in vec3 v_normal; \n" "layout(location = 0) out vec4 outColor; \n" "uniform samplerCube s_texture; \n" "void main() \n" "{ \n" " outColor = texture(s_texture, v_normal); \n" "} \n"; userData->programObject = myesLoadProgram(vShaderStr, fShaderStr); userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture"); userData->textureId = CreateSimpleTextureCubemap(); // 生成球体 userData->numIndices = myesGenSphere(20, 0.75f, &userData->vertices, &userData->normals, NULL, &userData->indices); glClearColor(1.0f, 1.0f, 1.0f, 0.0f); return GL_TRUE; } void Draw(MYESContext *myesContext) { myUserData *userData = (myUserData *)myesContext->userData; glViewport(0, 0, myesContext->width, myesContext->height); glClear(GL_COLOR_BUFFER_BIT); // 面剔除,剔除后面的面,因为看不到,可以提高性能 glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glUseProgram(userData->programObject); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, userData->vertices); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, userData->normals); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, userData->textureId); glUniform1i(userData->samplerLoc, 0); glDrawElements(GL_TRIANGLES, userData->numIndices, GL_UNSIGNED_INT, userData->indices); } void ShutDown(MYESContext *myesContext) { myUserData *userData = (myUserData *)myesContext->userData; glDeleteTextures(1, &userData->textureId); glDeleteProgram(userData->programObject); free(userData->vertices); free(userData->normals); } int myesMain(MYESContext *myesContext) { myesContext->userData = malloc(sizeof(myUserData)); myesCreateWindow(myesContext, "9_3_texturewrap", 320, 240, MY_ES_WINDOW_RGB); if (!Init(myesContext)) { return GL_FALSE; } esRegisterDrawFunc(myesContext, Draw); esRegisterShutdownFunc(myesContext, ShutDown); return GL_TRUE; } // 生成球体 // myesGenSphere(20, 0.75f, &userData->vertices, &userData->normals, NULL, &userData->indices); int myesGenSphere(int numSlices, float radius, GLfloat **vertices, GLfloat **normals, GLfloat **texCoords, GLuint **indices) { int i, j; int numParallels = numSlices / 2; int numVertices = (numParallels + 1)*(numSlices + 1); int numIndices = numParallels * numSlices * 6; float angleStep = (2.0f * ES_PI) / ((float) numSlices); if (vertices != NULL) { *vertices = (GLfloat *)malloc(sizeof(GLfloat)*3*numVertices); } if (normals != NULL) { *normals = (GLfloat *)malloc(sizeof(GLfloat)*3*numVertices); } if (texCoords != NULL) { *texCoords = (GLfloat *)malloc(sizeof(GLfloat)*2*numVertices); } if (indices != NULL) { *indices = (GLuint *)malloc(sizeof(GLuint) * numIndices); } for (i = 0; i < numParallels + 1; i++) { for (j = 0; j < numSlices + 1; j++) { int vertex = (i*(numSlices + 1) + j) * 3; if (vertices) { (*vertices)[vertex + 0] = radius * sinf(angleStep*(float)i) * sinf(angleStep*(float)j); (*vertices)[vertex + 1] = radius * cosf(angleStep * (float)i); (*vertices)[vertex + 2] = radius * sinf(angleStep * (float) i) * cosf(angleStep * (float) j); } if (normals) { (*normals)[vertex + 0] = (*vertices)[vertex + 0] / radius; (*normals)[vertex + 1] = (*vertices)[vertex + 1] / radius; (*normals)[vertex + 2] = (*vertices)[vertex + 2] / radius; } if (texCoords) { int texIndex = (i * (numSlices + 1) + j)*2; (*texCoords)[texIndex + 0] = (float)j / (float)numSlices; (*texCoords)[texIndex + 1] = (1.0f - (float)i) / (float)(numParallels - 1); } } } if (indices != NULL) { GLuint *indexBuf = (*indices); for (i = 0; i < numParallels; i++) { for (j = 0; j < numSlices; j++) { *indexBuf++ = i * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1); *indexBuf++ = i * (numSlices + 1) + j; *indexBuf++ = (i + 1) * (numSlices + 1) + (j + 1); *indexBuf++ = i * (numSlices + 1) + (j + 1); } } } return numIndices; }
1. GL02-02:OpenGL球体绘制 https://www.jianshu.com/p/48a4b3f3d51e 2. 面剔除 https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/04%20Face%20culling/