You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenGL通过三角形绘制平整平面时索引错误如何修复

OpenGL平面生成问题修复方案

参考图

  • 期望的索引绘制顺序:
    期望的索引绘制顺序
  • 实际错误渲染结果:
    实际得到的渲染结果

现存问题梳理

  1. 顶点生成不全:每行顶点的循环上限设为了terrain_width-1,导致每行少生成1个顶点,和索引计算的预期顶点数不匹配
  2. 索引越界+计算错误:
    • 行循环上限设为了terrain_height,处理最后一行时访问row+1的顶点会越界
    • 三角形索引的计算逻辑完全不符合网格四边形拆分规则,导致索引指向错误的顶点
  3. 容器未清空:每次调用绘制函数都会向顶点、索引、纹理坐标容器追加数据,多次调用后数据冗余错乱
  4. 法向量未初始化:绑定了法向量属性指针,但没有往法向量容器中写入任何有效数据
  5. 属性禁用错误:最后禁用了从未启用的color属性,反而没有禁用启用过的texCoord属性

修改后的代码

void Terrain::draw_terrain(const Input& in)
{
    // 每次绘制前先清空原有数据,避免重复追加
    terrain_verts.clear();
    terrain_indices.clear();
    terrain_texture_coordinates.clear();
    terrain_norms.clear();

    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::scale(M, glm::vec3(1.0f, 1.0f, 1.0f));
    // 先生成所有顶点、法向量、纹理坐标
    for (int row = 0; row < terrain_height; row++)
    {
        int col;
        // 修改:循环到terrain_width,生成每行所有顶点
        for (col = 0; col < terrain_width; col++) {
            // x, y, z, 1
            terrain_verts.emplace_back(col, row, 0.0f, 1);
            // 补充平面法向量,全部朝向z轴正方向
            terrain_norms.emplace_back(0.0f, 0.0f, 1.0f, 0.0f);
        }

        // 纹理坐标生成逻辑保留,按需调整即可
        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);
            }
        }
    }

    // 单独生成索引,行循环只到terrain_height-1,避免越界
    for (int row = 0; row < terrain_height - 1; row++)
    {
        int col;
        for (col = 0; col < terrain_width - 1; col++)
        {
            // 第一个三角形(对应你说的蓝色方向)
            terrain_indices.emplace_back(col + row * terrain_width); // 左上
            terrain_indices.emplace_back(col + row * terrain_width + 1); // 右上
            terrain_indices.emplace_back(col + (row + 1) * terrain_width); // 左下
            // 第二个三角形(对应你说的绿色方向)
            terrain_indices.emplace_back(col + row * terrain_width + 1); // 右上
            terrain_indices.emplace_back(col + (row + 1) * terrain_width + 1); // 右下
            terrain_indices.emplace_back(col + (row + 1) * terrain_width); // 左下
        }
    }

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

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

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

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

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

    // 修改:禁用正确的属性,移除不存在的color属性禁用
    glDisableVertexAttribArray(spLambertTextured->a("vertex"));
    glDisableVertexAttribArray(spLambertTextured->a("texCoord"));
    glDisableVertexAttribArray(spLambertTextured->a("normal"));
}

额外优化建议

如果你的地形尺寸是固定的,不需要每次绘制都重新生成顶点、索引和纹理坐标,完全可以把这部分逻辑移到初始化函数里只执行一次,绘制时直接复用数据即可,能大幅提升渲染性能。

内容的提问来源于stack exchange,提问作者code_rushh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:15:03