示例#1
0
	void DiFocusedShadowPolicy::calculateLVS(const DiSceneManager& sm, const DiCamera& cam,
		const DiLight& light, const DiAABB& sceneBB, PointListBody *out_LVS) const
	{
		DiConvexBody bodyLVS;

		// init body with view frustum
		bodyLVS.define(cam);

		// clip the body with the light frustum (point + spot)
		// for a directional light the space of the intersected
		// view frustum and sceneBB is always lighted and in front
		// of the viewer.
		if (light.GetType() != LIGHT_DIRECTIONAL)
		{
			// clip with the light frustum
			// set up light camera to clip the resulting frustum
			if (!mLightFrustumCameraCalculated)
			{
				calculateShadowMappingMatrix(sm, cam, light, NULL, NULL, mLightFrustumCamera);
				mLightFrustumCameraCalculated = true;
			}
			bodyLVS.clip(*mLightFrustumCamera);
		}

		// clip the body with the scene bounding box
		bodyLVS.clip(sceneBB);

		// extract bodyLVS vertices
		out_LVS->build(bodyLVS);
	}
示例#2
0
	void DiFocusedShadowPolicy::calculateB(const DiSceneManager& sm, const DiCamera& cam,
		const DiLight& light, const DiAABB& sceneBB, const DiAABB& receiverBB, 
		PointListBody *out_bodyB) const
	{
		DI_ASSERT_MESSAGE(out_bodyB != NULL, "bodyB vertex list is NULL");

		/// perform convex intersection of the form B = ((V \cap S) + l) \cap S \cap L

		// get V
		mBodyB.define(cam);

		if (light.GetType() != LIGHT_DIRECTIONAL)
		{
			if (mUseAggressiveRegion)
				mBodyB.clip(sceneBB);

			// form a convex hull of bodyB with the light position
			mBodyB.extend(light.GetDerivedPosition());

			// clip bodyB with sceneBB
			mBodyB.clip(sceneBB);

			// clip with the light frustum
			// set up light camera to clip with the resulting frustum planes
			if (!mLightFrustumCameraCalculated)
			{
				calculateShadowMappingMatrix(sm, cam, light, NULL, NULL, mLightFrustumCamera);
				mLightFrustumCameraCalculated = true;
			}
			mBodyB.clip(*mLightFrustumCamera);

			// extract bodyB vertices
			out_bodyB->build(mBodyB);

		}
		else
		{
			// For directional lights, all we care about is projecting the receivers
			// backwards towards the light, clipped by the camera region
			mBodyB.clip(receiverBB);

			// Also clip based on shadow far distance if appropriate
			float farDist = sm.GetShadowFarDistance();
			if (farDist)
			{
				DiVec3 pointOnPlane = cam.GetDerivedPosition() +
					(cam.GetDerivedDirection() * farDist);
				DiPlane p(cam.GetDerivedDirection(), pointOnPlane);
				mBodyB.clip(p);
			}

			// Extrude the intersection bodyB into the inverted light direction and store 
			// the info in the point list.
			// Maximum extrusion extent is to the shadow far distance
			out_bodyB->buildAndIncludeDirection(mBodyB, 
				farDist ? farDist : cam.GetNearClipDistance() * 3000,
				-light.GetDerivedDirection());
		}
	}
	//-----------------------------------------------------------------------
	void LiSPSMShadowCameraSetup::getShadowCamera (const SceneManager *sm, const Camera *cam, 
		const Viewport *vp, const Light *light, Camera *texCam) const
	{
		// check availability - viewport not needed
		OgreAssert(sm != NULL, "SceneManager is NULL");
		OgreAssert(cam != NULL, "Camera (viewer) is NULL");
		OgreAssert(light != NULL, "Light is NULL");
		OgreAssert(texCam != NULL, "Camera (texture) is NULL");
		mLightFrustumCameraCalculated = false;


		// calculate standard shadow mapping matrix
		Matrix4 LView, LProj;
		calculateShadowMappingMatrix(*sm, *cam, *light, &LView, &LProj, NULL);

		// build scene bounding box
		const VisibleObjectsBoundsInfo& visInfo = sm->getShadowCasterBoundsInfo(light);
		AxisAlignedBox sceneBB = visInfo.aabb;
		sceneBB.merge(sm->getVisibleObjectsBoundsInfo(cam).aabb);
		sceneBB.merge(cam->getDerivedPosition());

		// in case the sceneBB is empty (e.g. nothing visible to the cam) simply
		// return the standard shadow mapping matrix
		if (sceneBB.isNull())
		{
			texCam->setCustomViewMatrix(true, LView);
			texCam->setCustomProjectionMatrix(true, LProj);
			return;
		}

		// calculate the intersection body B
		mPointListBodyB.reset();
		calculateB(*sm, *cam, *light, sceneBB, &mPointListBodyB);

		// in case the bodyB is empty (e.g. nothing visible to the light or the cam)
		// simply return the standard shadow mapping matrix
		if (mPointListBodyB.getPointCount() == 0)
		{
			texCam->setCustomViewMatrix(true, LView);
			texCam->setCustomProjectionMatrix(true, LProj);
			return;
		}

		// transform to light space: y -> -z, z -> y
		LProj = msNormalToLightSpace * LProj;

		// calculate LVS so it does not need to be calculated twice
		// calculate the body L \cap V \cap S to make sure all returned points are in 
		// front of the camera
		calculateLVS(*sm, *cam, *light, sceneBB, &mPointListBodyLVS);

		// fetch the viewing direction
		const Vector3 viewDir = getLSProjViewDir(LProj * LView, *cam, mPointListBodyLVS);

		// The light space will be rotated in such a way, that the projected light view 
		// always points upwards, so the up-vector is the y-axis (we already prepared the
		// light space for this usage).The transformation matrix is set up with the
		// following parameters:
		// - position is the origin
		// - the view direction is the calculated viewDir
		// - the up vector is the y-axis
		LProj = buildViewMatrix(Vector3::ZERO, viewDir, Vector3::UNIT_Y) * LProj;

		// calculate LiSPSM projection
		LProj = calculateLiSPSM(LProj * LView, mPointListBodyB, mPointListBodyLVS, *sm, *cam, *light) * LProj;

		// map bodyB to unit cube
		LProj = transformToUnitCube(LProj * LView, mPointListBodyB) * LProj;

		// transform from light space to normal space: y -> z, z -> -y
		LProj = msLightSpaceToNormal * LProj;

		// LView = Lv^-1
		// LProj = Switch_{-ls} * FocusBody * P * L_r * Switch_{ls} * L_p
		texCam->setCustomViewMatrix(true, LView);
		texCam->setCustomProjectionMatrix(true, LProj);
	}
