『陰影』有很多種方法,而『投射陰影』技術已被大量的應用於遊戲,從光源位置透視投影3D物體,從而將陰影投射到平面. 而且視覺效果佳.算法思路如下:
- 啟用『模板緩存』,將陰影繪畫限制在相應的區域中
- 構造投影矩陣,此矩陣根據『光源位置』和被『投影平面』位置來設定,並且與模型視圖矩陣相乘.
- 禁用光照和紋理,並設置顏色為黑色.
- 禁用深度測試.
- 啟用透明混合
- 繪畫陰影
落雪陰影演示下載:
構造投影矩陣
void Build_Matrix_Shadow(MATRIX4X4_PTR destMat, VECTOR4D_PTR lightPos, PLANE3D_PTR plane)
{
float dot;// 點積
dot = plane->M[0] * lightPos->M[0] +
plane->M[1] * lightPos->M[1] +
plane->M[2] * lightPos->M[2] +
plane->M[3] * lightPos->M[3];
// 第一列
destMat->_M[0] = dot – lightPos->M[0] * plane->M[0];
destMat->_M[4] = 0.0f – lightPos->M[0] * plane->M[1];
destMat->_M[8] = 0.0f – lightPos->M[0] * plane->M[2];
destMat->_M[12] = 0.0f – lightPos->M[0] * plane->M[3];
// 第二列
destMat->_M[1] = 0.0f – lightPos->M[1] * plane->M[0];
destMat->_M[5] = dot – lightPos->M[1] * plane->M[1];
destMat->_M[9] = 0.0f – lightPos->M[1] * plane->M[2];
destMat->_M[13] = 0.0f – lightPos->M[1] * plane->M[3];
// 第三列
destMat->_M[2] = 0.0f – lightPos->M[2] * plane->M[0];
destMat->_M[6] = 0.0f – lightPos->M[2] * plane->M[1];
destMat->_M[10] = dot – lightPos->M[2] * plane->M[2];
destMat->_M[14] = 0.0f – lightPos->M[2] * plane->M[3];
// 第四列
destMat->_M[3] = 0.0f – lightPos->M[3] * plane->M[0];
destMat->_M[7] = 0.0f – lightPos->M[3] * plane->M[1];
destMat->_M[11] = 0.0f – lightPos->M[3] * plane->M[2];
destMat->_M[15] = dot – lightPos->M[3] * plane->M[3];
}
MATRIX4X4 shadow_matrix; // 投影矩陣
GLfloat light_pos[4] = { 150.0, 150.0, 150.0, 1.0 };// 『光照位置』
PLANE3D plane = { 0.0, 1.0, 0.0, 0.0 };// 『投影平面』
構造投影矩陣
Build_Matrix_Shadow(&shadow_matrix,(VECTOR4D_PTR)&Light_Pos,(PLANE3D_PTR) &plane);
渲染陰影示例代碼
// 禁用對所有的然色分量的修改
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
// 禁用深度測試
glEnable(GL_DEPTH_TEST);
// 深度緩存設為只讀
glDepthMask(GL_FALSE);
// 啟用模板測試
glEnable(GL_STENCIL_TEST);
// 設置模板比較程序
glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
// 設置模板ref操作,
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);//
// 繪畫地板,將模板環存中相應的地板像素設為1
Draw_Floor();
// 啟用所有顏色分量的修改
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// 啟用深度測試
glEnable(GL_DEPTH_TEST);
// 深度緩存設為可讀寫
glDepthMask(GL_TRUE);
// 設置模板比較程序,只能在模板緩存中值為1的相應去區域繪製
glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
// 設置模板操作
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);// 保持當前值
// 繪製”鏡像”
glPushMatrix();
// 反轉
glScalef(1.0f, -1.0f, 1.0f);
//結束鏡像繪畫
glPopMatrix();
// 繪畫地板
Draw_Floor();
// 以黑色繪製陰影,將其與相應表面進行混合,無光照不進行深度測試
glPushMatrix();
glPushAttrib(GL_ALL_ATTRIB_BITS);
glDisable(GL_TEXTURE_2D);// 禁用2D紋理
glDisable(GL_LIGHTING);// 禁用光照
glDisable(GL_DEPTH_TEST);// 禁用深度測試
glEnable(GL_BLEND);// 啟用混合
// 確保不在任何一個光柵位置處進行重複繪製
glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
// 黑色陰影
glColor4f(0.0f, 0.0f, 0.0f, blend);
// 以陰影進行投影
glMultMatrixf((float*)&shadow_matrix);// 投影矩陣
// 繪畫粒子暴風雪陰影
Draw_Snowstorm(&snowstorm, &Camera3D, &billboard);
glEnable(GL_TEXTURE_2D);// 禁用2D紋理
glEnable(GL_LIGHTING);// 禁用光照
glEnable(GL_DEPTH_TEST);// 禁用深度測試
glDisable(GL_BLEND);// 啟用混合
glPopAttrib();
glPopMatrix();
// 禁用模板測試
glDisable(GL_STENCIL_TEST);
// 繪畫粒子暴風雪
Draw_Snowstorm();