OpenGL:地形未绘制(高度图)

3

编辑:我想问题可能出现在加载顶点和索引时。可能应该重点关注这一部分 :)

我正在尝试从bmp文件中加载高度图,并在OpenGL中显示它。像我尝试的大多数事情一样,一切都编译并运行没有错误,但屏幕上没有任何东西被绘制。我似乎无法很好地隔离问题,因为所有代码都可以单独工作,但当组合在一起绘制地形时,什么都不起作用。

地形类

我有一个地形类。它有2个VBO、1个IBO和1个VAO。它还存储了顶点、索引、顶点颜色和高度。它是从bmp文件加载的。

加载地形:

Terrain* Terrain::loadTerrain(const std::string& filename, float height)
{
    BitMap* bmp = BitMap::load(filename);
    Terrain* t = new Terrain(bmp->width, bmp->length);
    for(unsigned y = 0; y < bmp->length; y++)
    {
        for(unsigned x = 0; x < bmp->width; x++)
        {
            unsigned char color =
                (unsigned char)bmp->pixels[3 * (y * bmp->width + x)];
            float h = height * ((color / 255.0f) - 0.5f);
            t->setHeight(x, y, h);
        }
    }
    delete bmp;
    t->initGL();
    return t;
}

初始化缓冲区:

void Terrain::initGL()
{
    // load vertices from heights data
    vertices = new Vector4f[w * l];
    int vertIndex = 0;
    for(unsigned y = 0; y < l; y++)
    {
        for(unsigned x = 0; x < w; x++)
        {
            vertices[vertIndex++] = Vector4f((float)x, (float)y, heights[y][x], 1.0f);
        }
    }

    // generate indices for indexed drawing
    indices = new GLshort[(w - 1) * (l - 1) * 6]; // patch count * 6 (2 triangles per terrain patch)
    int indicesIndex = 0;
    for(unsigned y = 0; y < (l - 1); ++y)
    {
        for(unsigned x = 0; x < (w - 1); ++x)
        {
            int start = y * w + x;
            indices[indicesIndex++] = (GLshort)start;
            indices[indicesIndex++] = (GLshort)(start + 1);
            indices[indicesIndex++] = (GLshort)(start + w);

            indices[indicesIndex++] = (GLshort)(start + 1);
            indices[indicesIndex++] = (GLshort)(start + 1 + w);
            indices[indicesIndex++] = (GLshort)(start + w);
        }
    }

    // generate colours for the vertices
    colours = new Vector4f[w * l];
    for(unsigned i = 0; i < w * l; i++)
    {
        colours[i] = Vector4f(0.0f, 1.0f, 0.0f, 1.0f); // let's make the entire terrain green
    }

    // THIS CODE WORKS FOR CUBES (BEGIN)

    // vertex buffer object
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // index buffer object
    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    // colours vertex buffer object
    glGenBuffers(1, &colour_vbo);
    glBindBuffer(GL_ARRAY_BUFFER, colour_vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(colours), colours, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // create vertex array object
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, colour_vbo);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    glBindVertexArray(0);

    // THIS CODE WORKS FOR CUBES (END)
}

我创建VBO、IBO和VAO的部分对于立方体来说工作正常,它们被很好地绘制出来。

渲染地形:

void Terrain::render()
{
    glUseProgram(shaderProgram);

    glBindVertexArray(vao);
    int indices_length = (w - 1) * (l - 1) * 6;
    glDrawElements(GL_TRIANGLES, indices_length, GL_UNSIGNED_SHORT, 0);
}

着色器

这些是顶点和片段着色器。

顶点:

#version 330

layout (location = 0) in vec4 position;
layout (location = 1) in vec4 vertexColour;

out vec4 fragmentColour;

uniform vec3 offset;
uniform mat4 perspectiveMatrix;

void main()
{
    vec4 cameraPos = position + vec4(offset.x, offset.y, offset.z, 0.0);

    gl_Position = perspectiveMatrix * cameraPos;

    fragmentColour = vertexColour;
}

碎片:

#version 330

in vec4 fragmentColour;

out vec4 outputColour;

void main()
{
    outputColour = fragmentColour;
}

透视矩阵

这里是“相机”的设置:

struct CameraSettings
{
    static const float FRUSTUM_SCALE = 1.0f;
    static const float Z_NEAR = 0.5f;
    static const float Z_FAR = 3.0f;

    static float perspective_matrix[16];
};

float CameraSettings::perspective_matrix[16] = {
    FRUSTUM_SCALE,
        0, 0, 0, 0,
        FRUSTUM_SCALE,
        0, 0, 0, 0,
        (Z_FAR + Z_NEAR) / (Z_NEAR - Z_FAR),
        -1.0f,
        0, 0,
        (2 * Z_FAR * Z_NEAR) / (Z_NEAR - Z_FAR),
        0
};

在调用initGL()之后填充制服:

// get offset uniform
    offsetUniform = ShaderManager::getUniformLocation(shaderProgram, "offset");
    perspectiveMatrixUniform = ShaderManager::getUniformLocation(shaderProgram, "perspectiveMatrix");

    // set standard uniform data
    glUseProgram(shaderProgram);
    glUniform3f(offsetUniform, xOffset, yOffset, zOffset);
    glUniformMatrix4fv(perspectiveMatrixUniform, 1, GL_FALSE, CameraSettings::perspective_matrix);
    glUseProgram(0);

有人可以检查我的代码并提出建议吗?


你能把所有高度设置为“0”并查看发生了什么吗?背面剔除是否已启用?也许你的三角形顶点顺序有误? - Nico Schertler
我已经尝试过启用和禁用背面剔除,但结果相同。将所有高度设置为0也没有任何效果。 - RaptorDotCpp
1
在顶点着色器中,你不应该使用模型视图矩阵来转换顶点吗? - Nico Schertler
@NicoSchertler 我会这样做并回报 :) - RaptorDotCpp
我明白,@BartekBanachewicz。我不是让你帮我调试代码。我只是想把我的代码完整地呈现给你。我个人认为问题出在某个特定的部分,所以我想请你关注那一部分。我只是想提供一个完整的画面。 - RaptorDotCpp
显示剩余4条评论
1个回答

4

我相信当你说:

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

你实际上想说:

    glBufferData(GL_ARRAY_BUFFER, sizeof (Vector4f) * w * l, vertices, GL_STATIC_DRAW);

(同颜色缓冲区等)


是的。否则,您只需发送指针的大小(4个字节)。 - Grimmy
当然可以!解引用顶点也能起作用吗?sizeof(*vertices)?只是出于好奇。 - RaptorDotCpp
1
sizeof(*vertices) == sizeof(Vector4f) - gmarkou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接