Shadow Mapping неправильно проецируется

У меня проблемы с реализацией отображения теней в моем графическом движке OpenGL.

На первом этапе я рендерим карту теней в буферный объект кадра (с прикрепленной к нему текстурой глубины) с легкой точки зрения:

Vector3f lightPosition = Vector3f(mainLight->getPosition().x, mainLight->getPosition().y, mainLight->getPosition().z);

shadowMapFBO->BindForWriting();

glUseProgramObjectARB(0);

glViewport(0, 0, screenWidth * SHADOW_Q, screenHeight * SHADOW_Q);

glClear(GL_DEPTH_BUFFER_BIT);

glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK); //Avoid self shadowing

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-20, 20, -20, 20, 0.0f, +300.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(lightPosition.X, lightPosition.Y, lightPosition.Z, 0, 0, 0, 0, 1, 0);

drawSceneTree();

setTextureMatrix();

Я рисую всю сцену, используя функцию drawSceneTree (), и сохраняю световую матрицу в OpenGL TEXTURE7, используя функцию setTextureMatrix (), содержание которой таково:

static double modelView[16];
static double projection[16];

const GLdouble bias[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
};

// Grab modelview and transformation matrices
glGetDoublev(GL_MODELVIEW_MATRIX, modelView);
glGetDoublev(GL_PROJECTION_MATRIX, projection);

glActiveTextureARB(GL_TEXTURE7);
glMatrixMode(GL_TEXTURE);

glLoadIdentity();
glLoadMatrixd(bias);

// concatating all matrice into one.
glMultMatrixd(projection);
glMultMatrixd(modelView);// Go back to normal matrix mode
glMatrixMode(GL_MODELVIEW);

Затем я визуализирую сцену с точки зрения камеры и использую шейдер для рендеринга теней:

glViewport(0, 0, screenWidth, screenHeight);

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

// Clear previous frame values
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LIGHTING);

//Using the shadow shader
glUseProgram(shadowMapFBO->getShader());
glUniform1iARB(shadowMapFBO->getShadowMapUniform(), 7);
glUniform1iARB(shadowMapFBO->getTextureUniform(), 0);

shadowMapFBO->BindForReading(7);

setupMatrices(0, 4, -13, 0, 5, 0);

glEnable(GL_CULL_FACE);

glCullFace(GL_BACK);
drawSceneTree();

Функция setupMatrices () устанавливает матрицу проекции и просмотра модели. Я связываю shadowMapFBO с OpenGL TEXTURE7, используя функцию BindForReading (7), содержимое которой:

glActiveTexture(GL_TEXTURE0 + TextureUnit);
glBindTexture(GL_TEXTURE_2D, depthTextureId);

Наконец, вершинные и фрагментные шейдеры таковы:

Vertex:

varying vec4 ShadowCoord;

varying vec3 normal;
varying vec3 vertex_to_light_vector;
varying vec2 texture_coordinate;

void main()
{
ShadowCoord = gl_TextureMatrix[7] * gl_Vertex;

gl_Position = ftransform();

gl_FrontColor = gl_Color;

normal = gl_NormalMatrix * gl_Normal;

vec4 vertex_in_modelview_space = gl_ModelViewMatrix * gl_Vertex;

vertex_to_light_vector = vec3(gl_LightSource[0].position -vertex_in_modelview_space);

texture_coordinate = vec2(gl_MultiTexCoord0);
}

Фрагмент:

uniform sampler2D ShadowMap;
uniform sampler2D Texture;

varying vec4 ShadowCoord;
varying vec3 normal;
varying vec3 vertex_to_light_vector;
varying vec2 texture_coordinate;void main()
{
const vec4 AmbientColor = vec4(0.7, 0.7, 0.7, 1.0);
const vec4 DiffuseColor = vec4(0.5, 0.5, 0.5, 1.0);

vec3 normalized_normal = normalize(normal);
vec3 normalized_vertex_to_light_vector = normalize(vertex_to_light_vector);

float DiffuseTerm = clamp(dot(normal, vertex_to_light_vector), 0.0, 1.0);vec4 shadowCoordinateWdivide = ShadowCoord / ShadowCoord.w ;

// Used to lower moiré pattern and self-shadowing
shadowCoordinateWdivide.z += 0.0005;

float distanceFromLight = texture2D(ShadowMap,shadowCoordinateWdivide.st).z;float shadow = 1.0;
if (ShadowCoord.w > 0.0)
shadow = distanceFromLight < shadowCoordinateWdivide.z ? 0.5 : 1.0 ;gl_FragColor = texture2D(Texture, texture_coordinate) * shadow * (AmbientColor + DiffuseColor * DiffuseTerm);
gl_FragColor.a = 1.0;

}

И я получаю тень от персонажа игры, проецируемого на все объекты сцены. Я записал это в GIF:

https://dl.dropboxusercontent.com/u/658766/captura.gif

P.S: Карта теней также отображается на экране в целях отладки, в правом верхнем углу.

0

Решение

Ваша теневая координата должна быть обработана с помощью матрицы ModelWold (без проекции или просмотра матрицы). В моих шейдерах я вычисляю это так:

 ShadowCoord = gl_TextureMatrix[7] *  inverse(modelView) * gl_ModelViewMatrix * gl_Vertex;

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

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]