从HDRi LatLong地图直接渲染到浮点立方体贴图 - 而不是HDR

时间:2016-10-10 20:01:50

标签: c++ opengl floating-point hdr

我将HDR辐射环境贴图作为LatLong 2D纹理图像,我想将其转换为立方体贴图。我这样做是通过将HDR地图加载为2D浮动纹理,将其投影到立方体上,然后从6个不同方向渲染此立方体内的场景,直接填充带有glFramebufferTexture2D的立方体贴图,其中相应的立方体贴图面作为函数的纹理目标。

生成的立方体贴图是按如下方式生成的浮点立方体贴图:

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

for (unsigned int i = 0; i < 6; ++i)
{
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, NULL);
}
if (mipmap)
    glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

请注意,type参数为GL_FLOAT,因此它应该正确接受HDR值。使用stb_image.h加载HDR图像,如下所示:

if (stbi_is_hdr(path.c_str()))
{
    stbi_set_flip_vertically_on_load(true);

    int width, height, nrComponents;
    float *data = stbi_loadf(path.c_str(), &width, &height, &nrComponents, 0);
    if (data)
    {
        GLenum format;
        if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        Bind();
            glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_FLOAT, data);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            if (Mipmapping)
                glGenerateMipmap(GL_TEXTURE_2D);
        Unbind();
        stbi_image_free(data);
    }
}

我也尝试迭代这个数组并检索最大浮点值以查看HDR是否正确加载并且当前HDR地图的最高浮点值是288,远远高于1.0我{期待。

根据输入纹理(HDR浮点图)和输出立方体贴图(作为浮点数),事情变得棘手,我希望立方体贴图面被正确地视为浮点纹理并直接复制HDR值。然而,立方体贴图出现LDR,因为我添加色调映射的时刻(带有可变曝光)我得到了相当多的条带,我显然错过了HDR的精度,如下图所示(曝光量为~7.5)< / p>

LDR image of what should be HDR

我不确定是否有一些我遗漏的东西,我在OpenGL的文档中找不到关于直接渲染到浮点帧缓冲区的文档;我认为这是可能的,因为如果不是这样就没有意义。

为了完整起见,以下是从LatLong图像生成立方体贴图的相关代码(renderCustomCommand使用适当的采样器设置渲染立方体):

glGenFramebuffers(1, &m_FramebufferCubemap);
glGenRenderbuffers(1, &m_CubemapDepthRBO);

Camera faceCameras[6] = {
    Camera(position, vec3( 1.0f,  0.0f,  0.0f), vec3(0.0f, -1.0f,  0.0f)),
    Camera(position, vec3(-1.0f,  0.0f,  0.0f), vec3(0.0f, -1.0f,  0.0f)),
    Camera(position, vec3( 0.0f,  1.0f,  0.0f), vec3(0.0f,  0.0f,  1.0f)),
    Camera(position, vec3( 0.0f, -1.0f,  0.0f), vec3(0.0f,  0.0f,- 1.0f)),
    Camera(position, vec3( 0.0f,  0.0f,  1.0f), vec3(0.0f, -1.0f,  0.0f)),
    Camera(position, vec3( 0.0f,  0.0f, -1.0f), vec3(0.0f, -1.0f,  0.0f))
};

glBindFramebuffer(GL_FRAMEBUFFER, m_FramebufferCubemap);
glBindRenderbuffer(GL_RENDERBUFFER, m_CubemapDepthRBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_CubemapDepthRBO);

glViewport(0, 0, width, height);
glBindFramebuffer(GL_FRAMEBUFFER, m_FramebufferCubemap);

for (unsigned int i = 0; i < 6; ++i)
{
    Camera *camera = &faceCameras[i];
    camera->SetPerspective(90.0f, width/height, 0.1f, 100.0f);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubeTarget->ID, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    for (unsigned int i = 0; i < renderCommands.size(); ++i)
    {
        renderCustomCommand(&renderCommands[i], camera);
    }
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, m_RenderSize.x, m_RenderSize.y);

以下是LatLong 2D图像的采样代码 - &gt;立方体:

#version 330 core
out vec4 FragColor;
in vec3 wPos;

#include sample.glsl

uniform sampler2D environment;

void main()
{
    vec2 uv = SampleLatLong(normalize(wPos));
    vec3 color = texture(environment, uv).rgb;
    FragColor = vec4(color, 1.0);
}

请注意,LatLong到Cubemap的转换效果很好,因为2D环境在立方体贴图上正确渲染,但只是在它作为天空盒渲染时被固定到[0,1]范围,就好像它在整个过程中的某个地方一样丢失了浮点数据。

我一直坚持这个问题已经有一段时间了,希望你们中的任何一个人能够有所了解(甚至可以直接渲染浮动立方体贴图这样吗?)。谢谢。

编辑:以下是Photoshop中高曝光设置的相同照片,因为您可以看到我在渲染器中丢失了很多细节。

HDR image from Photoshop with high exposure

1 个答案:

答案 0 :(得分:1)

glTexImage2D调用的第三个参数需要是GL_RGB16F或GL_RGB32F。 它指定内部格式。

末尾的两个参数GL_RGB和GL_FLOAT仅用于指定可选数据指针的内存布局。它们不会影响内部格式。