using Godot; using System.Text; using System.Collections.Generic; namespace Rokojori { public class Cameras { public static float ComputeCameraFrameFittingDistance( Camera3D camera, float radius ) { var fovRadians = Mathf.DegToRad( camera.Fov ); return ( radius * 2 ) / Mathf.Tan( fovRadians / 2.0f ); } public static float ComputeCameraFrameFittingDistance( float fovDegrees, float radius ) { var fovRadians = Mathf.DegToRad( fovDegrees ); return ( radius * 2 ) / Mathf.Tan( fovRadians / 2.0f ); } public static float ComputeCameraFittingScale( float fovDegrees, float distance ) { var fovRadians = Mathf.DegToRad( fovDegrees ); return distance / ( 0.5f / Mathf.Tan( fovRadians / 2.0f ) ); } public static float ComputeFOVForBillboard( float fovDegrees, float radius, float placingDistance ) { var fovRadians = Mathf.DegToRad( fovDegrees ); var d = ( radius * Mathf.Tan( fovRadians / 2f ) ) / placingDistance; var rads = 2f * Mathf.Atan( d ); return Mathf.RadToDeg( rads ); } public static float ComputePixelDensityVertical( float fovDegrees, float distance, Vector2 screenSize ) { float fovRadians = Mathf.DegToRad( fovDegrees ); float verticalViewSize = 2.0f * distance * Mathf.Tan( fovRadians / 2.0f ); float screenHeightPixels = screenSize.Y; float pixelDensity = screenHeightPixels / verticalViewSize; return pixelDensity; } public static float ComputeSizeOfPixelVertical( float fovDegrees, float distance, Vector2 screenSize ) { return ComputePixelDensityVertical( fovDegrees, distance, screenSize ); } public static float ComputePixelDistanceForSizeVertical( float fovDegrees, float size, Vector2 screenSize ) { float fovRadians = Mathf.DegToRad(fovDegrees); float screenHeightPixels = screenSize.Y; float pixelDensity = 1.0f / size; float distance = screenHeightPixels / (2.0f * pixelDensity * Mathf.Tan(fovRadians / 2.0f)); return distance; } public static float ComputePixelDensityHorizontal(float fovDegrees, float distance, Vector2 screenSize) { float aspectRatio = screenSize.X / screenSize.Y; float verticalFovRad = Mathf.DegToRad( fovDegrees ); float horizontalFovRad = 2.0f * Mathf.Atan(Mathf.Tan( verticalFovRad / 2.0f ) * aspectRatio); float horizontalViewSize = 2.0f * distance * Mathf.Tan( horizontalFovRad / 2.0f ); float pixelDensity = screenSize.X / horizontalViewSize; return pixelDensity; } public static Vector3 GlobalToView( Transform3D transform, Vector3 globalPosition ) { return globalPosition * transform; } public static Vector3 ViewToClip( Projection cameraProjection, Vector3 viewPosition ) { var clip = cameraProjection * viewPosition; return clip; } public static Vector2 ClipToScreen( Vector3 clipPosition ) { var size = Vector2.One; var clip = clipPosition.XY() * 0.5f + new Vector2( 0.5f, 0.5f ); return clip * size; } public static Vector2 ClipToScreen( Vector3 clipPosition, Vector2 screenPixelSize ) { var clip = clipPosition.XY() * 0.5f + new Vector2( 0.5f, 0.5f ); return clip * screenPixelSize; } public static Vector2 GlobalToScreen( Vector3 globalPosition, Transform3D cameraTransform, Projection cameraProjection, Vector2 screenPixelSize ) { var view = GlobalToView( cameraTransform, globalPosition ); var clip = ViewToClip( cameraProjection, view ); var screen = ClipToScreen( clip, screenPixelSize ); return screen; } } }