一個三維物體繪制出來之後,打上光照就很具有真實感了,但是如果一個物體沒有影子,那麼是一個很可怕的事情。那麼我們如何把一個物體的影子加上呢,本文會介紹一種方法,可以讓三維物體的影子投影到指定的平面上。如何繪制下面的花瓶可以參考我的另一個文章:opengl繪制花瓶
程式示範連結:https://download.csdn.net/download/qq_31804159/10383046
實作結果:
下面介紹一下原理:
1、如下圖,我們定義光源為平行光,其方向為 l 向量,下圖的p表示一個三維物體上的一點,n表示目标平面的法線,s表示p點投影到目标平面的點。Ax+By+Cz+D=0即為目标平面的方程,
具體計算如下(下圖從老師那裡盜的
):
這裡強調一下最後一步,我們把一個3*3的投影矩陣轉換成4*4的矩陣是因為我們要使用齊次坐标,齊次坐标是将一個原本是n維的向量用一個n+1維向量來表示,如二維點 (1,2) 在齊次坐标中即可标示成 (1,2,1) 或 (2,4,2)。我們把3*3的投影矩陣轉換到到4*4的矩陣時擴大了k倍,k表示縮放系數。則我們最終得到投影點的坐标s應為(Qx/w,Qy/w,Qz/w ); 這一過程我們稱為歸一化處理。
2、我們通過上面的計算公式我們可以得到投影矩陣,下面矩陣可以直接使用:
那麼我們隻要讓模型的每個點pi均乘以這個矩陣,那我們就可以得到投影點si.
下面是代碼具體實作:
3、 定義一些變量
QMatrix4x4 ProjectMat; //定義投影矩陣
QVector3D lightPos; //定義燈的位置
QVector<QVector3D> project_vertexs;//投影點的集合
4、構造投影矩陣
void BuildShaderMat(float a, float b, float c, float d, QVector3D lpos)
{
float lx = lpos.x();
float ly = lpos.y();
float lz = lpos.z();
float k = a*lx+b*ly+c*lz;
float mat[16] = {b*ly+c*lz,-b*lx,-c*lx,-d*lx,
-a*ly , a*lx+c*lz,-c*ly,-d*ly,
-a*lz , -b*lz,a*lx+b*ly, -d*lz,
0,0,0,k
};
QMatrix4x4 pmat(mat);
ProjectMat = pmat;
}
5.計算投影點
void BuildShader()
{
for( int i =0; i< m_vertex.size(); i++)
{
QVector4D p = m_vertex[i].toVector4D();
p.setW(1);
p = ProjectMat*p;
QVector3D sp(p.x()/p.w(),p.y()/p.w(),p.z()/p.w());
project_vertexs.push_back(sp);
}
}
6、繪制陰影
void drawShader()
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glBegin(GL_QUADS);
glColor3f(0.6,0.6,0.6);
for( int i= 0; i<project_vertexs.size(); i++)
{
glVertex3f(project_vertexs[i].x(),project_vertexs[i].y(),project_vertexs[i].z());
}
glEnd();
glBegin(GL_POLYGON);
glEnd();
glEnable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
}
然後分别調用以上函數即可完成陰影的生成
本例參考源碼連結:https://download.csdn.net/download/qq_31804159/10383051