我在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()绘制所有场景,并使用函数setTextureMatrix()将光矩阵存储到OpenGL TEXTURE7中,其内容如下:
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()函数用于设置投影和模型视图矩阵。我使用函数BindForReading(7)将shadowMapFBO绑定到OpenGL TEXTURE7中,其内容为:
glActiveTexture(GL_TEXTURE0 + TextureUnit);
glBindTexture(GL_TEXTURE_2D, depthTextureId);
最后,顶点和片段着色器如下:
顶点:
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:阴影贴图也在屏幕上呈现,用于调试,位于右上角。
阴影坐标必须由ModelWold矩阵处理(既没有投影矩阵也没有视图矩阵)。在我的着色器中,我用以下方法计算它:
ShadowCoord = gl_TextureMatrix[7] * inverse(modelView) * gl_ModelViewMatrix * gl_Vertex;
但您可以将其作为统一材质传递给着色器。这是在将ModelViewProjectionMatrix设置为查看原点后应用于场景中每个单独对象的变换矩阵(肯定有更聪明的方法来处理这个问题,但我没有太多挖掘)。