using UnityEngine;
using System.Globalization;
namespace OmiLAXR.Types
{
public struct Frustum
{
public readonly float ZNear;
public readonly float ZFar;
public readonly float FovX;
public readonly float FovY;
public Frustum(float zNear, float zFar, float fovX, float fovY)
{
ZNear = zNear;
ZFar = zFar;
FovX = fovX;
FovY = fovY;
}
///
/// Liefert das symmetrische Frustum der (Mono-)Kamera.
/// FovX/FovY sind in Grad. Gilt für Perspective-Kameras.
///
public static Frustum FromCamera(Camera cam)
{
if (cam == null) throw new System.ArgumentNullException(nameof(cam));
if (cam.orthographic)
throw new System.NotSupportedException("Orthographic-Kameras haben kein sinnvolles FOV. Nutze Breite/Höhe statt FOV.");
var zNear = cam.nearClipPlane;
var zFar = cam.farClipPlane;
var fovY = cam.fieldOfView; // Vertikales FOV in Grad
var fovX = 2f * Mathf.Atan(Mathf.Tan(fovY * Mathf.Deg2Rad * 0.5f) * cam.aspect) * Mathf.Rad2Deg;
return new Frustum(zNear, zFar, fovX, fovY);
}
///
/// Liefert das (symmetrisch angenäherte) Frustum für ein Stereo-Auge.
/// Nutzt die per-Auge-Projektionsmatrix, falls Stereo aktiv ist.
///
public static Frustum FromCameraStereo(Camera cam, Camera.StereoscopicEye eye)
{
if (cam == null) throw new System.ArgumentNullException(nameof(cam));
if (!cam.stereoEnabled)
return FromCamera(cam); // Fallback
if (cam.orthographic)
throw new System.NotSupportedException("Orthographic-Kameras haben kein sinnvolles FOV. Nutze Breite/Höhe statt FOV.");
var P = cam.GetStereoProjectionMatrix(eye);
var zNear = cam.nearClipPlane;
var zFar = cam.farClipPlane;
// Für ein (nahezu) symmetrisches FOV genügen m00/m11:
var fovY = 2f * Mathf.Atan(1f / P[1,1]) * Mathf.Rad2Deg;
var fovX = 2f * Mathf.Atan(1f / P[0,0]) * Mathf.Rad2Deg;
return new Frustum(zNear, zFar, fovX, fovY);
}
public override string ToString()
=> string.Format(
CultureInfo.InvariantCulture,
"Frustum(zNear={0:0.###}, zFar={1:0.###}, fovX={2:0.###}, fovY={3:0.###})",
ZNear,
ZFar,
FovX,
FovY);
}
}