#if UNITY_EDITOR
using UnityEngine;
using System.Collections.Generic;
namespace O3DWB
{
public class CameraViewVolume
{
#region Private Variables
///
/// Holds the camera view volume points in world space. This array can be accessed
/// using members of the 'CameraViewVolumePoint' as indices.
///
private Vector3[] _worldSpaceVolumePoints;
private Box _worldSpaceAABB;
///
/// This array holds the view volume's planes in world space. The elements in this array
/// can be accessed using members of the 'CameraViewVolumePlane' enum as indices. The
/// planes are stored in the following order: left, right, bottom, top, near, far. All
/// planes are pointing inside the volume.
///
private Plane[] _worldSpacePlanes;
///
/// Holds a collection of rays which unite the view volume points. For example, one of these
/// rays could be the ray which starts from the top left point on the camera near plane and
/// aims towards the camera top left far clip plane point.
///
private Ray3D[] _worldSpaceVolumeEdgeRays;
private float _farClipPlaneDistance;
private float _nearClipPlaneDistance;
#endregion
#region Public Properties
public Vector3[] WorldSpaceVolumePoints { get { return _worldSpaceVolumePoints.Clone() as Vector3[]; } }
public Ray3D[] WorldSpaceVolumeEdgeRays { get { return _worldSpaceVolumeEdgeRays.Clone() as Ray3D[]; } }
public Vector3 TopLeftPointOnNearPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.TopLeftOnNearPlane]; } }
public Vector3 TopRightPointOnNearPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.TopRightOnNearPlane]; } }
public Vector3 BottomRightPointOnNearPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.BottomRightOnNearPlane]; } }
public Vector3 BottomLeftPointOnNearPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.BottomLeftOnNearPlane]; } }
public Vector3 TopLeftPointOnFarPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.TopLeftOnFarPlane]; } }
public Vector3 TopRightPointOnFarPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.TopRightOnFarPlane]; } }
public Vector3 BottomRightPointOnFarPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.BottomRightOnFarPlane]; } }
public Vector3 BottomLeftPointOnFarPlane { get { return _worldSpaceVolumePoints[(int)CameraViewVolumePoint.BottomLeftOnFarPlane]; } }
public float FarClipPlaneDistance { get { return _farClipPlaneDistance; } }
public float NearClipPlaneDistance { get { return _nearClipPlaneDistance; } }
public Box WorldSpaceAABB { get { return _worldSpaceAABB; } }
#endregion
#region Constructors
public CameraViewVolume()
{
}
///
/// Constructor.
///
///
/// The camera whose view volume data is necessary to construct the 'CameraViewVolume' instance.
///
///
/// This can be used to in cases when it's useful to have a view volume that has a smaller or bigger
/// far clip plane distance. This value will override the actual camera far clip plane distance and the
/// view volume will be constructed using this value instead. Note that the far clip plane distance for
/// 'camera' will not be modified.
///
public CameraViewVolume(Camera camera, float desiredCameraFarClipPlane)
{
BuildForCamera(camera, desiredCameraFarClipPlane);
}
#endregion
#region Public Methods
///
/// Builds the camera view volume for the specified camera. Please see the comments for the
/// class constructor in order to understand what the second parameter is about.
///
public void BuildForCamera(Camera camera, float desiredCameraFarClipPlane)
{
// Store the old camera far clip plane distance. We need to do this because we will
// temporarily modify the camera far clip plane to 'desiredCameraFarClipPlane' in order
// to perform all the necessary calculations.
float oldCameraFarClipPlane = camera.farClipPlane;
AdjustCameraFarClipPlane(camera, desiredCameraFarClipPlane);
// Calculate the view volume data
CalculateWorldSpacePoints(camera);
CalculateWorldSpacePlanes(camera);
CalculateWorldSpaceVolumeEdgeRays();
// Restore the camera far clip plane to what it was before
camera.farClipPlane = oldCameraFarClipPlane;
// Store clip plane distances
_farClipPlaneDistance = desiredCameraFarClipPlane;
_nearClipPlaneDistance = camera.nearClipPlane;
_worldSpaceAABB = Box.FromPoints(new List(_worldSpaceVolumePoints));
}
public bool ContainsWorldSpaceAABB(Bounds worldSpaceAABB)
{
return GeometryUtility.TestPlanesAABB(_worldSpacePlanes, worldSpaceAABB);
}
#endregion
#region Private Methods
///
/// Calculates the view volume world space points using the specified camera.
///
private void CalculateWorldSpacePoints(Camera camera)
{
CameraViewVolumePointsCalculator volumePointsCalculator = CameraViewVolumePointsCalculatorFactory.Create(camera);
_worldSpaceVolumePoints = volumePointsCalculator.CalculateWorldSpaceVolumePoints(camera);
}
///
/// Calculates the view volume world space planes using the specified camera.
///
private void CalculateWorldSpacePlanes(Camera camera)
{
_worldSpacePlanes = GeometryUtility.CalculateFrustumPlanes(camera);
}
///
/// Calculates the view volume world space edge rays.
///
private void CalculateWorldSpaceVolumeEdgeRays()
{
_worldSpaceVolumeEdgeRays = CameraViewVolumeEdgeRaysCalculator.CalculateWorldSpaceVolumeEdgeRays(this);
}
///
/// Adjusts the far clip plane distance of 'camera' to 'desiredFarClipPlane'.
///
///
/// The method will ensure that the far clip plane always sits in front of the
/// near plane.
///
private void AdjustCameraFarClipPlane(Camera camera, float desiredFarClipPlane)
{
// Set the far clip plane distance and make sure it sits in front of the near plane.
camera.farClipPlane = desiredFarClipPlane;
EnsureFarClipPlaneSitsInFrontOfNearPlane(camera);
}
///
/// Ensures the the far clip plane of 'camera' always sits in front of the
/// camera's near plane.
///
private void EnsureFarClipPlaneSitsInFrontOfNearPlane(Camera camera)
{
if (camera.farClipPlane <= camera.nearClipPlane) camera.farClipPlane = camera.nearClipPlane + 0.1f;
}
#endregion
}
}
#endif