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

vktxenjb  于 2022-11-04  发布在  其他
关注(0)|答案(1)|浏览(192)

我正在尝试为一些体积效果生成一个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;
}

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

而且,每个切片都是完全相同的,这是永远不应该发生的。
我怀疑我没有正确地写入切片,或者我保存图像的代码是错误的。
任何帮助都将不胜感激!

yxyvkwin

yxyvkwin1#

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

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;
}

相关问题