Ejemplo n.º 1
0
	DiVec3 DiFocusedShadowPolicy::getLSProjViewDir(const DiMat4& lightSpace, 
		const DiCamera& cam, const PointListBody& bodyLVS) const
	{
		// goal is to construct a view direction
		// because parallel lines are not parallel any more after perspective projection we have to transform
		// a ray to point us the viewing direction

		// fetch a point near the camera
		const DiVec3 e_world = getNearCameraPoint_ws(cam.GetViewMatrix(), bodyLVS);

		// plus the direction results in a second point
		const DiVec3 b_world = e_world + cam.GetDerivedDirection();

		// transformation into light space
		const DiVec3 e_ls = lightSpace * e_world;
		const DiVec3 b_ls = lightSpace * b_world;

		// calculate the projection direction, which is the subtraction of
		// b_ls from e_ls. The y component is set to 0 to project the view
		// direction into the shadow map plane.
		DiVec3 projectionDir(b_ls - e_ls);
		projectionDir.y = 0;

		// deal with Y-only vectors
		return DiMath::RealEqual(projectionDir.length(), 0.0f) ?
			DiVec3::NEGATIVE_UNIT_Z : projectionDir.normalisedCopy();
	}
	//-----------------------------------------------------------------------
	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;
	}
	//-----------------------------------------------------------------------
	Real LiSPSMShadowCameraSetup::calculateNOptSimple(const PointListBody& bodyLVS, 
		const Camera& cam) const
	{
		// get view matrix
		const Matrix4& viewMatrix = cam.getViewMatrix();

		// calculate e_es
		const Vector3 e_ws  = getNearCameraPoint_ws(viewMatrix, bodyLVS);
		const Vector3 e_es = viewMatrix * e_ws;

		// according to the new formula (mainly for directional lights)
		// n_opt = zn + sqrt(z0 * z1);
		// zn is set to Abs(near eye point)
		// z0 is set to the near camera clip distance
		// z1 is set to the far camera clip distance
		return (Math::Abs(e_es.z) + Math::Sqrt(cam.getNearClipDistance() * cam.getFarClipDistance())) * mOptAdjustFactor;
	}
	//-----------------------------------------------------------------------
	Real LiSPSMShadowCameraSetup::calculateNOpt(const Matrix4& lightSpace, 
		const AxisAlignedBox& bodyBABB_ls, const PointListBody& bodyLVS, 
		const Camera& cam) const
	{
		// get inverse light space matrix
		Matrix4 invLightSpace = lightSpace.inverse();

		// get view matrix
		const Matrix4& viewMatrix = cam.getViewMatrix();

		// calculate z0_ls
		const Vector3 e_ws  = getNearCameraPoint_ws(viewMatrix, bodyLVS);
		const Vector3 z0_ls = calculateZ0_ls(lightSpace, e_ws, bodyBABB_ls.getMaximum().z, cam);

		// z1_ls has the same x and y values as z0_ls and the minimum z values of bodyABB_ls
		const Vector3 z1_ls = Vector3(z0_ls.x, z0_ls.y, bodyBABB_ls.getMinimum().z);

		// world
		const Vector3 z0_ws = invLightSpace * z0_ls;
		const Vector3 z1_ws = invLightSpace * z1_ls;

		// eye
		const Vector3 z0_es = viewMatrix * z0_ws;
		const Vector3 z1_es = viewMatrix * z1_ws;

		const Real z0 = z0_es.z;
		const Real z1 = z1_es.z;

		// check if we have to do uniform shadow mapping
		if ((z0 < 0 && z1 > 0) ||
			(z1 < 0 && z0 > 0))
		{
			// apply uniform shadow mapping
			return 0.0;
		}
		return cam.getNearClipDistance() + Math::Sqrt(z0 * z1) * mOptAdjustFactor;
	}