OpenGL之陰影

OpenGL陰影

『陰影』有很多種方法,而『投射陰影』技術已被大量的應用於遊戲,從光源位置透視投影3D物體,從而將陰影投射到平面. 而且視覺效果佳.算法思路如下:

  1. 啟用『模板緩存』,將陰影繪畫限制在相應的區域中
  2. 構造投影矩陣,此矩陣根據『光源位置』和被『投影平面』位置來設定,並且與模型視圖矩陣相乘.
  3. 禁用光照和紋理,並設置顏色為黑色.
  4. 禁用深度測試.
  5. 啟用透明混合
  6. 繪畫陰影

落雪陰影演示下載:

構造投影矩陣

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

 

評論