Скрипт также как и GeometryUtility.CalculateFrustumPlanes(camera) создает плоскости для использования в GeometryUtility.TestPlanesAABB(planes : Plane[], bounds : Bounds), но в отличие от первого используется не вся ближняя плоскость камеры, а только нужная прямоугольная область на ней.
Синтаксис:
Используется csharp
public static class CameraExt
{
private static int[] m_VertOrder = new int[24]
{
0,1,2,3, // near
6,5,4,7, // far
0,4,5,1, // left
3,2,6,7, // right
1,5,6,2, // top
0,3,7,4 // bottom
};
public static Plane[] GenerateFrustumPlanes(this Camera cam, float x1, float y1, float x2, float y2)
{
DoCorrectCoordinates(ref x1, ref y1, ref x2, ref y2);
Vector3[] vScreen = new Vector3[4];
vScreen[0] = cam.ScreenToViewportPoint(new Vector3(x1, y1));
vScreen[1] = cam.ScreenToViewportPoint(new Vector3(x1, y2));
vScreen[2] = cam.ScreenToViewportPoint(new Vector3(x2, y2));
vScreen[3] = cam.ScreenToViewportPoint(new Vector3(x2, y1));
Vector3[] v = new Vector3[8];
for (int i = 0; i < 4; i++)
v[i] =v[i+4]= vScreen[i];
v[0].z = v[1].z = v[2].z = v[3].z = cam.nearClipPlane;
v[4].z = v[5].z = v[6].z = v[7].z = cam.farClipPlane;
// Transform viewport --> world
for (int i = 0; i < 8; i++)
v[i] = cam.ViewportToWorldPoint(v[i]) *-1.0f;
Plane[] planes = new Plane[6];
planes[0] = new Plane(v[0], v[1], v[2]);//near
planes[1] = new Plane(v[6], v[5], v[4]);//far
planes[2] = new Plane(v[0], v[4], v[5]);//left
planes[3] = new Plane(v[3], v[2], v[6]);//right
planes[4] = new Plane(v[1], v[5], v[6]);//top
planes[5] = new Plane(v[0], v[3], v[7]);//bottom
for (int i = 0; i < 6; i++)
planes[i].normal *= -1.0f;
#region Отображение Frustum в редакторе
#if UNITY_EDITOR
for (int i = 0; i < 8; i++)
v[i] *= -1f;
for (int i = 0; i < 4; i++)
{
int j = (i != 3) ? i : -1;
Debug.DrawLine(v[m_VertOrder[i]], v[m_VertOrder[4 + 2 - j]], Color.blue, 10.0f);
Debug.DrawLine(v[m_VertOrder[i]], v[m_VertOrder[j + 1]], Color.blue, 10.0f);
Debug.DrawLine(v[m_VertOrder[i + 4]], v[m_VertOrder[j + 5]], Color.blue, 10.0f);
}
#endif
#endregion
return planes;
}
#endregion
private static void DoCorrectCoordinates(ref float x1, ref float y1, ref float x2, ref float y2)
{
//если координаты равны, то увеличиваем размер области, чтобы пирамида генерировалась корректно
if (x1 == x2)
x2++;
if (y1 == y2)
y2++;
//устанавливаем x1,y1 как минимумы, а x2,y2 как максимумы
if (x1 > x2)
{
float temp = x1;
x1 = x2;
x2 = temp;
}
if (y1 > y2)
{
float temp = y1;
y1 = y2;
y2 = temp;
}
}
}
{
private static int[] m_VertOrder = new int[24]
{
0,1,2,3, // near
6,5,4,7, // far
0,4,5,1, // left
3,2,6,7, // right
1,5,6,2, // top
0,3,7,4 // bottom
};
public static Plane[] GenerateFrustumPlanes(this Camera cam, float x1, float y1, float x2, float y2)
{
DoCorrectCoordinates(ref x1, ref y1, ref x2, ref y2);
Vector3[] vScreen = new Vector3[4];
vScreen[0] = cam.ScreenToViewportPoint(new Vector3(x1, y1));
vScreen[1] = cam.ScreenToViewportPoint(new Vector3(x1, y2));
vScreen[2] = cam.ScreenToViewportPoint(new Vector3(x2, y2));
vScreen[3] = cam.ScreenToViewportPoint(new Vector3(x2, y1));
Vector3[] v = new Vector3[8];
for (int i = 0; i < 4; i++)
v[i] =v[i+4]= vScreen[i];
v[0].z = v[1].z = v[2].z = v[3].z = cam.nearClipPlane;
v[4].z = v[5].z = v[6].z = v[7].z = cam.farClipPlane;
// Transform viewport --> world
for (int i = 0; i < 8; i++)
v[i] = cam.ViewportToWorldPoint(v[i]) *-1.0f;
Plane[] planes = new Plane[6];
planes[0] = new Plane(v[0], v[1], v[2]);//near
planes[1] = new Plane(v[6], v[5], v[4]);//far
planes[2] = new Plane(v[0], v[4], v[5]);//left
planes[3] = new Plane(v[3], v[2], v[6]);//right
planes[4] = new Plane(v[1], v[5], v[6]);//top
planes[5] = new Plane(v[0], v[3], v[7]);//bottom
for (int i = 0; i < 6; i++)
planes[i].normal *= -1.0f;
#region Отображение Frustum в редакторе
#if UNITY_EDITOR
for (int i = 0; i < 8; i++)
v[i] *= -1f;
for (int i = 0; i < 4; i++)
{
int j = (i != 3) ? i : -1;
Debug.DrawLine(v[m_VertOrder[i]], v[m_VertOrder[4 + 2 - j]], Color.blue, 10.0f);
Debug.DrawLine(v[m_VertOrder[i]], v[m_VertOrder[j + 1]], Color.blue, 10.0f);
Debug.DrawLine(v[m_VertOrder[i + 4]], v[m_VertOrder[j + 5]], Color.blue, 10.0f);
}
#endif
#endregion
return planes;
}
#endregion
private static void DoCorrectCoordinates(ref float x1, ref float y1, ref float x2, ref float y2)
{
//если координаты равны, то увеличиваем размер области, чтобы пирамида генерировалась корректно
if (x1 == x2)
x2++;
if (y1 == y2)
y2++;
//устанавливаем x1,y1 как минимумы, а x2,y2 как максимумы
if (x1 > x2)
{
float temp = x1;
x1 = x2;
x2 = temp;
}
if (y1 > y2)
{
float temp = y1;
y1 = y2;
y2 = temp;
}
}
}
пример использования:
x1, y1, x2, y2 - экранные координаты произвольной прямоугольной области
Синтаксис:
Используется csharp
Plane[] planes = Camera.main.GenerateFrustumPlanes(x1, y1, x2, y2);
GeometryUtility.TestPlanesAABB(planes, myGameObject.collider.bounds))
GeometryUtility.TestPlanesAABB(planes, myGameObject.collider.bounds))