示例#4
0
	void DiFocusedShadowPolicy::getShadowCamera (const DiSceneManager *sm, const DiCamera *cam, 
		const DiViewport *vp, const DiLight *light, DiCamera *texCam, size_t iteration) const
	{
		// check availability - viewport not needed
		DI_ASSERT_MESSAGE(sm != NULL, "SceneManager is NULL");
		DI_ASSERT_MESSAGE(cam != NULL, "Camera (viewer) is NULL");
		DI_ASSERT_MESSAGE(light != NULL, "Light is NULL");
		DI_ASSERT_MESSAGE(texCam != NULL, "Camera (texture) is NULL");
		mLightFrustumCameraCalculated = false;

		texCam->SetNearClipDistance(light->DeriveShadowNearClipDistance(cam));
		texCam->SetFarClipDistance(light->DeriveShadowFarClipDistance(cam));

		// calculate standard shadow mapping matrix
		DiMat4 LView, LProj;
		calculateShadowMappingMatrix(*sm, *cam, *light, &LView, &LProj, NULL);

		// build scene bounding box
		auto& visInfo = texCam->GetVisBoundsInfo();
		DiAABB sceneBB = visInfo.aabb;
		DiAABB receiverAABB = cam->GetVisBoundsInfo().receiverAabb;
		sceneBB.Merge(receiverAABB);
		sceneBB.Merge(cam->GetDerivedPosition());

		// in case the sceneBB is empty (e.g. nothing visible to the cam) simply
		// return the standard shadow mapping matrix
		if (sceneBB.IsNull())
		{
			texCam->SetCustomViewMatrix(true, LView);
			texCam->SetCustomProjectionMatrix(true, LProj);
			return;
		}

		// calculate the intersection body B
		mPointListBodyB.reset();
		calculateB(*sm, *cam, *light, sceneBB, receiverAABB, &mPointListBodyB);

		// in case the bodyB is empty (e.g. nothing visible to the light or the cam)
		// simply return the standard shadow mapping matrix
		if (mPointListBodyB.getPointCount() == 0)
		{
			texCam->SetCustomViewMatrix(true, LView);
			texCam->SetCustomProjectionMatrix(true, LProj);
			return;
		}

		// transform to light space: y -> -z, z -> y
		LProj = msNormalToLightSpace * LProj;

		// calculate LVS so it does not need to be calculated twice
		// calculate the body L \cap V \cap S to make sure all returned points are in 
		// front of the camera
		mPointListBodyLVS.reset();
		calculateLVS(*sm, *cam, *light, sceneBB, &mPointListBodyLVS);

		// fetch the viewing direction
		const DiVec3 viewDir = getLSProjViewDir(LProj * LView, *cam, mPointListBodyLVS);

		// The light space will be rotated in such a way, that the projected light view 
		// always points upwards, so the up-vector is the y-axis (we already prepared the
		// light space for this usage).The transformation matrix is set up with the
		// following parameters:
		// - position is the origin
		// - the view direction is the calculated viewDir
		// - the up vector is the y-axis
		LProj = buildViewMatrix(DiVec3::ZERO, viewDir, DiVec3::UNIT_Y) * LProj;

		// map bodyB to unit cube
		LProj = transformToUnitCube(LProj * LView, mPointListBodyB) * LProj;

		// transform from light space to normal space: y -> z, z -> -y
		LProj = msLightSpaceToNormal * LProj;

		// set the two custom matrices
		texCam->SetCustomViewMatrix(true, LView);
		texCam->SetCustomProjectionMatrix(true, LProj);
	}
	//-----------------------------------------------------------------------
	void FocusedShadowCameraSetup::calculateB(const SceneManager& sm, const Camera& cam, 
		const Light& light, const AxisAlignedBox& sceneBB, const AxisAlignedBox& receiverBB, 
		PointListBody *out_bodyB) const
	{
		OgreAssert(out_bodyB != NULL, "bodyB vertex list is NULL");

		/// perform convex intersection of the form B = ((V \cap S) + l) \cap S \cap L

		// get V
		mBodyB.define(cam);

		if (light.getType() != Light::LT_DIRECTIONAL)
		{
			// clip bodyB with sceneBB
			/* Note, Matthias' original code states this:
			"The procedure ((V \cap S) + l) \cap S \cap L (Wimmer et al.) leads in some 
			cases to disappearing shadows. Valid parts of the scene are clipped, so shadows 
			are partly incomplete. The cause may be the	transformation into light space that 
			is only done for the corner points which may not contain the whole scene afterwards 
			any more. So we fall back to the method of Stamminger et al. (V + l) \cap S \cap L 
			which does not show these anomalies."

			.. leading to the commenting out of the below clip. However, ift makes a major
			difference to the quality of the focus, and so far I haven't noticed
			the clipping issues described. Intuitively I would have thought that
			any clipping issue would be due to the findCastersForLight not being
			quite right, since if the sceneBB includes those there is no reason for
			this clip instruction to omit a genuine shadow caster.

			I have made this a user option since the quality effect is major and
			the clipping problem only seems to occur in some specific cases. 
			*/
			if (mUseAggressiveRegion)
				mBodyB.clip(sceneBB);

			// form a convex hull of bodyB with the light position
			mBodyB.extend(light.getDerivedPosition());

			// clip bodyB with sceneBB
			mBodyB.clip(sceneBB);

			// clip with the light frustum
			// set up light camera to clip with the resulting frustum planes
			if (!mLightFrustumCameraCalculated)
			{
				calculateShadowMappingMatrix(sm, cam, light, NULL, NULL, mLightFrustumCamera);
				mLightFrustumCameraCalculated = true;
			}
			mBodyB.clip(*mLightFrustumCamera);

			// extract bodyB vertices
			out_bodyB->build(mBodyB);

		}
		else
		{
			// For directional lights, all we care about is projecting the receivers
			// backwards towards the light, clipped by the camera region
			mBodyB.clip(receiverBB);

			// Also clip based on shadow far distance if appropriate
			Real farDist = light.getShadowFarDistance();
			if (farDist)
			{
				Vector3 pointOnPlane = cam.getDerivedPosition() + 
					(cam.getDerivedDirection() * farDist);
				Plane p(cam.getDerivedDirection(), pointOnPlane);
				mBodyB.clip(p);
			}

			// Extrude the intersection bodyB into the inverted light direction and store 
			// the info in the point list.
			// Maximum extrusion extent is to the shadow far distance
			out_bodyB->buildAndIncludeDirection(mBodyB, 
				farDist ? farDist : cam.getNearClipDistance() * 3000, 
				-light.getDerivedDirection());
		}
	}