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

OpenGL延迟像素化照明

李谦
2023-03-14

我正在为体素游戏开发一个3通道延迟照明系统,但是我在像素化照明和环境遮挡方面有问题。

第一阶段将屏幕上每个像素的颜色、位置和法线渲染成单独的纹理。这部分工作正常:

第二个着色器为屏幕上的每个像素计算环境光遮挡值,并将其渲染为纹理。此部分工作不正常,已像素化:

原始遮挡数据:

第三个着色器使用颜色、位置、法线和遮挡纹理将游戏场景渲染到屏幕上。这一阶段的照明也是像素化的:

SSAO(第二遍)片段着色器来自www. LearnOpenGL. com屏幕空间环境遮挡教程:

out float FragColor;

layout (binding = 0) uniform sampler2D gPosition; // World space position
layout (binding = 1) uniform sampler2D gNormal; // Normalised normal values
layout (binding = 2) uniform sampler2D texNoise;

uniform vec3 samples[64]; // 64 random precalculated vectors (-0.1 to 0.1 magnitude)
uniform mat4 projection;

float kernelSize = 64;
float radius = 1.5;

in vec2 TexCoords;

const vec2 noiseScale = vec2(1600.0/4.0, 900.0/4.0);

void main()
{
    vec4 n = texture(gNormal, TexCoords);

    // The alpha value of the normal is used to determine whether to apply SSAO to this pixel
    if (int(n.a) > 0)
    {
        vec3 normal = normalize(n.rgb);
        vec3 fragPos = texture(gPosition, TexCoords).xyz;
        vec3 randomVec = normalize(texture(texNoise, TexCoords * noiseScale).xyz);

        // Some maths. I don't understand this bit, it's from www.learnopengl.com
        vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
        vec3 bitangent = cross(normal, tangent);
        mat3 TBN = mat3(tangent, bitangent, normal);

        float occlusion = 0.0;

        // Test 64 points around the pixel
        for (int i = 0; i < kernelSize; i++)
        {
            vec3 sam = fragPos + TBN * samples[i] * radius;

            vec4 offset = projection * vec4(sam, 1.0);
            offset.xyz = (offset.xyz / offset.w) * 0.5 + 0.5;

            // If the normal's are different, increase the occlusion value
            float l = length(normal - texture(gNormal, offset.xy).rgb);
            occlusion += l * 0.3;
        }

        occlusion = 1 - (occlusion / kernelSize);
        FragColor = occlusion;
    }
}

照明和最终片段着色器:

out vec4 FragColor;

in vec2 texCoords;

layout (binding = 0) uniform sampler2D gColor; // Colour of each pixel
layout (binding = 1) uniform sampler2D gPosition; // World-space position of each pixel
layout (binding = 2) uniform sampler2D gNormal; // Normalised normal of each pixel
layout (binding = 3) uniform sampler2D gSSAO; // Red channel contains occlusion value of each pixel

// Each of these textures are 300 wide and 2 tall.
// The first row contains light positions. The second row contains light colours.

uniform sampler2D playerLightData; // Directional lights
uniform sampler2D mapLightData; // Spherical lights

uniform float worldBrightness;

// Amount of player and map lights
uniform float playerLights;
uniform float mapLights;

void main()
{
    vec4 n = texture(gNormal, texCoords);

    // BlockData: a = 4
    // ModelData: a = 2
    // SkyboxData: a = 0;

    // Don't do lighting calculations on the skybox
    if (int(n.a) > 0)
    {
        vec3 Normal = n.rgb;
        vec3 FragPos = texture(gPosition, texCoords).rgb;
        vec3 Albedo = texture(gColor, texCoords).rgb;

        vec3 lighting = Albedo * worldBrightness * texture(gSSAO, texCoords).r;

        for (int i = 0; i < playerLights; i++)
        {
            vec3 pos = texelFetch(playerLightData, ivec2(i, 0), 0).rgb;

            vec3 direction = pos - FragPos;
            float l = length(direction);

            if (l < 40)
            {
                // Direction of the light to the position
                vec3 spotDir = normalize(direction);

                // Angle of the cone of the light
                float angle = dot(spotDir, -normalize(texelFetch(playerLightData, ivec2(i, 1), 0).rgb));

                // Crop the cone
                if (angle >= 0.95)
                {
                    float fade = (angle - 0.95) * 40;
                    lighting += (40.0 - l) / 40.0 * max(dot(Normal, spotDir), 0.0) * Albedo * fade;
                }
            }
        }

        for (int i = 0; i < mapLights; i++)
        {
            // Compare this pixel's position with the light's position
            vec3 difference = texelFetch(mapLightData, ivec2(i, 0), 0).rgb - FragPos;
            float l = length(difference);

            if (l < 7.0)
            {
                lighting += (7.0 - l) / 7.0 * max(dot(Normal, normalize(difference)), 0.0) * Albedo * texelFetch(mapLightData, ivec2(i, 1), 0).rgb;
            } 
        }

        FragColor = vec4(lighting, 1.0);
    }
    else
    {
        FragColor = vec4(texture(gColor, texCoords).rgb, 1.0);
    }
}

