void ArMoveProperty::UpdateRotation(ArGameEntity* srcEntity, const DiK2Pos& targetPos, float dt, int turnRate) { DiK2RenderObject* renderObj = srcEntity->GetRenderObj(); auto newPos = renderObj->GetPosition(); DiVec3 direction = DiVec3(targetPos.x, 0, targetPos.z) - DiVec3(newPos.x, 0, newPos.z); direction.y = 0; direction.normalise(); float yawToGoal; DiVec3 srcVec = renderObj->GetRotQuat() * DiVec3::UNIT_Z; if ((1.0f + srcVec.dotProduct(direction)) < 0.0001f) yawToGoal = 180; else { DiQuat toGoal = renderObj->GetRotQuat().zAxis().getRotationTo(direction); yawToGoal = toGoal.getYaw().valueDegrees(); } float yawAtSpeed = yawToGoal / DiMath::Abs(yawToGoal) * dt * ((float)turnRate); if (yawToGoal < 0) yawToGoal = std::min<float>(0, std::max<float>(yawToGoal, yawAtSpeed)); else if (yawToGoal > 0) yawToGoal = std::max<float>(0, std::min<float>(yawToGoal, yawAtSpeed)); DiQuat actorOrientation = renderObj->GetRotQuat(); actorOrientation = DiQuat(DiDegree(yawToGoal), DiVec3::UNIT_Y) * actorOrientation; float rotrad = actorOrientation.getYaw().valueRadians(); renderObj->SetRotation(rotrad); }
DiMat4 DiFocusedShadowPolicy::buildViewMatrix(const DiVec3& pos, const DiVec3& dir, const DiVec3& up) const { DiVec3 xN = dir.crossProduct(up); xN.normalise(); DiVec3 upN = xN.crossProduct(dir); upN.normalise(); DiMat4 m(xN.x, xN.y, xN.z, -xN.dotProduct(pos), upN.x, upN.y, upN.z, -upN.dotProduct(pos), -dir.x, -dir.y, -dir.z, dir.dotProduct(pos), 0.0, 0.0, 0.0, 1.0 ); return m; }
void DiNormalShadowPolicy::getShadowCamera (const DiSceneManager *sm, const DiCamera *cam, const DiViewport *vp, const DiLight *light, DiCamera *texCam, size_t iteration) const { DiVec3 pos, dir; // reset custom view / projection matrix in case already set texCam->SetCustomViewMatrix(false); texCam->SetCustomProjectionMatrix(false); texCam->SetNearClipDistance(light->DeriveShadowNearClipDistance(cam)); texCam->SetFarClipDistance(light->DeriveShadowFarClipDistance(cam)); // get the shadow frustum's far distance float shadowDist = sm->GetShadowFarDistance(); if (!shadowDist) { // need a shadow distance, make one up shadowDist = cam->GetNearClipDistance() * 300; } float shadowOffset = shadowDist * (sm->GetShadowDirLightTextureOffset()); // Directional lights if (light->GetType() == LIGHT_DIRECTIONAL) { // set up the shadow texture // Set ortho projection texCam->SetProjectionType(PT_ORTHOGRAPHIC); // set ortho window so that texture covers far dist texCam->SetOrthoWindow(shadowDist * 2, shadowDist * 2); // Calculate look at position // We want to look at a spot shadowOffset away from near plane // 0.5 is a litle too close for angles DiVec3 target = cam->GetDerivedPosition() + (cam->GetDerivedDirection() * shadowOffset); // Calculate direction, which same as directional light direction dir = - light->GetDerivedDirection(); // backwards since point down -z dir.normalise(); // Calculate position // We want to be in the -ve direction of the light direction // far enough to project for the dir light extrusion distance pos = target + dir * sm->GetShadowDirLightExtrusionDistance(); float worldTexelSize = (shadowDist * 2) / (vp->mWidth * vp->mParent->GetWidth()); //get texCam orientation DiVec3 up = DiVec3::UNIT_Y; // Check it's not coincident with dir if (DiMath::Abs(up.dotProduct(dir)) >= 1.0f) { // Use camera up up = DiVec3::UNIT_Z; } // cross twice to rederive, only direction is unaltered DiVec3 left = dir.crossProduct(up); left.normalise(); up = dir.crossProduct(left); up.normalise(); // Derive quaternion from axes DiQuat q; q.FromAxes(left, up, dir); //convert world space camera position into light space DiVec3 lightSpacePos = q.Inverse() * pos; //snap to nearest texel lightSpacePos.x -= fmod(lightSpacePos.x, worldTexelSize); lightSpacePos.y -= fmod(lightSpacePos.y, worldTexelSize); //convert back to world space pos = q * lightSpacePos; } else if (light->GetType() == LIGHT_SPOT) { const DiSpotLight* spot = static_cast<const DiSpotLight*>(light); // Set perspective projection texCam->SetProjectionType(PT_PERSPECTIVE); // set FOV slightly larger than the spotlight range to ensure coverage DiRadian fovy = spot->GetOuterAngle() * 1.2; // limit angle if (fovy.valueDegrees() > 175) fovy = DiDegree(175); texCam->SetFOVy(fovy); // Calculate position, which same as spotlight position pos = light->GetDerivedPosition(); // Calculate direction, which same as spotlight direction dir = - light->GetDerivedDirection(); // backwards since point down -z dir.normalise(); } else { DI_ASSERT_FAIL; } // Finally set position texCam->SetPosition(pos); DiVec3 up = DiVec3::UNIT_Y; // Check it's not coincident with dir if (DiMath::Abs(up.dotProduct(dir)) >= 1.0f) { // Use camera up up = DiVec3::UNIT_Z; } // cross twice to rederive, only direction is unaltered DiVec3 left = dir.crossProduct(up); left.normalise(); up = dir.crossProduct(left); up.normalise(); // Derive quaternion from axes DiQuat q; q.FromAxes(left, up, dir); texCam->SetOrientation(q); }
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 }
bool DiCameraHelper::Update( float elapsed ) { if (!mEnabled) { return false; } if (mStyle == CS_FREELOOK) { DiVec3 accel = DiVec3::ZERO; if (mGoingForward) { accel += mCamera->GetDirection(); } if (mGoingBack) accel -= mCamera->GetDirection(); if (mGoingRight) accel += mCamera->GetRight(); if (mGoingLeft) accel -= mCamera->GetRight(); if (mGoingUp) accel += mCamera->GetUp(); if (mGoingDown) accel -= mCamera->GetUp(); float topSpeed = mFastMove ? mTopSpeed * 20 : mTopSpeed; if (accel.squaredLength() != 0) { accel.normalise(); mVelocity += accel * topSpeed * elapsed * 10; } else { mVelocity -= mVelocity * elapsed * 10; } float tooSmall = std::numeric_limits<float>::epsilon(); if (mVelocity.squaredLength() > topSpeed * topSpeed) { mVelocity.normalise(); mVelocity *= topSpeed; } else if (mVelocity.squaredLength() < tooSmall * tooSmall) { mVelocity = DiVec3::ZERO; } if (mVelocity != DiVec3::ZERO) { mCamera->Move(mVelocity * elapsed); } } else if (mStyle == CS_SMOOTH) { if (Driver && mMousePos.x >= 0 && mMousePos.y >= 0) { DiRenderWindow* window = Driver->GetMainRenderWindow(); int x = (mMousePos.x - window->GetWidth() / 2); int y = (mMousePos.y - window->GetHeight() / 2); DiVec3 pos = mCamera->GetPosition(); pos.x += (x - pos.x) * 0.01f; pos.y += (-y - pos.y) * 0.01f; mCamera->SetPosition(pos); mCamera->LookAt(0, 0, 0); } } return true; }