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 DiFocusedShadowPolicy::calculateShadowMappingMatrix(const DiSceneManager& sm, const DiCamera& cam, const DiLight& light, DiMat4 *out_view, DiMat4 *out_proj, DiCamera *out_cam) const { DiVec3 lightPos = light.GetDerivedPosition(); DiVec3 lightDir = light.GetDerivedDirection(); // get the shadow frustum's far distance float shadowDist = sm.GetShadowFarDistance(); if (!shadowDist) { // need a shadow distance, make one up shadowDist = cam.GetNearClipDistance() * 3000; } float shadowOffset = shadowDist * sm.GetShadowDirLightTextureOffset(); if (light.GetType() == LIGHT_DIRECTIONAL) { // generate view matrix if requested if (out_view != NULL) { DiVec3 pos; #if 0 if (sm.getCameraRelativeRendering()) { pos = DiVec3::ZERO; } else #endif { pos = cam.GetDerivedPosition(); } *out_view = buildViewMatrix(pos, lightDir, cam.GetDerivedUp()); } // generate projection matrix if requested if (out_proj != NULL) { *out_proj = DiMat4::getScale(1, 1, -1); //*out_proj = DiMat4::IDENTITY; } // set up camera if requested if (out_cam != NULL) { out_cam->SetProjectionType(PT_ORTHOGRAPHIC); out_cam->SetDirection(lightDir); out_cam->SetPosition(cam.GetDerivedPosition()); out_cam->SetFOVy(DiDegree(90)); out_cam->SetNearClipDistance(shadowOffset); } } else if (light.GetType() == LIGHT_SPOT) { const DiSpotLight* spot = static_cast<const DiSpotLight*>(&light); // generate view matrix if requested if (out_view != NULL) { *out_view = buildViewMatrix(light.GetDerivedPosition(), light.GetDerivedDirection(), cam.GetDerivedUp()); } // generate projection matrix if requested if (out_proj != NULL) { // set FOV slightly larger than spotlight range mTempFrustum->SetFOVy(DiMath::Clamp<DiRadian>(spot->GetOuterAngle() * 1.2, DiRadian(0), DiRadian(DiMath::PI/2.0f))); mTempFrustum->SetNearClipDistance(light.DeriveShadowNearClipDistance(&cam)); mTempFrustum->SetFarClipDistance(light.DeriveShadowFarClipDistance(&cam)); *out_proj = mTempFrustum->GetProjectionMatrix(); } // set up camera if requested if (out_cam != NULL) { out_cam->SetProjectionType(PT_PERSPECTIVE); out_cam->SetDirection(light.GetDerivedDirection()); out_cam->SetPosition(light.GetDerivedPosition()); out_cam->SetFOVy(DiMath::Clamp<DiRadian>(spot->GetOuterAngle() * 1.2, DiRadian(0), DiRadian(DiMath::PI/2.0f))); out_cam->SetNearClipDistance(light.DeriveShadowNearClipDistance(&cam)); out_cam->SetFarClipDistance(light.DeriveShadowFarClipDistance(&cam)); } } #if 0 else if (light.GetType() == LIGHT_POINT) { // target analogue to the default shadow textures // Calculate look at position // We want to look at a spot shadowOffset away from near plane // 0.5 is a little too close for angles DiVec3 target = cam.GetDerivedPosition() + (cam.GetDerivedDirection() * shadowOffset); lightDir = target - lightPos; lightDir.normalise(); // generate view matrix if requested if (out_view != NULL) { *out_view = buildViewMatrix(lightPos, lightDir, cam.GetDerivedUp()); } // generate projection matrix if requested if (out_proj) { // set FOV to 120 degrees mTempFrustum->SetFOVy(DiDegree(120)); mTempFrustum->SetNearClipDistance(light._deriveShadowNearClipDistance(&cam)); mTempFrustum->SetFarClipDistance(light._deriveShadowFarClipDistance(&cam)); *out_proj = mTempFrustum->GetProjectionMatrix(); } // set up camera if requested if (out_cam) { out_cam->SetProjectionType(PT_PERSPECTIVE); out_cam->SetDirection(lightDir); out_cam->SetPosition(lightPos); out_cam->SetFOVy(DiDegree(120)); out_cam->SetNearClipDistance(light._deriveShadowNearClipDistance(&cam)); out_cam->SetFarClipDistance(light._deriveShadowFarClipDistance(&cam)); } } #endif }