Search Unity

Drawing camera frustum with a mesh, strange behaviour

Discussion in 'Scripting' started by Thibault-Potier, Oct 23, 2018.

  1. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    Hi

    I need to create a mesh representing the frustum of a camera. I almost have it !!! But somehow there is a problem when i move this camera: the mesh is not following it properly.

    As you can see, i am also drawing the frustum with some "Debug.DrawLine", feeding them the exact same point as my mesh, and it's displaying properly.

    What am i missing ??





    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DrawCamFov : MonoBehaviour {
    6.  
    7.     public Camera cam;
    8.  
    9.     GameObject[] Triangles;
    10.  
    11.     private void Start()
    12.     {
    13.         Triangles = new GameObject[4];
    14.         for (int i = 0; i < 4; i++)
    15.         {
    16.             GameObject child = new GameObject();
    17.             MeshFilter mf = child.AddComponent<MeshFilter>();
    18.             child.transform.parent = cam.transform;
    19.             Triangles[i] = child;
    20.  
    21.             Vector3[] vertices = new Vector3[]
    22.             {
    23.                 Vector3.zero,
    24.                 Vector3.zero,
    25.                 Vector3.zero
    26.             };
    27.             int[] triangles = new int[]
    28.             {
    29.              2,1,0
    30.             };
    31.  
    32.             mf.mesh = new Mesh();
    33.             mf.mesh.vertices = vertices;
    34.             mf.mesh.triangles = triangles;
    35.  
    36.             child.AddComponent<MeshRenderer>();
    37.         }
    38.     }
    39.  
    40.     void Update()
    41.     {
    42.         DrawFrustum(cam);
    43.     }
    44.  
    45.     void DrawFrustum(Camera cam)
    46.     {
    47.         Vector3[] nearCorners = new Vector3[4]; //Approx'd nearplane corners
    48.         Vector3[] farCorners = new Vector3[4]; //Approx'd farplane corners
    49.         Plane[] camPlanes = GeometryUtility.CalculateFrustumPlanes(cam); //get planes from matrix
    50.  
    51.         Plane temp = camPlanes[1]; camPlanes[1] = camPlanes[2]; camPlanes[2] = temp; //swap [1] and [2] so the order is better for the loop
    52.         for (int i = 0; i < 4; i++)
    53.         {
    54.             nearCorners[i] = Plane3Intersect(camPlanes[4], camPlanes[i], camPlanes[(i + 1) % 4]); //near corners on the created projection matrix
    55.             farCorners[i] = Plane3Intersect(camPlanes[5], camPlanes[i], camPlanes[(i + 1) % 4]); //far corners on the created projection matrix
    56.         }
    57.  
    58.         for (int i = 0; i < 4; i++)
    59.         {
    60.             Debug.DrawLine(nearCorners[i], nearCorners[(i + 1) % 4], Color.red, Time.deltaTime, true); //near corners on the created projection matrix
    61.             Debug.DrawLine(farCorners[i], farCorners[(i + 1) % 4], Color.blue, Time.deltaTime, true); //far corners on the created projection matrix
    62.             Debug.DrawLine(nearCorners[i], farCorners[i], Color.green, Time.deltaTime, true); //sides of the created projection matrix
    63.  
    64.  
    65.             Triangles[i].GetComponent<MeshFilter>().mesh.vertices = new[]
    66.              {
    67.                      transform.position,
    68.                      farCorners[i],
    69.                      farCorners[(i + 1) % 4]
    70.              };
    71.         }
    72.     }
    73.  
    74.     Vector3 Plane3Intersect(Plane p1, Plane p2, Plane p3)
    75.     { //get the intersection point of 3 planes
    76.         return ((-p1.distance * Vector3.Cross(p2.normal, p3.normal)) +
    77.                 (-p2.distance * Vector3.Cross(p3.normal, p1.normal)) +
    78.                 (-p3.distance * Vector3.Cross(p1.normal, p2.normal))) /
    79.          (Vector3.Dot(p1.normal, Vector3.Cross(p2.normal, p3.normal)));
    80.     }
    81. }
    82.  
    All the credit for the "working part" of this code should be given to my inspiration source :
    https://grrava.blogspot.com/2014/04/render-view-frustrum-of-camera-in-unity.html
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    I'm guessing your GeometryUtility.CalculateFrustumPlanes is already pre-transforming the coordinates, then you're making the thing a child of the camera itself, so when it turns, it essentially "double turns."

    Relative to the camera's transform, for a given frustum the points will be static, i.e., relative to it.
     
  3. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
  4. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    Aaaaaaand it works perfectly :D

    So if you want to achieve the same thing, replace this function in the previous code with :

    Code (CSharp):
    1. void DrawFrustum(Camera cam)
    2.     {
    3.         Vector3[] frustumCorners = new Vector3[4];
    4.         cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), cam.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
    5.  
    6.         for (int i = 0; i < 4; i++)
    7.         {
    8.             var worldSpaceCorner = cam.transform.TransformVector(frustumCorners[i]);
    9.             Debug.DrawRay(cam.transform.position, worldSpaceCorner, Color.blue);
    10.  
    11.             Triangles[i].GetComponent<MeshFilter>().mesh.vertices = new[]
    12.              {
    13.                      cam.transform.position,
    14.                      frustumCorners[i],
    15.                      frustumCorners[(i + 1) % 4]
    16.                    
    17.             };
    18.         }
    19.     }
    Cleaner, easyer, Better ;)
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    The best lines of code are ones that you delete: they cannot possibly have a bug.
     
  6. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    You may found them better, but :
    Code (CSharp):
    1.  Vector3[] frustumCorners = new Vector3[4];
    2.         camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
    3.  
    works perfectly and fit in 2 lines. Plus it's directly copy and paste from unity documentation.