延迟着色和衰减 [英] Deferred Shading and attenuation

查看:200
本文介绍了延迟着色和衰减的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我在我的引擎中添加了延迟着色支持;但我遇到了一些衰减问题:



正如你所看到的,当我渲染光体积,它不能很好地与图像的环境部分混合!



这是我如何声明我的点光:

  PointLight指针; 
pointlight.SetPosition(glm :: vec3(0.0,6.0,0.0));
pointlight.SetIntensity(glm :: vec3(1.0f,1.0f,1.0f));

以下是我如何计算光球半径:

 衰减衰减= pointLights [i] .GetAttenuation(); 
float lightMax = std :: fmaxf(std :: fmax(pointLights [i] .GetIntensity()。r,pointLights [i] .GetIntensity().g),
pointLights [i] .GetIntensity ().b);

float pointLightRadius =(-attenuation.linear +
std :: sqrtf(std :: pow(attenuation.linear,2.0f) - 4.0f * attenuation.exponential *
(衰减常数 - (256.0f / 5.0f)* lightMax)))/(2.0f *衰减指数)。

最后,这里是我的PointLightPass片段着色器:

  #version 450 core 

struct BaseLight
{
vec3 intensityities; // aka color of light
float ambientCoeff;
};

struct Attenuation
{
float constant;
float linear;
float exponential;
};

struct PointLight
{
BaseLight base;
衰减衰减;
vec3 position;
};

struct Material
{
float shininess;
vec3 specularColor;
float ambientCoeff;
};


布局(std140)uniform视口
{
uniform mat4投影;
uniform mat4查看;
uniform mat4 ViewProjection;
uniform vec2 scrResolution;
};

layout(binding = 0)uniform sampler2D gPositionMap;
layout(binding = 1)uniform sampler2D gAlbedoMap;
layout(binding = 2)uniform samplinger2D gNormalMap;
layout(binding = 3)uniform sampler2D gSpecularMap;

uniform vec3 cameraPosition;
uniform PointLight pointLight;

out vec4 fragmentColor;

vec2 FetchTexCoord()
{
return gl_FragCoord.xy / scrResolution;
}

void main()
{
vec2 texCoord = FetchTexCoord();
vec3 gPosition = texture(gPositionMap,texCoord).xyz;
vec3 gSurfaceColor = texture(gAlbedoMap,texCoord).xyz;
vec3 gNormal = texture(gNormalMap,texCoord).xyz;
vec3 gSpecColor = texture(gSpecialMap,texCoord).xyz;
float gSpecPower = texture(gSpecularMap,texCoord).a;

vec3 totalLight = gSurfaceColor * 0.1; // TODO remove hardcoded ambient light
vec3 viewDir = normalize(cameraPosition - gPosition);

vec3 lightDir = normalize(pointLight.position - gPosition);
vec3 diffuse = max(dot(gNormal,lightDir),0.0f)* gSurfaceColor *
pointLight.base.intensities;

vec3 halfWayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(gNormal,halfWayDir),0.0f),1.0f);
vec3 specular = pointLight.base.intensities * spec / ** gSpecColor * /;

float distance = length(pointLight.position - gPosition);
float attenuation = 1.0f /(1.0f + pointLight.attenuation.linear * distance
+ pointLight.attenuation.exponential * distance * distance +
pointLight.attenuation.constant);



diffuse * = attenuation;
specular * = attenuation;
totalLight + = diffuse + specular;

fragmentColor = vec4(totalLight,1.0f);
}

那么,建议您处理这个问题?



编辑:以下是更多详细信息:



对于延迟着色,




  • 我填充了我的GBuffer;

  • 我做环境光通过,我用环境颜色渲染一个全屏四边形
    : p>

    #version 420核心

     布局(std140)uniform视口
    {
    uniform mat4投影;
    uniform mat4查看;
    uniform mat4 ViewProjection;
    uniform vec2 scrResolution;
    };

    layout(binding = 1)uniform sampler2D gAlbedoMap;
    out vec4 fragmentColor;

    vec2 FetchTexCoord()
    {
    return gl_FragCoord.xy / scrResolution;
    }

    void main()
    {
    vec2 texCoord = FetchTexCoord();
    vec3 gSurfaceColor = texture(gAlbedoMap,texCoord).xyz;

    vec3 totalLight = gSurfaceColor * 1.2; // TODO remove hardcoded ambient light
    fragmentColor = vec4(totalLight,1.0f);
    }




点光源(见上面的代码);

解决方案

你有这个问题的原因是,音量(一个事实,你在这个问题没有完全清楚,但是在您的其他问题)。



您正在使用正常的光衰减方程。好吧,你会注意到这个方程并不奇怪地停在某个任意半径。它定义为从0到无穷大的所有距离。



光量的目的是防止超过一定距离的照明贡献。那么,如果你的光衰减在那个距离没有变为零,那么你将看到在光量的边缘的不连续。



如果你'要使用光量,你需要使用光衰减方程,实际上保证在体积的边缘达到零。或者失败,你应该为你的体积选择一个半径,使光的衰减强度几乎为零。



保持半径更大,直到你不能告诉它为止。


Recently I added deferred shading support in my engine; however I ran into some attenuation issues:

