# 平民程序 - linghuye's blog

## 阴影技术的理解和使用

Planar shadows are created by building a special matrix transform which flattens an object's geometry into a plane when rendered and is definitely one of the simplest ways of creating real-time shadows. Unfortunately, planar shadows are only useful when projected onto planar surface like a wall or floor so their use in modern applications or games is quickly falling out of favor.

2.然后,以正常镜头视点,渲染整个场景.对每个Fragment计算其相对于光源的XYZ位置,并与深度图中XY位置处的Z值比较,若小等于深度图的Z,表明照射该处的光线不受其他物体遮挡,反之,则收到其他物体遮挡,呈现阴影.

OpenGL实现原理:
We render the scene from the light's view and store the depth values in a texture.  We then render the world normally from the camera's view.  Texture generation is used to calculate and project our texture coordinates for the shadow mapping.  We test the depth values of the light's view and the camera's view in the light's clip space to see if there is a shadow.  Basically, if the camera can see something that the light can't, that means that that part should be shadowed.

2.建立纹理投影矩阵为光源视点下的模型矩阵,并设定纹理坐标生成方式为镜头空间的平面自动生成.
// 设置纹理矩阵
glMatrixMode(GL_TEXTURE);
gluPerspective(...); // light frustum
glMultMatrixf(...);  // Light matrix
glMatrixMode(GL_MODELVIEW);

// 激活4元纹理坐标的生成
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);

// 设置纹理坐标生成方式为平面公式线性插值的镜头空间坐标
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);

// 设置GL_EYE_LINEAR下纹理坐标生成的平面公式的系数
float x[] = { 1.0f, 0.0f, 0.0f, 0.0f };
float y[] = { 0.0f, 1.0f, 0.0f, 0.0f };
float z[] = { 0.0f, 0.0f, 1.0f, 0.0f };
float w[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glTexGenfv(GL_S, GL_EYE_PLANE, x);
glTexGenfv(GL_T, GL_EYE_PLANE, y);
glTexGenfv(GL_R, GL_EYE_PLANE, z);
glTexGenfv(GL_Q, GL_EYE_PLANE, w);

s = 1.0f * x + 0.0f * y + 0.0f * z + 0.0f = x;
t = 0.0f * x + 1.0f * y + 0.0f * z + 0.0f = y;
r = 0.0f * x + 0.0f * y + 1.0f * z + 0.0f = z;
q = 0.0f * x + 0.0f * y + 0.0f * z + 1.0f = 1.0;
=> 顶点坐标和纹理坐标在数值上相等对应 => 生成的纹理坐标的r即为z => 即在纹理投影矩阵/光源视点矩阵下的深度值.

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);