游戏中每个方块的大小是1x1(世界空间大小)。我试着把这些面分成更小的三角形,如下所示,但是没有太大的明显差异。

如何提高照明和SSAO数据的分辨率以减少这些像素化的伪影?提前谢谢你

共有1个答案

濮阳俊明
2023-03-14

好消息!多亏了GameDev stack exchange的一些升级,我能够通过将位置缓冲区的分辨率从GL_RGBA16F升级到GL_RGBA32F来解决这个问题。

以下是他的答案。

 类似资料:
  • 问题内容: 我有一个输入,可以根据更改过滤ng-repeat列表。重复数据包含大量数据,并且需要花费几秒钟来过滤所有内容。我希望他们在开始过滤过程之前有0.5秒的延迟。 产生延迟的正确方法是什么? 输入项 重复 过滤功能 谢谢 问题答案: AngularJS 1.3+ 从AngularJS 1.3开始,您可以利用提供的属性轻松实现这一点,而无需使用。这是一个例子: HTML: JS: - 要么 -

  • 问题内容: 我正在尝试使用新的React Lazy和Suspense创建后备加载组件。这很好用,但后备时间仅显示几毫秒。有没有办法增加额外的延迟或最短时间,因此我可以在渲染下一个组件之前显示该组件的动画? 现在懒导入 等待组件: 我可以做这样的事情吗? 问题答案: 函数应该返回对象的承诺,该对象由具有默认导出功能的模块返回。不会返回承诺,也不能那样使用。尽管任意承诺可以: 如果目标是提供 最小的

  • 7.4.4 延迟初始化的bean 默认情况下,ApplicationContext实现在初始化过程中随即创建和配置所有单例bean。一般来说,这种预实例化是可取的,因为可以立即发现配置或周围环境中的错误,而不是在几个小时甚至几天以后。当这种行为不可取时,可以通过将bean定义标记为延迟初始化来阻止预实例化。延迟初始化的bean告诉IoC容器,当bean首次被请求时而不是在启动时创建一个实例。 在X

  • 问题内容: 我正在开发一个eshop。在基于类别的产品页面上,我放置了一些基于javascript的过滤器。但是,如果类别具有很多产品,则会出现问题。该链接具有与我相似的功能… 这个页面多么缓慢,却超过2mb !!! 对我来说,每个产品都需要一半的K字节,但是图像是个问题。.因此,我正在寻找如何延迟加载图像的方法。由于与该网站不同,我的页面具有分页功能,因此我认为加载仅对页面可见的图像是一种解决方

  • 问题内容: 在我的应用程序中,我需要从URL下载很多图片并将其显示在gridView中。(可以在1-200张照片之间)。我不想一次下载所有图片。我读到了关于延迟下载的信息,我的问题是:我只能得到Json的一部分,以其他线程下载图片, 并且只有当用户向下滚动 gridView时,我才继续到Json的其他部分,并且等等吗? 编辑:再次嗨。我想在此gridView中实现多选,而我很难在适配器的getVi

  • 我们的网站通过Netscaler运行,我们已经激活了图像的延迟加载。我试图了解它的功能,以及它是否可以以任何方式控制。例如,如果可以将特定图像设置为非延迟加载。但是我找不到关于它的具体实现的任何东西,只找到描述如何激活它的文章。 如果我理解正确,它就像经典的基于js的lazyloading一样,通过添加类lazy并将src移动到数据原始属性来转换imagetags。然后,当滚动到视图中时,java