From e4a321698eb8b2bada23a5ee5e2ee007a9ee4beb Mon Sep 17 00:00:00 2001 From: mq1n Date: Wed, 27 Aug 2025 23:30:28 +0300 Subject: [PATCH] fix camera glitch issue --- src/EterLib/Camera.cpp | 132 ++++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/src/EterLib/Camera.cpp b/src/EterLib/Camera.cpp index f180d1a..201f578 100644 --- a/src/EterLib/Camera.cpp +++ b/src/EterLib/Camera.cpp @@ -5,6 +5,7 @@ #include "StdAfx.h" #include "../eterBase/Utils.h" #include "Camera.h" +#include const float c_fDefaultResistance = 0.3f; @@ -219,6 +220,10 @@ void CCamera::SetViewParams( const D3DXVECTOR3 &v3Eye, const D3DXVECTOR3& v3Targ m_v3Target = v3Target; m_v3Up = v3Up; + // Avoid screen flipping with nan values in the view matrix + if (!m_v3Eye.y) + m_v3Eye.y = 0.1f; + SetViewMatrix(); } @@ -252,40 +257,107 @@ void CCamera::SetUp(const D3DXVECTOR3 & v3Up) SetViewMatrix(); } +bool IsNaN(const D3DXVECTOR3& v) +{ + return std::isnan(v.x) || std::isnan(v.y) || std::isnan(v.z); +} + void CCamera::SetViewMatrix() { + // Calculate view direction m_v3View = m_v3Target - m_v3Eye; + if (IsNaN(m_v3View)) + { + m_v3View = D3DXVECTOR3(0.0f, 0.0f, 1.0f); + } + + // v3CenterRay is the reverse of the view vector D3DXVECTOR3 v3CenterRay = -m_v3View; - CalculateRoll(); + + // Calculate roll (if this function uses m_v3View, ensure it’s valid) + CalculateRoll(); + + // Compute the distance from eye to target m_fDistance = D3DXVec3Length(&m_v3View); + if (std::isnan(m_fDistance)) + { + m_fDistance = 0.0f; + } + m_fDistance = std::fmax(0.0f, m_fDistance); assert(m_fDistance >= 0); - D3DXVec3Normalize(&m_v3View , &m_v3View); - D3DXVec3Cross(&m_v3Cross, &m_v3Up, &m_v3View); - D3DXVec3Normalize(&m_v3Cross, &m_v3Cross); + // Normalize the view vector if possible + if (m_fDistance > FLT_EPSILON) + { + D3DXVec3Normalize(&m_v3View, &m_v3View); + } + else + { + // Avoid dividing by zero; set to a default forward direction + m_v3View = D3DXVECTOR3(0.0f, 0.0f, 1.0f); + } - D3DXVec3Cross(&m_v3Up, &m_v3View, &m_v3Cross); - D3DXVec3Normalize(&m_v3Up, &m_v3Up); - const auto vv = D3DXVECTOR3(0.0f, 0.0f, 1.0f); - m_fPitch = D3DXVec3Dot(&m_v3Up, &vv);// / D3DXVec2Length(&v2ViewYZ); - if (m_fPitch >= 1) - m_fPitch = 1; - else if (m_fPitch <= -1) - m_fPitch = -1; + // Compute the cross product for the right vector and normalize + D3DXVec3Cross(&m_v3Cross, &m_v3Up, &m_v3View); + float crossLength = D3DXVec3Length(&m_v3Cross); + if (crossLength > FLT_EPSILON) + { + D3DXVec3Normalize(&m_v3Cross, &m_v3Cross); + } + else + { + // Use a default right vector if the cross product is near zero + m_v3Cross = D3DXVECTOR3(1.0f, 0.0f, 0.0f); + } + + // Recompute the up vector and normalize + D3DXVec3Cross(&m_v3Up, &m_v3View, &m_v3Cross); + float upLength = D3DXVec3Length(&m_v3Up); + if (upLength > FLT_EPSILON) + { + D3DXVec3Normalize(&m_v3Up, &m_v3Up); + } + else + { + // Use a default up vector. + m_v3Up = D3DXVECTOR3(0.0f, 1.0f, 0.0f); + } + + // Calculate the pitch angle from the up vector + D3DXVECTOR3 val = D3DXVECTOR3(0.0f, 0.0f, 1.0f); + m_fPitch = D3DXVec3Dot(&m_v3Up, &val); + // Clamp the dot product so acosf is safe + if (m_fPitch >= 1.0f) + m_fPitch = 1.0f; + else if (m_fPitch <= -1.0f) + m_fPitch = -1.0f; m_fPitch = acosf(m_fPitch); + if (std::isnan(m_fPitch)) + { + m_fPitch = 0.0f; + } m_fPitch *= (180.0f / D3DX_PI); - if ( 0 < m_v3View.z ) + if (m_v3View.z > 0) m_fPitch = -m_fPitch; + // Build the view matrix. D3DXMatrixLookAtRH(&m_matView, &m_v3Eye, &m_v3Target, &m_v3Up); + // Compute the determinant and check it. float fDeterminantD3DMatView = D3DXMatrixDeterminant(&m_matView); - D3DXMatrixInverse(&m_matInverseView, &fDeterminantD3DMatView, &m_matView); + if (std::isnan(fDeterminantD3DMatView) || fabs(fDeterminantD3DMatView) < FLT_EPSILON) + { + D3DXMatrixIdentity(&m_matInverseView); + } + else + { + D3DXMatrixInverse(&m_matInverseView, &fDeterminantD3DMatView, &m_matView); + } m_matBillboard = m_matInverseView; - m_matBillboard._41 = 0.0f; - m_matBillboard._42 = 0.0f; - m_matBillboard._43 = 0.0f; + m_matBillboard._41 = 0.0f; + m_matBillboard._42 = 0.0f; + m_matBillboard._43 = 0.0f; m_ViewRay.SetStartPoint(m_v3Target); m_ViewRay.SetDirection(v3CenterRay, m_fDistance); @@ -302,21 +374,27 @@ void CCamera::SetViewMatrix() m_kCameraBackToTerrainRay.SetDirection(-m_v3View, m_fTerrainCollisionRadius); m_kCameraLeftToTerrainRay.SetDirection(-m_v3Cross, 3.0f * m_fTerrainCollisionRadius); m_kCameraRightToTerrainRay.SetDirection(m_v3Cross, 3.0f * m_fTerrainCollisionRadius); - const auto vv2 = (v3CenterRay - m_fTerrainCollisionRadius * m_v3Up); - m_kTargetToCameraBottomRay.SetDirection(v3CenterRay - m_fTerrainCollisionRadius * m_v3Up, D3DXVec3Length(&vv2)); + + D3DXVECTOR3 temp = (v3CenterRay - m_fTerrainCollisionRadius * m_v3Up); + m_kTargetToCameraBottomRay.SetDirection(v3CenterRay - m_fTerrainCollisionRadius * m_v3Up, + D3DXVec3Length(&temp)); m_kLeftObjectCollisionRay.SetStartPoint(m_v3Target); m_kTopObjectCollisionRay.SetStartPoint(m_v3Target); m_kRightObjectCollisionRay.SetStartPoint(m_v3Target); m_kBottomObjectCollisionRay.SetStartPoint(m_v3Target); - const auto vv3 = (v3CenterRay + m_fObjectCollisionRadius * m_v3Cross); - const auto vv4 = (v3CenterRay - m_fObjectCollisionRadius * m_v3Cross); - const auto vv5 = (v3CenterRay + m_fObjectCollisionRadius * m_v3Up); - const auto vv6 = (v3CenterRay + m_fObjectCollisionRadius * m_v3Up); - m_kLeftObjectCollisionRay.SetDirection(v3CenterRay + m_fObjectCollisionRadius * m_v3Cross, D3DXVec3Length(&vv3)); - m_kRightObjectCollisionRay.SetDirection(v3CenterRay - m_fObjectCollisionRadius * m_v3Cross, D3DXVec3Length(&vv4)); - m_kTopObjectCollisionRay.SetDirection(v3CenterRay + m_fObjectCollisionRadius * m_v3Up, D3DXVec3Length(&vv5)); - m_kBottomObjectCollisionRay.SetDirection(v3CenterRay - m_fObjectCollisionRadius * m_v3Up, D3DXVec3Length(&vv6)); + + D3DXVECTOR3 val1 = (v3CenterRay + m_fObjectCollisionRadius * m_v3Cross); + m_kLeftObjectCollisionRay.SetDirection(val1, D3DXVec3Length(&val1)); + + D3DXVECTOR3 val2 = (v3CenterRay - m_fObjectCollisionRadius * m_v3Cross); + m_kRightObjectCollisionRay.SetDirection(val2, D3DXVec3Length(&val2)); + + D3DXVECTOR3 val3 = (v3CenterRay + m_fObjectCollisionRadius * m_v3Up); + m_kTopObjectCollisionRay.SetDirection(val3, D3DXVec3Length(&val3)); + + D3DXVECTOR3 val4 = (v3CenterRay - m_fObjectCollisionRadius * m_v3Up); + m_kBottomObjectCollisionRay.SetDirection(val4, D3DXVec3Length(&val4)); } void CCamera::Move(const D3DXVECTOR3 & v3Displacement)