使用索引时如何为 UV 添加 vec2 以进行纹理映射

Posted

技术标签:

【中文标题】使用索引时如何为 UV 添加 vec2 以进行纹理映射【英文标题】:How to add vec2 for UV for texture mapping when using indices 【发布时间】:2021-07-31 22:22:48 【问题描述】:

我正在尝试将纹理映射应用于我的立方体,但不确定如何进行。目前我正在使用索引来避免重复 vec3s 来制作一个立方体和一个点及其法线的顶点数组,如下所示:

// Cube data as our basic building block
       unsigned int indices[] = 
        10, 8, 0, 2, 10, 0, 12, 10, 2, 4, 12, 2,
        14, 12, 4, 6, 14, 4, 8, 14, 6, 0, 8, 6,
        12, 14, 8, 10, 12, 8, 2, 0, 6, 4, 2, 6
       ;


       vec3 vertexArray[] = 
        vec3(-0.5f, -0.5f, -0.5f),  vec3(-0.408248, -0.816497, -0.408248),
        vec3(0.5f, -0.5f, -0.5f),    vec3(0.666667, -0.333333, -0.666667),
        vec3(0.5f, 0.5f, -0.5f),    vec3(0.408248, 0.816497, -0.408248),
        vec3(-0.5f, 0.5f, -0.5f),   vec3(-0.666667, 0.333333, -0.666667),
        vec3(-0.5f, -0.5f, 0.5f),    vec3(-0.666667, -0.333333, 0.666667),
        vec3(0.5f, -0.5f, 0.5f),     vec3(0.666667, -0.666667, 0.333333),
        vec3(0.5f, 0.5f, 0.5f),     vec3(0.408248, 0.408248, 0.816497),
        vec3(-0.5f, 0.5f, 0.5f),    vec3(-0.408248, 0.816497, 0.408248),
       ;

        // convert arrays to vectors
        std::vector<vec3> vertexArrayVector;
        vertexArrayVector.insert(vertexArrayVector.begin(), std::begin(vertexArray), std::end(vertexArray));

        std::vector<unsigned int> indicesVector;
        indicesVector.insert(indicesVector.begin(), std::begin(indices), std::end(indices));

我现在想将纹理应用到立方体,但我不确定在使用索引时如何为 UV 添加 vec2 的使用。如果有帮助,我会创建这样的 VBO 和 VAO:

GLuint vertexBufferObject;
    GLuint indexBufferObject;
    GLuint vertexArrayObject;
    glGenVertexArrays(1, &vertexArrayObject);
    glGenBuffers(1, &indexBufferObject);
    glGenBuffers(1, &vertexBufferObject);

    glBindVertexArray(vertexArrayObject);


    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObject);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndicesArray[0]) * vertexIndicesArray.size(), &vertexIndicesArray[0], GL_STATIC_DRAW);

    // Upload Vertex Buffer to the GPU, keep a reference to it (vertexBufferObject)

    glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexPointsArray[0]) * vertexPointsArray.size(), &vertexPointsArray[0], GL_STATIC_DRAW);

    // Teach GPU how to read position data from vertexBufferObject
    glVertexAttribPointer(0,                   // attribute 0 matches aPos in Vertex Shader
        3,                   // size
        GL_FLOAT,            // type
        GL_FALSE,            // normalized?
        0,                   // 0 stride
        (void*)0              // array buffer offset
    );
    glEnableVertexAttribArray(0);

    // Teach GPU how to read normals data from vertexBufferObject
    glVertexAttribPointer(1,                            // attribute 1 matches normals in Vertex Shader
        3,
        GL_FLOAT,
        GL_FALSE,
        0,
        (void*)sizeof(glm::vec3)      // normal is offseted a vec3 (comes after position)
    );
    glEnableVertexAttribArray(1);

【问题讨论】:

【参考方案1】:

具有 5 个分量(x、y、z、u、v)的元组的顶点坐标和纹理坐标。如果您有一个由面共享但与不同纹理坐标相关联的顶点坐标,则需要复制一个顶点坐标。您必须为网格中所需的每个顶点坐标和纹理坐标组合指定 1 个属性元组。 不能为顶点坐标和纹理坐标指定不同的索引。请参阅Rendering meshes with multiple indices 和Why does OpenGL not support multiple index buffering?。

【讨论】:

以上是关于使用索引时如何为 UV 添加 vec2 以进行纹理映射的主要内容,如果未能解决你的问题,请参考以下文章

[OpenGL] 纹理高级篇 - flowmap的原理

如何在 webgl 中使用 uv 纹理包裹空间以制作黑洞

更改纹理大小时是不是必须重新映射 UV?

Unity里的UV到底是什么

从 DensePose 输出创建 UV 纹理贴图

加入不和谐服务器时如何为特定成员添加角色