8080
8181#include " W3DDevice/Common/W3DConvert.h"
8282#include " W3DDevice/GameClient/HeightMap.h"
83+ #include " W3DDevice/GameClient/WorldHeightMap.h"
8384#include " W3DDevice/GameClient/W3DAssetManager.h"
8485#include " W3DDevice/GameClient/W3DDisplay.h"
8586#include " W3DDevice/GameClient/W3DScene.h"
@@ -617,7 +618,7 @@ Real W3DView::calcCameraAreaOffset(Real maxEdgeZ)
617618// -------------------------------------------------------------------------------------------------
618619void W3DView::clipCameraIntoAreaConstraints ()
619620{
620- constexpr const Real eps = 1e- 6f ;
621+ constexpr const Real eps = 0 . 1f ;
621622 Coord2D pos = getPosition2D ();
622623 pos.x = clamp (m_cameraAreaConstraints.lo .x + eps, pos.x , m_cameraAreaConstraints.hi .x - eps);
623624 pos.y = clamp (m_cameraAreaConstraints.lo .y + eps, pos.y , m_cameraAreaConstraints.hi .y - eps);
@@ -731,8 +732,6 @@ void W3DView::updateCameraTransform()
731732 if (TheGlobalData->m_headless )
732733 return ;
733734
734- updateCameraClipPlanes ();
735-
736735 Vector3 sourcePos;
737736 Vector3 targetPos;
738737 buildCameraPosition (sourcePos, targetPos);
@@ -762,30 +761,75 @@ void W3DView::updateCameraTransform()
762761}
763762
764763// -------------------------------------------------------------------------------------------------
764+ // TheSuperHackers @tweak The far clip plane is now generally aligned with the actual terrain
765+ // draw size. This is most useful for low camera angles.
765766// -------------------------------------------------------------------------------------------------
766- void W3DView::updateCameraClipPlanes ()
767+ void W3DView::updateCameraClipPlanes (const Matrix3D &transform )
767768{
768- // TheSuperHackers @bugfix Extends the initial far Z from 1200 because that is not enough at
769- // default max height 310 and default pitch 37.5.
770- static_assert (WorldHeightMap::NORMAL_DRAW_WIDTH == WorldHeightMap::NORMAL_DRAW_HEIGHT, " Expects squared draw area" );
771- Real farZ = (WorldHeightMap::NORMAL_DRAW_WIDTH * 1 .08f ) * MAP_XY_FACTOR;
769+ Real farZ;
770+
771+ if (TheGlobalData->m_drawEntireTerrain )
772+ {
773+ farZ = 100000 .0f ;
774+ }
775+ else if (TheTerrainRenderObject && TheTerrainRenderObject->getMap ())
776+ {
777+ WorldHeightMap *heightMap = TheTerrainRenderObject->getMap ();
778+
779+ const Vector3 camPos = transform.Get_Translation ();
780+ const Vector3 camDir = -transform.Get_Z_Vector ();
781+
782+ const Int loX = heightMap->getDrawOrgX () - heightMap->getBorderSize ();
783+ const Int loY = heightMap->getDrawOrgY () - heightMap->getBorderSize ();
784+ const Int hiX = loX + heightMap->getDrawWidth ();
785+ const Int hiY = loY + heightMap->getDrawHeight ();
786+
787+ // Convert to world coordinates
788+ const Real minX = loX * MAP_XY_FACTOR;
789+ const Real minY = loY * MAP_XY_FACTOR;
790+ const Real maxX = hiX * MAP_XY_FACTOR;
791+ const Real maxY = hiY * MAP_XY_FACTOR;
792+
793+ const Real minZ = TheTerrainRenderObject->getMinHeight ();
794+
795+ // Bounding sphere
796+ Vector3 center;
797+ center.X = (minX + maxX) * 0 .5f ;
798+ center.Y = (minY + maxY) * 0 .5f ;
799+ center.Z = minZ - 1 .0f ; // -1 to avoid Z clipping when looking straight down
772800
773- const Real heightMultiplier = m_heightAboveGround / ViewDefaultMaxHeightAboveTerrain;
774- farZ *= std::max (heightMultiplier, 1 .0f );
801+ // Half extents
802+ const Real dx = (maxX - minX) * 0 .5f ;
803+ const Real dy = (maxY - minY) * 0 .5f ;
804+
805+ // Project center
806+ const Vector3 v = center - camPos;
807+ const Real projectedDistanceToCenter = fabs (Vector3::Dot_Product (v, camDir));
808+
809+ // Project radius
810+ const Real projectedRadiusToEdge = fabs (dx * camDir.X ) + fabs (dy * camDir.Y );
811+
812+ // Final far plane
813+ farZ = projectedDistanceToCenter + projectedRadiusToEdge;
814+ }
815+ else
816+ {
817+ farZ = WorldHeightMap::NORMAL_DRAW_WIDTH * MAP_XY_FACTOR;
818+ }
775819
776820 if (m_useRealZoomCam) // WST 10.19.2002
777821 {
778822 if (m_FXPitch < 0 .95f )
779823 {
780- // Extend far Z when we pitch up for RealZoomCam
824+ // Extend far Z when we pitch up for RealZoomCam
781825 farZ /= m_FXPitch;
782826 }
783827 }
784828 else
785829 {
786- if (TheGlobalData-> m_drawEntireTerrain || m_FXPitch < 0 .95f )
830+ if (m_FXPitch < 0 .95f )
787831 {
788- // Extend far clip plane so entire terrain can be visible
832+ // Extend far clip plane so entire terrain can be visible
789833 farZ *= 10 .0f ;
790834 }
791835 }
@@ -810,6 +854,10 @@ void W3DView::setCameraTransform(const Matrix3D &transform)
810854 updateTerrain ();
811855 }
812856
857+ // TheSuperHackers @info Camera clip planes must be updated after the terrain,
858+ // because the new terrain draw size is needed to calculate the far clip plane.
859+ updateCameraClipPlanes (transform);
860+
813861 // TheSuperHackers @fix Notify the Radar about the changed view always.
814862 // This way the radar view box should always be in sync with the camera view.
815863 if (TheRadar)
@@ -875,7 +923,6 @@ void W3DView::set3DCameraLookAt(const Coord3D &pos, const Coord3D &dir, Real rol
875923 Matrix3D transform;
876924 transform.Look_At_Dir (camPos, camDir, roll);
877925
878- updateCameraClipPlanes ();
879926 setCameraTransform (transform);
880927
881928 m_recalcCamera = false ;
0 commit comments