Недавно я добавил поддержку отложенного затенения в моем движке; Однако я столкнулся с некоторыми проблемами ослабления:
Как вы можете видеть, когда я рендерим объем света (сферу), он не очень хорошо сочетается с окружающей частью изображения!
Вот как я заявляю мой точечный свет:
PointLight pointlight;
pointlight.SetPosition(glm::vec3(0.0, 6.0, 0.0));
pointlight.SetIntensity(glm::vec3(1.0f, 1.0f, 1.0f));
Вот как я вычисляю радиус легкой сферы:
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);
И, наконец, вот мой фрагментный шейдер PointLightPass:
#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);
}
Итак, что вы можете предложить для решения этой проблемы?
РЕДАКТИРОВАТЬ: Вот более подробную информацию:
Для отложенного затенения,
Я делаю проход окружающего света, где я отрисовываю полноэкранный квад
с окружающими цветами:
# версия 420 ядро
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);
}
Затем я передаю свои точечные огни (см. Код выше);
Причина, по которой у вас возникает эта проблема, заключается в том, что вы используете «легкую громкость» (факт, который вы не прояснили полностью в этом вопросе, но были затронуты в ваш другой вопрос).
Вы используете нормальное уравнение ослабления света. Хорошо, вы заметите, что это уравнение магическим образом не останавливается на каком-то произвольном радиусе. Он определяется для всех расстояний от 0 до бесконечности.
Цель вашего уровня громкости состоит в том, чтобы предотвратить воздействие света на определенное расстояние. Что ж, если ваше ослабление света не достигнет нуля на этом расстоянии, то вы увидите разрыв на краю объема света.
Если вы собираетесь использовать объем света, вам нужно использовать уравнение ослабления света, которое на самом деле гарантированно достигнет нуля на краю объема. Или, в противном случае, вы должны выбрать радиус для своего объема, чтобы ослабленная сила света была почти равна нулю. И ваш радиус слишком мал для этого.
Продолжайте увеличивать свой радиус, пока не увидите, что он там.
Других решений пока нет …