2014-12-06 3 views
2

Я написал простое трехмерное приложение, реализующее жесткие и PCF-алгоритмы теневого отображения, используя известную технику извлечения лица. К несчастью, проблема с этой техникой заключается только в запечатанных сетках, которые могут создавать оттенки теней. Например, самолет не может произвести такой эффект, потому что плоскость является передней гранью сама по себе.Артефакты теневых акне с использованием OpenGL и GLSL

Таким образом, решение заключается в использовании функции «glPolygonOffset», целью которой является небольшое изменение значения глубины во время пути пересечения глубины каждой вершины, видимой из «светового обзора». Другими словами, эта функция необходима, чтобы избежать артефактов теневого акне, сохраняя на этот раз все сетки передних поверхностей.

Вот проявление такого рендеринга с использованием жесткого алгоритма отображения теней:

enter image description here

Как вы можете увидеть тень рендеринг идеально без каких-либо артефактов!

Вот 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» в течение первого пути:

enter image description here

Как вы можете видеть, что мы можем видеть явно «теневые прыщи» артефакты!

Вот код из моего пиксельного шейдера:

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)); 

У меня есть следующий рендеринг:

enter image description here

Как вы можете видеть , есть артефакты «тени акне» только на правой стороне куба!

Чтобы решить проблему, я попробовал несколько комбинаций кода, добавляя некоторые значения смещения, чтобы иметь дело с глубиной вершин в пространстве света без каких-либо успехов.

+0

это называется тень акне –

+0

glPolygonOffset работает в сочетании с передней/задней лицевой выключатель - задние поверхности отображаются в положении; передние грани визуализируются со смещением, пропорциональным их наклонам. Точно так же эффективны не только визуализация на лицевой стороне, но и постоянные смещения в светлом пространстве. Если вам нужен самолет, чтобы бросить тень, просто сделайте это двухсторонней плоскостью. – Justin

ответ

0

Не знаю, поможет ли это. Возможно, я слишком усложняю ваш вопрос.Этот код выполняется из приложения Objective C, но соответствующий код в основном имеет только C. Он работает и работает. Вы увидите в фрагменте фрагмента сцены заявление: if (depthInShadow> 0.006). Эта глубина в теневом номере - это то, что я должен был «настроить», чтобы избавиться от прыщей.

Это изменение. После повторного чтения вашего сообщения я вижу утверждение: if (ShadowCoords [index] .w> 0.0f). Это выглядит очень похоже на инструкцию depthInShadow в моем шейдере фрагмента сцены, который мне пришлось «настроить» на что-то чуть большее 0,0, чтобы избавиться от прыщей. Попробуйте.

Я оставлю код, представленный ниже, в случае, если он представляет интерес для кого-либо другого, кто придет к новому для теневого отображения.

Многие из переменных объявлены в файле .h, но вы получите эту идею. Это довольно стандартный код преобразования теней, поэтому, если вы все это видели раньше, вы можете остановиться здесь и сэкономить себе долгое чтение.

настроить теневой буфер и шейдеров:

// ************************************* Save the Current Frame Buffer 

glGetIntegerv(GL_FRAMEBUFFER_BINDING, renderBuffer); 

// ************************************ Create the Shadow Map Texture 

glGenTextures(1, shadowTexture); 
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]); 

glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST); 
glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST); 

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOWMAPRATIO * VIEWWIDTH, SHADOWMAPRATIO * VIEWHEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 

glActiveTexture(GL_TEXTURE5); 
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]); 

// ************************************ Create the Shadow Map Frame Buffer 

glGenFramebuffersEXT(1, shadowBuffer); 
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadowBuffer[0]); 

// **************************************** No Color Attachment 

glDrawBuffer(GL_NONE); 
glReadBuffer(GL_NONE); 

// ************************************* Attach the Shadow Texture to It 

glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, shadowTexture[0], 0); 

// ******************************* Check to see if Frame Buffer is Complete 

GLenum frameBufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); 
if(frameBufferStatus != GL_FRAMEBUFFER_COMPLETE) 
{ 
    NSLog(@"There is a problem with the shadow frame buffer, %d", frameBufferStatus); 
    if(frameBufferStatus == GL_INVALID_ENUM) NSLog(@"Invalid Enum."); 
    if(frameBufferStatus == GL_INVALID_VALUE) NSLog(@"Invalid Value."); 
    if(frameBufferStatus == GL_INVALID_OPERATION) NSLog(@"Invalid Operation"); 
    if(frameBufferStatus == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) NSLog(@"Incomplete Attachment"); 
    if(frameBufferStatus == GL_FRAMEBUFFER_UNSUPPORTED) NSLog(@"Unsupported"); 
} 

// *********************************** Reset the original Frame Buffer 

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]); 

// ************************************** Compile and Link the Shadow Shaders 

ShaderInfo shadowShaderInfo[] = { 
     { GL_VERTEX_SHADER, "path/shadow120.vsh" }, 
     { GL_FRAGMENT_SHADER, "path/shadow120.fsh" }, 
     { GL_NONE, NULL } 
    }; 

shadowShaders = LoadShaders(shadowShaderInfo); 

glUseProgram(shadowShaders); 

shadowPositionLoc = glGetAttribLocation(shadowShaders, "ShadowPosition"); 

shadowViewMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowViewMatrix"); 
if(shadowViewMatrixLoc == -1) NSLog(@"View Matrix not found in shadow shader"); 

shadowModelMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowModelMatrix"); 
if(shadowModelMatrixLoc == -1) NSLog(@"Model Matrix not found in shadow shader"); 

shadowProjectionMatrixLoc= glGetUniformLocation(shadowShaders, "ShadowProjectionMatrix"); 
if(shadowProjectionMatrixLoc == -1) NSLog(@"Projection Matrix not found in shadow shader"); 

