如何修复地形纹理?

How to fix texturing a terrain?

我编写了一个由三角形组成的平坦地形,但似乎出现了一些镜像。我想让它模仿草,但有些地方很模糊。我需要在 glTexParameteri 中添加一些参数吗?或者可能是与绘图代码相关的错误?

读取纹理的函数:

GLuint Terrain::write_model_texture(const char* filename)
{

    GLuint tex;
    // Activate texture 0
    glActiveTexture(GL_TEXTURE0);

    // Read into computers memory
    std::vector<unsigned char> image;
    unsigned width, height;

    // Read the image
    unsigned error = lodepng::decode(image, width, height, filename);

    // Import to graphics card memory
    glGenTextures(1, &tex);                     //Initialize one handle
    glBindTexture(GL_TEXTURE_2D, tex); //Activate handle

    // Copy image to graphics cards memory represented by the active handle
    glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
        GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)image.data());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    return tex;
}

还有绘制三角形的代码:

this->P = glm::mat4(1.0f);
    this->V = glm::mat4(1.0f);
    this->M = glm::mat4(1.0f);

    P = in.P;
    V = in.V;

    
    //M = glm::rotate(M, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
    M = glm::translate(M, glm::vec3(-5.0f, -5.0f, 0.0f));
    //M = glm::scale(M, glm::vec3(10.0f, 10.0f, 10.0f));
    
    for (int row = 0; row < terrain_height; row++)
    {
        int col;
        // adding a row of vertices
        for (col = 0; col < terrain_width; col++) {
            // x, y, z, 1
            
            //std::cout << random_num << std::endl;
            terrain_verts.emplace_back(col, row, 0, 1);
            terrain_norms.emplace_back(0.0f, 0.0f, 1.0f, 0);
        }

        // adding a row of indices
        for (col = 0; col < terrain_width; col++)
        {
            terrain_indices.emplace_back(col + row * terrain_width);
            terrain_indices.emplace_back(col + row * terrain_width + 1);
            terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
        }

        for (col = terrain_width - 1; col >= 0; col--)
        {
            terrain_indices.emplace_back(col + row * terrain_width);
            terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
            terrain_indices.emplace_back(col + terrain_width * (row + 1));
        }

        // adding a row of texture coordinates
        if (row % 2 == 0)
        {
            for (col = 0; col < terrain_width; col += 2)
            {
                terrain_texture_coordinates.emplace_back(0, 0);
                terrain_texture_coordinates.emplace_back(1, 0);
            }
            
        }
        else
        {
            for (col = 0; col < terrain_width; col += 2)
            {
                terrain_texture_coordinates.emplace_back(0, 1);
                terrain_texture_coordinates.emplace_back(1, 1);

            }
        }
    }

    spTextured->use();
    glUniformMatrix4fv(spTextured->u("P"), 1, false, glm::value_ptr(P));
    glUniformMatrix4fv(spTextured->u("V"), 1, false, glm::value_ptr(V));
    glEnableVertexAttribArray(spTextured->a("vertex"));
    glEnableVertexAttribArray(spTextured->a("texCoord"));
    glEnableVertexAttribArray(spTextured->a("normal"));

    glUniformMatrix4fv(spTextured->u("M"), 1, false, glm::value_ptr(M));

    glVertexAttribPointer(spTextured->a("vertex"), 4, GL_FLOAT, false, 0, terrain_verts.data());
    glVertexAttribPointer(spTextured->a("texCoord"), 2, GL_FLOAT, false, 0, terrain_texture_coordinates.data());
    glVertexAttribPointer(spTextured->a("normal"), 4, GL_FLOAT, false, 0, terrain_norms.data());

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);
    glUniform1i(spTextured->u("tex"), 0);

    glDrawElements(GL_TRIANGLES, terrain_indices_count(), GL_UNSIGNED_INT, terrain_indices.data());

    
    glDisableVertexAttribArray(spTextured->a("vertex"));
    glDisableVertexAttribArray(spTextured->a("color"));
    glDisableVertexAttribArray(spTextured->a("normal"));

你的指数没有任何意义:

for (col = 0; col < terrain_width; col++)
{
    terrain_indices.emplace_back(col + row * terrain_width);
    terrain_indices.emplace_back(col + row * terrain_width + 1);
    terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}

for (col = terrain_width - 1; col >= 0; col--)
{
    terrain_indices.emplace_back(col + row * terrain_width);
    terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
    terrain_indices.emplace_back(col + terrain_width * (row + 1));
}

如果您查看数据网格:

row = 0:  0 --- 1 --- 2 --- 3
          |     |     |     |
          |     |     |     |
row = 1:  4 --- 5 --- 6 ----7

          ^     ^     ^     ^
         col=0  1     2     3  

对于第 0 行第 0 列,您生成两个具有以下顶点的三角形:

  1. 0, 1, 3 是面积为零的变形三角形
  2. 0, 3, 4 完全穿过您的网格:

对于行=0、列=1 等内部单元格,您得到:

  1. 1, 2, 4 跨越 2 个网格单元
  2. 1, 4, 5 至少属于一个网格单元(虽然不是它应该的那个)

您实际上可以在屏幕截图中看到这些图案,您只需要考虑到您绘制了很多奇怪的重叠三角形。

你的 tex 坐标也不会那样工作。您可以像这样为交替行生成 tex 坐标:

row = 0:  (0,0) --- (1,0) 
            |         |
            |         |
row = 1:  (0,1) --- (1,1)
            |         |
            |         |
row = 2:  (0,0) --- (1,0)

如果您以这种方式映射纹理坐标,则第 1 行和第 2 行之间的单元格的图像将垂直镜像到第 0 行和第 1 行之间的单元格。您不能共享下方网格单元格的行顶点和以这种方式在其上方,您将必须使用不同的纹理坐标复制行顶点才能使其工作。

但是,这不是必需的,因为您可以使用 GL_REPEAT 纹理环绕模式,只需使用 [0,1] 范围之外的纹理坐标,例如:

row = 0:  (0,0) --- (1,0) --- (2,0)
            |         |         |
            |         |         |
row = 1:  (0,1) --- (1,1) --- (2,1)
            |         |         |
            |         |         |
row = 2:  (0,2) --- (1,2) --- (2,2)