DiVec3 DiFocusedShadowPolicy::getNearCameraPoint_ws(const DiMat4& viewMatrix, const PointListBody& bodyLVS) const { if (bodyLVS.getPointCount() == 0) return DiVec3(0,0,0); DiVec3 nearEye = viewMatrix * bodyLVS.getPoint(0), // for comparison nearWorld = bodyLVS.getPoint(0); // represents the final point // store the vertex with the highest z-value which is the nearest point for (size_t i = 1; i < bodyLVS.getPointCount(); ++i) { const DiVec3& vWorld = bodyLVS.getPoint(i); // comparison is done from the viewer DiVec3 vEye = viewMatrix * vWorld; if (vEye.z > nearEye.z) { nearEye = vEye; nearWorld = vWorld; } } return nearWorld; }
DiMat4 DiFocusedShadowPolicy::transformToUnitCube(const DiMat4& m, const PointListBody& body) const { // map the transformed body AAB points to the unit cube (-1/-1/-1) / (+1/+1/+1) corners DiAABB aab_trans; for (size_t i = 0; i < body.getPointCount(); ++i) { aab_trans.Merge(m * body.getPoint(i)); } DiVec3 vMin, vMax; vMin = aab_trans.GetMinimum(); vMax = aab_trans.GetMaximum(); const DiVec3 trans(-(vMax.x + vMin.x) / (vMax.x - vMin.x), -(vMax.y + vMin.y) / (vMax.y - vMin.y), -(vMax.z + vMin.z) / (vMax.z - vMin.z)); const DiVec3 scale(2 / (vMax.x - vMin.x), 2 / (vMax.y - vMin.y), 2 / (vMax.z - vMin.z)); DiMat4 mOut(DiMat4::IDENTITY); mOut.setTrans(trans); mOut.setScale(scale); return mOut; }
//----------------------------------------------------------------------- Matrix4 FocusedShadowCameraSetup::transformToUnitCube(const Matrix4& m, const PointListBody& body) const { // map the transformed body AAB points to the unit cube (-1/-1/-1) / (+1/+1/+1) corners AxisAlignedBox aab_trans; for (size_t i = 0; i < body.getPointCount(); ++i) { aab_trans.merge(m * body.getPoint(i)); } Vector3 vMin, vMax; vMin = aab_trans.getMinimum(); vMax = aab_trans.getMaximum(); const Vector3 trans(-(vMax.x + vMin.x) / (vMax.x - vMin.x), -(vMax.y + vMin.y) / (vMax.y - vMin.y), -(vMax.z + vMin.z) / (vMax.z - vMin.z)); const Vector3 scale(2 / (vMax.x - vMin.x), 2 / (vMax.y - vMin.y), 2 / (vMax.z - vMin.z)); Matrix4 mOut(Matrix4::IDENTITY); mOut.setTrans(trans); mOut.setScale(scale); return mOut; }
void DiFocusedShadowPolicy::PointListBody::merge(const PointListBody& plb) { size_t size = plb.getPointCount(); for (size_t i = 0; i < size; ++i) { this->addPoint(plb.getPoint(i)); } }
//----------------------------------------------------------------------- Matrix4 LiSPSMShadowCameraSetup::calculateLiSPSM(const Matrix4& lightSpace, const PointListBody& bodyB, const PointListBody& bodyLVS, const SceneManager& sm, const Camera& cam, const Light& light) const { // set up bodyB AAB in light space AxisAlignedBox bodyBAAB_ls; for (size_t i = 0; i < bodyB.getPointCount(); ++i) { bodyBAAB_ls.merge(lightSpace * bodyB.getPoint(i)); } // near camera point in light space const Vector3 e_ls = lightSpace * getNearCameraPoint_ws(cam.getViewMatrix(), bodyLVS); // C_start has x and y of e and z from the bodyABB_ls (we look down the negative z axis, so take the maximum z value) const Vector3 C_start_ls(e_ls.x, e_ls.y, bodyBAAB_ls.getMaximum().z); // calculate the optimal distance between origin and near plane Real n_opt; if (mUseSimpleNOpt) n_opt = calculateNOptSimple(bodyLVS, cam); else n_opt = calculateNOpt(lightSpace, bodyBAAB_ls, bodyLVS, cam); // in case n_opt is null, uniform shadow mapping will be done if (n_opt <= 0.0) { return Matrix4::IDENTITY; } // calculate the projection center C which is n units behind the near plane of P // we look into the negative z direction so add n const Vector3 C(C_start_ls + n_opt * Vector3::UNIT_Z); // set up a transformation matrix to transform the light space to its new origin Matrix4 lightSpaceTranslation(Matrix4::IDENTITY); lightSpaceTranslation.setTrans(-C); // range from bMin to bMax; d = |B_z_far - B_z_near| Real d = Math::Abs(bodyBAAB_ls.getMaximum().z - bodyBAAB_ls.getMinimum().z); // set up the LiSPSM perspective transformation // build up frustum to map P onto the unit cube with (-1/-1/-1) and (+1/+1/+1) Matrix4 P = buildFrustumProjection(-1, 1, -1, 1, n_opt, n_opt + d); return P * lightSpaceTranslation; }