shadowColorLoc= glGetUniformLocation(shadowShaders, "FrontColor"); 
if(shadowColorLoc == -1) NSLog(@"Front Color not found in shadow shader"); 

Однородные теневые матрицы, конечно, от положения камеры.

Теневые шейдеры, используемые для визуализации в буфер тени, тривиальны.

Тень вершинного шейдера:

#version 120 

attribute vec4 ShadowPosition; 

uniform mat4 ShadowModelMatrix; 
uniform mat4 ShadowViewMatrix; 
uniform mat4 ShadowProjectionMatrix; 

void main() 
{ 
    gl_Position = ShadowProjectionMatrix * ShadowViewMatrix * ShadowModelMatrix * ShadowPosition; 
} 

Тень фрагмент шейдера:

#version 120 

uniform vec4 FrontColor; 

void main() 
{ 

    gl_FragColor = FrontColor; 
} 

я впервые визуализировать сцену в теневой буфер с:

glUseProgram(shadowShaders); 

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, shadowBuffer[0]); 

glColorMask (GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE); 

glActiveTexture(GL_TEXTURE5); 
glBindTexture(GL_TEXTURE_2D, shadowTexture[0]); 

glClearDepth(1.0); 
glClear(GL_DEPTH_BUFFER_BIT); 

glUniformMatrix4fv(shadowModelMatrixLoc, 1, GL_FALSE, lightGLKModelMatrix.m); 
glUniformMatrix4fv(shadowViewMatrixLoc, 1, GL_FALSE, lightGLKViewMatrix.m); 
glUniformMatrix4fv(shadowProjectionMatrixLoc, 1, GL_FALSE, lightGLKProjectionMatrix.m); 
glUniform4fv(shadowColorLoc, 1, worldAmbient); 

.... rendering code .... 

glDisable(GL_POLYGON_OFFSET_FILL); 
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, renderBuffer[0]); 
glColorMask (GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE); 

Я тогда визуализировать сцену обычно используя эти шейдеры:

Scene Vertex шейдер:

#version 120 

attribute vec4 RingPosition; 
attribute vec3 RingNormal; 

uniform vec4 LightPosition; 

uniform mat4 RingModelMatrix; 
uniform mat4 RingViewMatrix; 
uniform mat4 RingProjectionMatrix; 
uniform mat3 RingNormalMatrix; 

uniform mat4 ShadowBiasMatrix; 
uniform mat4 ShadowModelMatrix; 
uniform mat4 ShadowViewMatrix; 
uniform mat4 ShadowProjectionMatrix; 

varying float DiffuseIntensity; 
varying float SpecularIntensity; 
varying vec4 ShadowCoordinate; 

const float specularContribution = 1.0; 
const float diffuseContribution = 1.0; 

void main() 
{ 
    mat4 ShadowMatrix = ShadowBiasMatrix * ShadowProjectionMatrix * ShadowViewMatrix * ShadowModelMatrix; 

    ShadowCoordinate = ShadowMatrix * RingPosition; 

    vec3 lightPosition= vec3(LightPosition); 
    float shininess = gl_FrontMaterial.shininess; 

    vec3 ecPosition = vec3(RingViewMatrix * RingModelMatrix * RingPosition); 
    vec3 tnorm = normalize(RingNormalMatrix * RingNormal); 
    vec3 lightVec = normalize(lightPosition - ecPosition); 
    vec3 reflectVec = reflect(-lightVec, tnorm); 
    vec3 viewVec = normalize(-ecPosition); 

    float spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0); 
    SpecularIntensity = specularContribution * pow(spec, shininess/5.0); 

    DiffuseIntensity = diffuseContribution * max(dot(lightVec, tnorm), 0.0); 

    gl_Position = RingProjectionMatrix * RingViewMatrix * RingModelMatrix * RingPosition; 
} 

Сцена Фрагмент шейдеры:

#version 120 

uniform sampler2D ShadowMap; 

varying float DiffuseIntensity; 
varying float SpecularIntensity; 
varying vec4 ShadowCoordinate; 

void main() 
{ 

    vec3 emission = vec3(gl_FrontMaterial.emission); 
    vec3 ambient = vec3(gl_FrontMaterial.ambient); 
    vec3 diffuse = vec3(gl_FrontMaterial.diffuse); 
    vec3 specular = vec3(gl_FrontMaterial.specular); 

    // Normalize the Shadow Map coordinates 
    // shadowCoordinateWdivide.z = current fragment depth from light 

    vec3 shadowCoordinateWdivide = ShadowCoordinate.xyz/ShadowCoordinate.w ; 

    float distanceFromLight = texture2D(ShadowMap, shadowCoordinateWdivide.xy).r; 

    float depthInShadow = shadowCoordinateWdivide.z - distanceFromLight; 

    float specularIntensity = SpecularIntensity; 
    float diffuseIntensity = DiffuseIntensity; 

    if (depthInShadow > 0.006) 
    { 
     specularIntensity = SpecularIntensity * 0.0; 
     diffuseIntensity = DiffuseIntensity * 0.0; 
    } 

    vec3 lightColor = emission; 
    lightColor = lightColor + ambient; 
    lightColor = lightColor + (specularIntensity * specular); 
    lightColor = lightColor + (diffuseIntensity * diffuse); 

    lightColor = clamp(lightColor, 0.0, 1.0); 

    gl_FragColor = vec4(lightColor, 1.0); 

} 

Матрица тени смещения:

GLfloat shadowBiasMatrix[16] = { 
0.5, 0.0, 0.0, 0.0, 
0.0, 0.5, 0.0, 0.0, 
0.0, 0.0, 0.5, 0.0, 
0.5, 0.5, 0.5, 1.0};