//------------------------------------------------------------------------ void CView::Update(float frameTime,bool isActive) { //FIXME:some cameras may need to be updated always if (!isActive) return; CGameObject* pLinkedTo = GetLinkedGameObject(); if (pLinkedTo && !pLinkedTo->CanUpdateView()) pLinkedTo = nullptr; IEntity* pEntity = pLinkedTo ? 0 : GetLinkedEntity(); if (pLinkedTo || pEntity) { m_viewParams.SaveLast(); CCamera* pSysCam = &m_pSystem->GetViewCamera(); //process screen shaking ProcessShaking(frameTime); //FIXME:to let the updateView implementation use the correct shakeVector m_viewParams.currentShakeShift = m_viewParams.rotation * m_viewParams.currentShakeShift; m_viewParams.frameTime = frameTime; //update view position/rotation if (pLinkedTo) { pLinkedTo->UpdateView(m_viewParams); if (!m_viewParams.position.IsValid()) { m_viewParams.position = m_viewParams.GetPositionLast(); CRY_ASSERT_MESSAGE(0, "Camera position is invalid, reverting to old position"); } if (!m_viewParams.rotation.IsValid()) { m_viewParams.rotation = m_viewParams.GetRotationLast(); CRY_ASSERT_MESSAGE(0, "Camera rotation is invalid, reverting to old rotation"); } } else { Matrix34 mat = pEntity->GetWorldTM(); mat.OrthonormalizeFast(); m_viewParams.position = mat.GetTranslation(); m_viewParams.rotation = Quat(mat); } ApplyFrameAdditiveAngles(m_viewParams.rotation); if (pLinkedTo) { pLinkedTo->PostUpdateView(m_viewParams); } const float fNearZ = gEnv->pGame->GetIGameFramework()->GetIViewSystem()->GetDefaultZNear(); //see if the view have to use a custom near clipping plane const float nearPlane = (m_viewParams.nearplane >= 0.01f) ? (m_viewParams.nearplane) : fNearZ; const float farPlane = gEnv->p3DEngine->GetMaxViewDistance(); float fov = (m_viewParams.fov < 0.001f) ? DEFAULT_FOV : m_viewParams.fov; // [VR] specific // Modify FOV based on the HDM device configuration IHmdManager* pHmdManager = gEnv->pSystem->GetHmdManager(); IHmdDevice* pHmdDevice = nullptr; bool bHmdTrackingEnabled = false; if (pHmdManager) { pHmdDevice = pHmdManager->GetHmdDevice(); if (pHmdDevice) { const HmdTrackingState &sensorState = pHmdDevice->GetLocalTrackingState(); if (sensorState.CheckStatusFlags(eHmdStatus_IsUsable)) { bHmdTrackingEnabled = true; } } } if (pHmdManager->IsStereoSetupOk()) { const IHmdDevice* pDev = pHmdManager->GetHmdDevice(); const HmdTrackingState &sensorState = pDev->GetLocalTrackingState(); if (sensorState.CheckStatusFlags(eHmdStatus_IsUsable)) { float arf_notUsed; pDev->GetCameraSetupInfo(fov, arf_notUsed); } } m_camera.SetFrustum(pSysCam->GetViewSurfaceX(), pSysCam->GetViewSurfaceZ(), fov, nearPlane, farPlane, pSysCam->GetPixelAspectRatio()); //TODO: (14, 06, 2010, "the player view should always get updated, this due to the hud being visable, without shocking, in cutscenes - todo is to see if we can optimise this code"); IActor* pActor = gEnv->pGame->GetIGameFramework()->GetClientActor(); if (pActor) { CGameObject* const linkToObj = static_cast<CGameObject*>(pActor->GetEntity()->GetProxy(ENTITY_PROXY_USER)); if (linkToObj && linkToObj != pLinkedTo) { linkToObj->PostUpdateView(m_viewParams); } } //apply shake & set the view matrix m_viewParams.rotation *= m_viewParams.currentShakeQuat; m_viewParams.rotation.NormalizeSafe(); m_viewParams.position += m_viewParams.currentShakeShift; // Camera space Rendering calculations on Entity if (pLinkedTo) { IEntity* pLinkedToEntity = pLinkedTo->GetEntity(); if (pLinkedToEntity) { const int slotIndex = 0; uint32 entityFlags = pLinkedToEntity->GetSlotFlags(slotIndex); if (entityFlags & ENTITY_SLOT_RENDER_NEAREST) { // Get camera pos relative to entity const Vec3 cameraLocalPos = m_viewParams.position; // Set entity's camera space position const Vec3 cameraSpacePos(-cameraLocalPos * m_viewParams.rotation); pLinkedToEntity->SetSlotCameraSpacePos(slotIndex,cameraSpacePos); // Add world pos onto camera local pos m_viewParams.position = pLinkedToEntity->GetWorldPos() + cameraLocalPos; } } } // Blending between cameras needs to happen after Camera space rendering calculations have been applied // so that the m_viewParams.position is in World Space again m_viewParams.UpdateBlending(frameTime); // [VR] specific // Add HMD's pose tracking on top of current camera pose // Each game-title can decide whether to keep this functionality here or (most likely) // move it somewhere else. Quat q = m_viewParams.rotation; Vec3 pos = m_viewParams.position; Vec3 p = Vec3(ZERO); // Uses the recorded tracking if time demo is on playback // Otherwise uses real tracking from device ITimeDemoRecorder* pTimeDemoRecorder = gEnv->pGame->GetIGameFramework()->GetITimeDemoRecorder(); if (pTimeDemoRecorder && pTimeDemoRecorder->IsPlaying()) { STimeDemoFrameRecord record; pTimeDemoRecorder->GetCurrentFrameRecord(record); p = q * record.hmdPositionOffset; q = q * record.hmdViewRotation; } else if (bHmdTrackingEnabled) { pHmdDevice->SetAsynCameraCallback(this); if (pHmdReferencePoint && pHmdReferencePoint->GetIVal() == 1) // actor-centered HMD offset { const IEntity* pEnt = GetLinkedEntity(); if (const IActor* pActor = gEnv->pGame->GetIGameFramework()->GetClientActor()) { if (pEnt && pActor->GetEntity() == pEnt) { q = pEnt->GetWorldRotation(); pos = pEnt->GetWorldPos(); } } } const HmdTrackingState &sensorState = pHmdDevice->GetLocalTrackingState(); p = q * sensorState.pose.position; q = q * sensorState.pose.orientation; } Matrix34 viewMtx(q); viewMtx.SetTranslation(pos + p); m_camera.SetMatrix(viewMtx); } else { m_linkedTo = 0; CCryAction* pCryAction = CCryAction::GetCryAction(); if (!pCryAction->IsGameSessionMigrating()) // If we're host migrating, leave the camera where it was { // Check if we're leaving a game mid way through - if we are then stop the camera from being reset for a frame or 2 before the unload happens if (!pCryAction->GetIGameSessionHandler()->IsMidGameLeaving()) { m_camera.SetPosition(Vec3(1,1,1)); } } } }
//------------------------------------------------------------------------ void CView::Update(float frameTime,bool isActive) { //FIXME:some cameras may need to be updated always if (!isActive) return; CGameObject * pLinkedTo = GetLinkedGameObject(); if (pLinkedTo && !pLinkedTo->CanUpdateView()) pLinkedTo = NULL; IEntity* pEntity = pLinkedTo ? 0 : GetLinkedEntity(); if (pLinkedTo || pEntity) { m_viewParams.SaveLast(); CCamera *pSysCam = &m_pSystem->GetViewCamera(); //process screen shaking ProcessShaking(frameTime); //FIXME:to let the updateView implementation use the correct shakeVector m_viewParams.currentShakeShift = m_viewParams.rotation * m_viewParams.currentShakeShift; m_viewParams.frameTime=frameTime; //update view position/rotation if (pLinkedTo) { pLinkedTo->UpdateView(m_viewParams); if (!m_viewParams.position.IsValid()) { m_viewParams.position = m_viewParams.GetPositionLast(); CRY_ASSERT_MESSAGE(0, "Camera position is invalid, reverting to old position"); } if (!m_viewParams.rotation.IsValid()) { m_viewParams.rotation = m_viewParams.GetRotationLast(); CRY_ASSERT_MESSAGE(0, "Camera rotation is invalid, reverting to old rotation"); } } else { Matrix34 mat = pEntity->GetWorldTM(); mat.OrthonormalizeFast(); m_viewParams.position = mat.GetTranslation(); m_viewParams.rotation = Quat(mat); } ApplyFrameAdditiveAngles(m_viewParams.rotation); if (pLinkedTo) { pLinkedTo->PostUpdateView(m_viewParams); } float fNearZ = gEnv->pGame->GetIGameFramework()->GetIViewSystem()->GetDefaultZNear(); //see if the view have to use a custom near clipping plane float nearPlane = (m_viewParams.nearplane > 0.01f)?(m_viewParams.nearplane):(fNearZ/*pSysCam->GetNearPlane()*/); float farPlane = gEnv->p3DEngine->GetMaxViewDistance(); float fov = m_viewParams.fov < 0.001 ? DEFAULT_FOV : m_viewParams.fov; m_camera.SetFrustum(pSysCam->GetViewSurfaceX(),pSysCam->GetViewSurfaceZ(),fov,nearPlane,farPlane, pSysCam->GetPixelAspectRatio()); //TODO: (14, 06, 2010, "the player view should always get updated, this due to the hud being visable, without shocking, in cutscenes - todo is to see if we can optimise this code"); IActor * pActor = gEnv->pGame->GetIGameFramework()->GetClientActor(); if (pActor) { CGameObject * linkToObj = (CGameObject*)pActor->GetEntity()->GetProxy( ENTITY_PROXY_USER ); if (linkToObj && linkToObj != pLinkedTo) { linkToObj->PostUpdateView(m_viewParams); } } //apply shake & set the view matrix m_viewParams.rotation *= m_viewParams.currentShakeQuat; m_viewParams.rotation.NormalizeSafe(); m_viewParams.position += m_viewParams.currentShakeShift; // Camera space Rendering calculations on Entity if(pLinkedTo) { IEntity* pLinkedToEntity = pLinkedTo->GetEntity(); if(pLinkedToEntity) { const int slotIndex = 0; uint32 entityFlags = pLinkedToEntity->GetSlotFlags(slotIndex); if(entityFlags & ENTITY_SLOT_RENDER_NEAREST) { // Get camera pos relative to entity const Vec3 cameraLocalPos = m_viewParams.position; // Set entity's camera space position const Vec3 cameraSpacePos(-cameraLocalPos * m_viewParams.rotation); pLinkedToEntity->SetSlotCameraSpacePos(slotIndex,cameraSpacePos); // Add world pos onto camera local pos m_viewParams.position = pLinkedToEntity->GetWorldPos() + cameraLocalPos; } } } // Blending between cameras needs to happen after Camera space rendering calculations have been applied // so that the m_viewParams.position is in World Space again m_viewParams.UpdateBlending(frameTime); Matrix34 viewMtx(m_viewParams.rotation); viewMtx.SetTranslation(m_viewParams.position); m_camera.SetMatrix(viewMtx); } else { m_linkedTo = 0; CCryAction *pCryAction = CCryAction::GetCryAction(); if (!pCryAction->IsGameSessionMigrating()) // If we're host migrating, leave the camera where it was { // Check if we're leaving a game mid way through - if we are then stop the camera from being reset for a frame or 2 before the unload happens if (!pCryAction->GetIGameSessionHandler()->IsMidGameLeaving()) { m_camera.SetPosition(Vec3(1,1,1)); } } } }