As you can see, when I'm rendering the light volume (sphere), it doesn't blend nicely with the ambient part of the image !

Here is how I declare my point light:

PointLight pointlight;
pointlight.SetPosition(glm::vec3(0.0, 6.0, 0.0));
pointlight.SetIntensity(glm::vec3(1.0f, 1.0f, 1.0f));

Here is how I compute the light sphere radius:

Attenuation attenuation = pointLights[i].GetAttenuation();
    float lightMax = std::fmaxf(std::fmax(pointLights[i].GetIntensity().r, pointLights[i].GetIntensity().g),
        pointLights[i].GetIntensity().b);

    float pointLightRadius = (-attenuation.linear +
        std::sqrtf(std::pow(attenuation.linear, 2.0f) - 4.0f * attenuation.exponential *
            (attenuation.constant - (256.0f / 5.0f) * lightMax))) / (2.0f * attenuation.exponential);

And finally, here is my PointLightPass fragment shader:

#version 450 core

struct BaseLight
{
    vec3 intensities;//a.k.a color of light
    float ambientCoeff;
};

struct Attenuation
{
    float constant;
    float linear;
    float exponential;
};

struct PointLight
{
    BaseLight base;
    Attenuation attenuation;
    vec3 position;
};

struct Material
{
    float shininess;
    vec3  specularColor;
    float ambientCoeff;
};


layout (std140) uniform Viewport
{
    uniform mat4 Projection;
    uniform mat4 View;
    uniform mat4 ViewProjection;
    uniform vec2 scrResolution;
};

layout(binding = 0) uniform sampler2D gPositionMap;
layout(binding = 1) uniform sampler2D gAlbedoMap;
layout(binding = 2) uniform sampler2D gNormalMap;
layout(binding = 3) uniform sampler2D gSpecularMap;

uniform vec3 cameraPosition;
uniform PointLight pointLight;

out vec4 fragmentColor;

vec2 FetchTexCoord()
{
      return gl_FragCoord.xy / scrResolution;
}

void main()
{
      vec2 texCoord = FetchTexCoord();
      vec3 gPosition =      texture(gPositionMap, texCoord).xyz;
      vec3 gSurfaceColor =  texture(gAlbedoMap, texCoord).xyz;
      vec3 gNormal =        texture(gNormalMap, texCoord).xyz;
    vec3 gSpecColor =   texture(gSpecularMap, texCoord).xyz;
    float gSpecPower =  texture(gSpecularMap, texCoord).a;

    vec3 totalLight = gSurfaceColor * 0.1; //TODO remove hardcoded ambient light
    vec3 viewDir = normalize(cameraPosition - gPosition);

    vec3 lightDir = normalize(pointLight.position - gPosition);
    vec3 diffuse = max(dot(gNormal, lightDir), 0.0f) * gSurfaceColor *
                    pointLight.base.intensities;

    vec3 halfWayDir = normalize(lightDir + viewDir);
    float spec = pow(max(dot(gNormal, halfWayDir), 0.0f), 1.0f);
    vec3 specular = pointLight.base.intensities * spec /** gSpecColor*/;

    float distance = length(pointLight.position - gPosition);
    float attenuation = 1.0f / (1.0f + pointLight.attenuation.linear * distance
                    + pointLight.attenuation.exponential * distance * distance +
                     pointLight.attenuation.constant);



    diffuse *= attenuation;
    specular *= attenuation;
    totalLight += diffuse + specular;

    fragmentColor = vec4(totalLight, 1.0f);
}

So what can you suggest to deal with this issue ?

EDIT : Here are more details :

For deferred shading,

  • I populate my GBuffer;
  • I make an ambient light pass where I render a fullscreen quad with the ambient colors :

    #version 420 core

    layout (std140) uniform Viewport
    {
        uniform mat4 Projection;
        uniform mat4 View;
        uniform mat4 ViewProjection;
        uniform vec2 scrResolution;
    };
    
    layout(binding = 1) uniform sampler2D gAlbedoMap;
    out vec4 fragmentColor;
    
    vec2 FetchTexCoord()
    {
          return gl_FragCoord.xy / scrResolution;
    }
    
    void main()
    {
        vec2 texCoord = FetchTexCoord();
        vec3 gSurfaceColor =    texture(gAlbedoMap, texCoord).xyz;
    
        vec3 totalLight = gSurfaceColor * 1.2; //TODO remove hardcoded ambient light
        fragmentColor = vec4(totalLight, 1.0f);
    }
    

Then I pass my point lights (see code above);

解决方案

The reason you're having this problem is that you're using a "light volume" (a fact that you didn't make entirely clear in this question, but was brought up in your other question).

You are using the normal light attenuation equation. Well, you'll notice that this equation does not magically stop at some arbitrary radius. It is defined for all distances from 0 to infinity.

The purpose of your light volume is to prevent lighting contributions beyond a certain distance. Well, if your light attenuation doesn't go to zero at that distance, then you're going to see a discontinuity at the edge of the light volume.

If you're going to use a light volume, you need to use a light attenuation equation that actually is guaranteed to reach zero at the edge of the volume. Or failing that, you should pick a radius for your volume such that the attenuated strength of the light is nearly zero. And your radius is too small for that.

Keep making your radius bigger until you can't tell it's there.

这篇关于延迟着色和衰减的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