【openGLES3.0编程指南笔记-8】加载立方图纹理

概述

立方图纹理

​ 立方图就是一个由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

球体绘制的数学模型

image

绘制球体的源码

// 生成球体
// 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;
}

效果图

image

参考

1. GL02-02:OpenGL球体绘制
https://www.jianshu.com/p/48a4b3f3d51e
2. 面剔除
https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/04%20Face%20culling/
posted @ 2021-05-09 17:54  pyjetson  阅读(212)  评论(0编辑  收藏  举报