Я написал простое трехмерное приложение, реализующее жесткие и PCF-алгоритмы теневого отображения, используя известную технику извлечения лица. К несчастью, проблема с этой техникой заключается только в запечатанных сетках, которые могут создавать оттенки теней. Например, самолет не может произвести такой эффект, потому что плоскость является передней гранью сама по себе.Артефакты теневых акне с использованием OpenGL и GLSL
Таким образом, решение заключается в использовании функции «glPolygonOffset», целью которой является небольшое изменение значения глубины во время пути пересечения глубины каждой вершины, видимой из «светового обзора». Другими словами, эта функция необходима, чтобы избежать артефактов теневого акне, сохраняя на этот раз все сетки передних поверхностей.
Вот проявление такого рендеринга с использованием жесткого алгоритма отображения теней:
Как вы можете увидеть тень рендеринг идеально без каких-либо артефактов!
Вот C++ код клиента определения глубины путь текстуры визуализации:
/*glEnable(GL_CULL_FACE); //OLD TECHNIQUE
glCullFace(GL_FRONT);*/
for (uint32_t idy = 0; idy < lightSceneNodeList.size(); idy++)
{
if (lightSceneNodeList[idy]->IsShadowEnabled())
{
type::ShadowCasterPtr pShadowCaster = ShadowManager::GetSingleton()
.FindShadowCasterByName(lightSceneNodeList[idy]->GetName());
{
pShadowCaster->Bind(TARGET_FBO);
{
glEnable(GL_POLYGON_OFFSET_FILL); //NEW TECHNIQUE
glPolygonOffset(1.1f, 4.0f);
glClear(GL_DEPTH_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
{
pShadowCaster->UpdateFrustrumPosition(
lightSceneNodeList[idy]->GetParentModelMatrix());
pShadowCaster->SetViewport();
{
for (uint32_t idx = 0; idx < pBatchList.size(); idx++)
pBatchList[idx]->Render(pShadowCaster);
}
}
glDisable(GL_POLYGON_OFFSET_FILL);
}
pShadowCaster->Unbind(TARGET_FBO);
}
}
}
//glDisable(GL_CULL_FACE);
А теперь код, используемый в коде фрагмент шейдеров для вычисления коэффициента тени во время второго пути рендеринга:
/*
** \brief Recover the depth value from shadow map by projection
*/
float Tex2D_Proj(sampler2DShadow shadowSampler, vec4 LightToVertexDir_LS)
{
float ShadowFactor = 1.0f;
{
vec3 LightToVertexDir_CS = LightToVertexDir_LS.xyz/LightToVertexDir_LS.w;
ShadowFactor = texture(shadowSampler, LightToVertexDir_CS);
}
return (ShadowFactor);
}
/*
** \brief Returns biased hard shadow factor.
*/
float Get_2D_Hard_ShadowFactor(sampler2DShadow shadowSampler, int index)
{
float shadowFactor = 1.0f;
{
if (ShadowCoords[index].z <= MaxShadowDist[index])
{
if (ShadowCoords[index].w > 0.0f);
{
shadowFactor = Tex2D_Proj(shadowSampler, ShadowCoords[index]);
}
}
}
return (shadowFactor);
}
Единая переменная «ShadowCoords» - это положение вершин в пространстве света, а «индекс» - индекс света.
Но теперь у меня есть проблема с использованием PCF алгоритма теневая отображения (пример с 4 образца), используя также функцию «glPolygonOffset» в течение первого пути:
Как вы можете видеть, что мы можем видеть явно «теневые прыщи» артефакты!
Вот код из моего пиксельного шейдера:
float Get_2D_PCF_ShadowFactor(sampler2DShadow shadowSampler, int index)
{
float shadowFactor = 0.0f;
{
int kernel_base = int(PCFKernelType[index])/2;
float kernel_count = pow(int(PCFKernelType[index]), 2.0f);
if (ShadowCoords[index].z <= MaxShadowDist[index])
{
if (ShadowCoords[index].w > 0.0f)
{
shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, 1));
shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(1, 1));
shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(1, -1));
shadowFactor += textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, -1));
shadowFactor *= 0.25f;
}
}
}
return (shadowFactor);
}
код В 'textureProjOffset' равно следующему:
float Tex2D_Proj_Offset(sampler2DShadow shadowSampler, vec4 LightToVertexDir_LS, vec2 offsetCoords, vec2 shadowMapSize)
{
float offset_x = 1.0f/shadowMapSize.x;
float offset_y = 1.0f/shadowMapSize.y;
float ShadowFactor = 1.0f;
{
vec3 LightToVertexDir_CS = LightToVertexDir_LS.xyz/LightToVertexDir_LS.w;
vec2 ShadowTexCoords = vec2(LightToVertexDir_CS.x, LightToVertexDir_CS.y);
vec2 DerivedShadowTexCoords = vec2(
ShadowTexCoords.x + offsetCoords.x * offset_x,
ShadowTexCoords.y + offsetCoords.y * offset_y);
ShadowFactor = texture(shadowSampler, vec3(
DerivedShadowTexCoords, LightToVertexDir_CS.z));
}
return (ShadowFactor);
}
Только вызов «textureProjOffset (shadowSampler, ShadowCoords [индекс ], ivec2 (0, 0)) 'работает правильно (конечно, это относится к первой технике теневого теневого отображения).
Если я использую только следующий вызов (так простое отображение жесткого тени, но используя смещение):
shadowFactor = textureProjOffset(shadowSampler, ShadowCoords[index], ivec2(-1, 0));
У меня есть следующий рендеринг:
Как вы можете видеть , есть артефакты «тени акне» только на правой стороне куба!
Чтобы решить проблему, я попробовал несколько комбинаций кода, добавляя некоторые значения смещения, чтобы иметь дело с глубиной вершин в пространстве света без каких-либо успехов.
это называется тень акне –
glPolygonOffset работает в сочетании с передней/задней лицевой выключатель - задние поверхности отображаются в положении; передние грани визуализируются со смещением, пропорциональным их наклонам. Точно так же эффективны не только визуализация на лицевой стороне, но и постоянные смещения в светлом пространстве. Если вам нужен самолет, чтобы бросить тень, просто сделайте это двухсторонней плоскостью. – Justin