使用帧缓冲区写入 3D 纹理并另存为图像

Writing to a 3D Texture Using Framebuffers and Saving as Image

我正在尝试为某些体积效果生成 3D worley 噪声纹理。我只是生成一组随机点,对于每个片段,我会找到最近的点并获得片段和像素之间的距离。然后将距离用作图像的最终颜色。结果在 2D 中看起来像这样:

这在我生成 2D 纹理时效果很好。在尝试生成 3D 纹理时,我开始 运行 遇到一些问题。

现在我将 3D 纹理的每个切片附加为颜色附件并使用着色器写入它。我的代码如下:

产生噪声的函数(注:这段代码假设宽高深都相等):

    void WorleyGenerator::GenerateWorley3D(int numPoints, Texture3D* texture, PrimitiveShape* quad, unsigned int nativeWidth, unsigned int nativeHeight)
{
    int resolution = texture->GetWidth();
    glViewport(0, 0, resolution, resolution);
    glDisable(GL_CULL_FACE);

    frameBuffer->Bind();
    shader3D->Bind();

    shader3D->SetFloat("uResolution", resolution);
    shader3D->SetInt("uNumWorleyPoints", numPoints); // Tell shader how many points we have

    // Generate random points and pass them ot shader
    for (int i = 0; i < numPoints; i++)
    {
        shader3D->SetFloat3("uPointData[" + std::to_string(i) + "]", glm::vec3(Utils::RandInt(0, resolution), Utils::RandInt(0, resolution), Utils::RandInt(0, resolution)));
    }

    // Render to each "slice" of the texture
    for (int z = 0; z < resolution; z++)
    {
        shader3D->SetInt("uCurrentSlice", z);
        glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture->GetID(), 0, z);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        quad->Draw();
    }

    frameBuffer->Unbind();

    glViewport(0, 0, nativeWidth, nativeHeight);
}

我的片段着色器:

#version 420 

in vec2 mTextureCoordinates;

out vec4 oColor;

uniform int uCurrentSlice;
uniform float uResolution;
uniform int uNumWorleyPoints;
uniform vec3 uPointData[256];

void main()
{
    vec3 fragPos = vec3(gl_FragCoord.xy, uCurrentSlice) / uResolution; // Convert frag pos to range 0 - 1

    // Find closest point's distance
    float closestDist = 100000.0f;

    // Get closest point for red channel
    for (int i = 0; i < uNumWorleyPoints; i++)
    {
        vec3 p = uPointData[i] / uResolution; // Convert point to range 0 - 1

        float dist = distance(fragPos, p);
        if (dist < closestDist)
        {
            closestDist = dist;
        }
    }

    oColor = vec4(closestDist, closestDist, closestDist, 1.0f);
}

现在要测试我的代码,我会将 3D 纹理的每个切片保存到 BMP 文件中:

void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
    unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
    float* data = new float[size];
    for (int z = 0; z < texture->GetDepth(); z++)
    {
        glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
        stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
    }

    delete[] data;
}

保存图像的结果如下所示:

此外,每个切片都完全相同,这是不应该发生的。

我怀疑我没有正确地写入切片,或者我保存图像的代码有误。

如有任何帮助,我们将不胜感激!

我的问题不在于纹理,而在于我如何保存图像。我改变了我的纹理保存功能:

void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
    unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
    float* data = new float[size];
    for (int z = 0; z < texture->GetDepth(); z++)
    {
        glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), z, GL_RGBA16F, GL_FLOAT, size, data);
        stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
    }

    delete[] data;
}

为此:

void Utils::SaveTexture3DAsBMP(const std::string& savePath, Texture3D* texture)
{
    unsigned int size = texture->GetWidth() * texture->GetHeight() * 4;
    uint8_t* data = new uint8_t[size];

    for (int z = 0; z < texture->GetDepth(); z++)
    {
        glGetTextureSubImage(texture->GetID(), 0, 0, 0, z, texture->GetWidth(), texture->GetHeight(), 1, GL_RGBA, GL_UNSIGNED_BYTE, size, data);
        stbi_write_bmp((savePath + std::to_string(z) + ".bmp").c_str(), texture->GetWidth(), texture->GetHeight(), 4, data);
    }

    delete[] data;
}