【问题标题】:Render from HDRi LatLong map directly to floating point cubemap - not HDR从 HDRi LatLong 贴图直接渲染到浮点立方体贴图 - 不是 HDR
【发布时间】:2017-02-19 07:48:13
【问题描述】:

我有一个 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);

请注意,类型参数是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)

我不确定我是否遗漏了一些东西,而且我在 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 图像进行采样的代码 -> 立方体:

#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 文件上推送曝光。 (在Photoshop或其他)。你有没有看到同样的文物。 Radiance 文件以 RGBE 编码。由于 RGB 共享相同的指数,因此您最终可能会因像素过亮或过暗而导致色彩质量差。此外,HDR 照片通常是从以不同曝光拍摄的同一张照片创建的。根据相机质量,低曝光版本的色彩质量也可能很差。
  • 第一个图像来自渲染器本身,来自浮点值,所以stb_image.h 已经将 RGBE 格式解码为浮点数。我还添加了一张从 Photoshop 中看到的高曝光图像,您确实可以看到以前使用默认曝光看不到的细节。
  • 好的。如果它不是源图像,它可能来自着色器。您是否在片段着色器中指定浮点精度。您可以尝试添加“precision highp float;”在片段着色器的开头。
  • 这是一个 OpenGL 程序,而不是 ES/WebGL,我认为浮点精度限定符与此无关。

标签: c++ opengl floating-point hdr


【解决方案1】:

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

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

【讨论】:

  • 就是这样!非常感谢!
猜你喜欢
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多