事隔几个月之后,终于有时间把代码贴上来了。代码下载
今天在搞Hardware shadow map,有一点小进展,但是还是有不少距离。期待写shadow map系列
1.先说一下3ds文件的结构吧,只说跟投影有关的东西,就是它是包含多个object的,读进来的模型也是包含多个object的。
// 模型信息结构体
struct t3DModel2.首先执行阴影的初始化工作
{
UINT texture[MAX_TEXTURES];
int numOfObjects; // 模型中对象的数目
int numOfMaterials; // 模型中材质的数目
std::vector <tMaterialInfo> pMaterials;// 材质链表信息
std::vector <t3DObject> pObject; // 模型中对象链表信息
};
//载入模型以下是ModelShadow::Init的定义
g_model.Import3DS(fileName);
// 初始化阴影
g_modelShadow.Init(g_model.GetModel(), g_lightPos);
3.初始化之后就可以渲染了
bool ModelShadow::Init(const t3DModel &model,const float *lightPos)
{
// 获取object的数目
objNum_ = model.numOfObjects;
objInfoTable_.resize(objNum_);
for(int objIndex = 0 ; objIndex < objNum_ ; objIndex++ )
{
....
}
glClearStencil(0);
....
SetConnectivity(); // 设置三角形之间的链接关系
CalcPlane(); // 计算每个三角形的平面方程
....
}
// 绘制模型,阴影通过两次获得的矩阵的差异就可以算出中间做了那些变换,比如(glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]); )
// 重设光源位置,如果光源位置不便可以忽略
g_modelShadow.ResetLightPos(g_lightPos);
// 这里获取当前的model view matrix(MVM)
g_modelShadow.GetCurMatrix();
glPushMatrix();
// 放置物体
glTranslatef(g_modelPos[0], g_modelPos[1], g_modelPos[2]);
// 这里又获取了一次model view matrix
g_model.Draw();
g_modelShadow.Draw();
glPopMatrix();
现在看一下ModelShadow::Draw的实现
void ModelShadow::Draw() const再看ModelShadow::castShadow
{
glClear(GL_STENCIL_BUFFER_BIT);
GLfloat objMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, objMatrix);
// 求逆矩阵,这四条语句就是在求物体的局部坐标系里灯的坐标
InverseMatrix16(objMatrix);
MultiplyMatrix16(objMatrix, curMatrix_);
memcpy(lightPos_, orignLightPos_, 4 * sizeof(float));
Mtx16MultVect4(objMatrix, lightPos_);
//Cast the shadow
CastShadow();
}
有一些问题,我在(2)里说错了的
void ModelShadow::CastShadow() const
{
SetVisibility(); // 设置每个三角形的可见性
....
// 第一趟渲染,通过模板测试的话模版值增一
glFrontFace(GL_CCW);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
DoShadowPass();
// 第二趟渲染,通过模板测试的话模版值减一
glFrontFace(GL_CW);
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
DoShadowPass();
....
glStencilFunc(GL_NOTEQUAL, 0, 1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
//在全屏幕混合一张图
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0, 0, 0, 0.3f);
....
}
glLoadIdentity();这个覆盖全屏真是投机取巧
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(-0.1f, 0.1f, -0.10f);
glVertex3f(-0.1f, -0.1f, -0.10f);
glVertex3f( 0.1f, 0.1f, -0.10f);
glVertex3f( 0.1f, -0.1f, -0.10f);
glEnd();
gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);
如果那个角度比45.0f大就无法覆盖了
正确的做法是改用正投影。