当前位置: 首页 > 知识库问答 >
问题:

从HDRi LatLong贴图直接渲染到浮点立方体贴图-非HDR

景恩
2023-03-14

我有一个HDR辐射环境贴图作为一个LatLong 2D纹理图像,我想将其转换为立方体贴图。为此,我将HDR贴图加载为2D float纹理,将其投影到立方体上,然后从6个不同的方向渲染该立方体内的场景,直接用glFramebufferTexture2D填充立方体贴图,并将相应的立方体贴图面作为函数的纹理目标。

生成的cubemap是按如下方式生成的浮点cubemap:

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\u FLOAT,因此应该正确接受HDR值。HDR图像使用stb\U图像加载。h如下所示:

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中设置了高曝光,你可以看到很多细节,我在渲染器中丢失了这些细节。

共有1个答案

尹英华
2023-03-14

glTexImage2D调用的第三个参数需要是GL\u RGB16F或GL\u RGB32F。它指定内部格式。

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

 类似资料:
  • 我们已经使用2D纹理很长时间了,但除此之外仍有更多的纹理类型等着我们探索。在本节中,我们将讨论的是将多个纹理组合起来映射到一张纹理上的一种纹理类型:立方体贴图(Cube Map)。 简单来说,立方体贴图就是一个包含了6个2D纹理的纹理,每个2D纹理都组成了立方体的一个面:一个有纹理的立方体。你可能会奇怪,这样一个立方体有什么用途呢?为什么要把6张纹理合并到一张纹理中,而不是直接使用6个单独的纹理呢

  • 在reactjs中,我试图从贴图对象渲染组件。更具体地说,按下一个按钮,我创建了一个新的“FormRow”组件,为了方便起见,我将其存储在javascript映射对象中(因为稍后我将使用它)。无论何时,我都想渲染刚刚添加的新组件,但我不知道如何从贴图中获取它。 我尝试以不同的方式解决我的问题,使用: myMap.for每个(key= 我没有尝试的是: https://stackoverflow.c

  • 我想将立方体贴图[图1]转换为等矩形全景图[图2]。 从球形到立方体是可能的(通过以下步骤:将2:1等矩形全景图转换为立方体贴图),但在如何反转它上迷失了方向。 使用Unity将图2渲染成一个球体。

  • 问题内容: 我正在使用LibGDX 0.9.9。我正在尝试渲染立方体贴图和雾。所以我的代码片段如下: 但是什么也没发生。我只看到对象。我究竟做错了什么? 问题答案: 花了一些时间后,我在LibGDX中实现了多维数据集映射。也许,这不是理想的解决方案,但仅此而已(至少我什么也找不到)。因此,我使用了本机OpenGL ES函数和LibGDX。我的课程如下: 如何使用它?只需创建它的实例: 要么 然后使

  • 有没有更好的方法来转换贴图

  • 我正在尝试使用mapbox创建多段线贴图,我能够正确地创建它。用户可以返回并在其配置文件中查看多段线地图。 疑问-是否有任何方法可以将我的lat long列表转换为某种格式并存储在db中,然后从db中获取并渲染贴图? 我也检查了geojson格式,但如果我们将geojson与mapbox一起使用,它将生成静态映射。 我使用flutter_map生成地图。 更新- 目前我正在使用flutter_ma