0
\$\begingroup\$

I have a side camera that can be set on run-time with changeable field of view with GUI. I am searching for a way to show the field of view of the side camera using my main camera. I am thinking about custom mesh creation through code so that it can be generated alongside the camera rectangle, but it seems too complex. Should I proceed with this method or are there any other solutions?[!

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Am I correct to think that you want a (wireframe) pyramid shape where the tip is the location of the camera lens and the base points towards where the camera is pointing? The pyramid would require a deformation that matches your camera settings (field of view angle determines the slope of the sides, projection determines the size of the base). Is this what you're looking for? \$\endgroup\$ – Felsir Dec 13 '16 at 10:48
  • \$\begingroup\$ @Felsir yes i want to show a payramid shape that i can see show much area is covered by the camera.see photo. The payramid must require to match the camera angle \$\endgroup\$ – Muhammad Faizan Khan Dec 13 '16 at 10:50
1
\$\begingroup\$

I was interested in this and thought I'd try and make a "field of view pyramid object" on a camera. This isn't a good method to include inside Update but you can make it into an onCall method and call it when it's needed. Here's the code (pyramid making code was taken from here and here and modified to make a "fov indicator"):

void Start ()
{
    cam = gameObject.GetComponent<Camera>(); //finds camera on this object
    GameObject g = GameObject.CreatePrimitive(PrimitiveType.Cube); //makes a cube
    Destroy(g.GetComponent<BoxCollider>()); //destroy the box collider on the cube because it's not needed
    MeshFilter meshFilter = g.GetComponent<MeshFilter>(); //get the meshfilter on cube
    //make a new mesh
    Mesh mesh = new Mesh();
    Vector3[] points = new Vector3[5];
    points[0] = cam.transform.position;
    points[1] = cam.ViewportToWorldPoint(new Vector3(0, 0, cam.farClipPlane));
    points[2] = cam.ViewportToWorldPoint(new Vector3(0, 1, cam.farClipPlane));
    points[3] = cam.ViewportToWorldPoint(new Vector3(1, 0, cam.farClipPlane));
    points[4] = cam.ViewportToWorldPoint(new Vector3(1, 1, cam.farClipPlane));
    mesh.vertices = new Vector3[] {
        points[0], points[1], points[2],
        points[0], points[3], points[1],
        points[0], points[4], points[2],
        points[0], points[3], points[4],
        points[1], points[2], points[4],
        points[1], points[4], points[3]
    };

    mesh.triangles = new int[] {
        0, 1, 2,
        3, 4, 5,
        8, 7, 6,
        11, 10, 9,
        14, 13, 12,
        17, 16, 15
    };

    mesh.RecalculateNormals();
    mesh.RecalculateBounds();
    mesh.MarkDynamic();
    //set the new mesh to cube's mesh
    meshFilter.mesh = mesh;
    //set the camera as the cube's parent
    g.transform.SetParent(cam.transform);
}

Demo: enter image description here

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ can i make it hallow? \$\endgroup\$ – Muhammad Faizan Khan Dec 14 '16 at 5:40
  • \$\begingroup\$ Change the material into something like wireframe. Unity store should have some of those free assets. One example: assetstore.unity3d.com/en/#!/content/21897 (of course, with this method, you'll have a cross like going through the bottom of the pyramid, because that's what the mesh is rendered as. It might also not show the mesh from the other side (it would be invisible if you were to go inside it) So, you need to draw the pyramid with the other side too. For example, for the line p[0],p[1],p[2], you also need to add p[0],p[2],p[1], so that it shows from the other side. \$\endgroup\$ – John Hamilton Dec 14 '16 at 5:42
  • \$\begingroup\$ hi john, can i restrict the mesh if it collides with any object? \$\endgroup\$ – Muhammad Faizan Khan Dec 15 '16 at 7:12
  • \$\begingroup\$ @MohammadFaizanKhan I'm not sure and that would be an entirely new question. You could make it hide behind all objects though, using render queues. \$\endgroup\$ – John Hamilton Dec 15 '16 at 7:19
  • \$\begingroup\$ render queues is not smart enough! I am checking this complex tuts youtube.com/watch?v=73Dc5JTCmKI \$\endgroup\$ – Muhammad Faizan Khan Dec 15 '16 at 7:26
0
\$\begingroup\$

You're probably looking for frustum calculations. There's a Unity built-in method on the Camera class if I recall correctly. Ah nope, GeometryUtility.

It's generally used as the input to GeometryUtility.TestPlanesAABB to see if a given collier is inside the view frustum (for render culling; i.e. hiding stuff behind the camera). However, you could write your own code to calculate a percentage value from the default camera, depending on your actual goal. That is the ratio FOV1 / FOV2 might be sufficient for your needs. Or perhaps not.

I'm including the following method for generating a view frustum from an arbitrary point (no Camera component needed) as it will be helpful in understanding what, exactly, the GeometryUtility method does in the event you need to compare two Plane arrays. This code returns an identical set of Planes as the GeometryUtility method.

    public static Plane[] CalculateFrustum(Vector3 origin, Vector3 direction, float fovRadians, float viewRatio, float distance) {
        Vector3 nearCenter = origin + direction * 0.3f;
        Vector3 farCenter  = origin + direction * distance;
        Vector3 camRight   = Vector3.Cross(direction,Vector3.up) * -1;
        Vector3 camUp      = Vector3.Cross(direction,camRight);

        float nearHeight = 2 * Mathf.Tan(fovRadians / 2) * 0.3f;
        float farHeight  = 2 * Mathf.Tan(fovRadians / 2) * distance;
        float nearWidth  = nearHeight * viewRatio;
        float farWidth   = farHeight * viewRatio;

        Vector3 farTopLeft  = farCenter + camUp*(farHeight*0.5f) - camRight*(farWidth*0.5f);//new Vector3(-camRight.x * (farWidth*0.5f), (farHeight*0.5f), -camRight.z * (farWidth*0.5f));
        //Vector3 farTopRight = farCenter + camUp*(farHeight*0.5f) + camRight*(farWidth*0.5f);//new Vector3( camRight.x * (farWidth*0.5f), (farHeight*0.5f),  camRight.z * (farWidth*0.5f));
        Vector3 farBottomLeft  = farCenter - camUp*(farHeight*0.5f) - camRight*(farWidth*0.5f);//new Vector3(-camRight.x * (farWidth*0.5f), -(farHeight*0.5f), -camRight.z * (farWidth*0.5f));
        Vector3 farBottomRight = farCenter - camUp*(farHeight*0.5f) + camRight*(farWidth*0.5f);//new Vector3( camRight.x * (farWidth*0.5f), -(farHeight*0.5f),  camRight.z * (farWidth*0.5f));

        Vector3 nearTopLeft  = nearCenter + camUp*(nearHeight*0.5f) - camRight*(nearWidth*0.5f);//new Vector3(-camRight.x * (nearWidth*0.5f), farCenter.y + (nearHeight*0.5f), -camRight.z * (nearWidth*0.5f));
        Vector3 nearTopRight = nearCenter + camUp*(nearHeight*0.5f) + camRight*(nearWidth*0.5f);//new Vector3( camRight.x * (nearWidth*0.5f), farCenter.y + (nearHeight*0.5f),  camRight.z * (nearWidth*0.5f));
        //Vector3 nearBottomLeft  = nearCenter - camUp*(nearHeight*0.5f) - camRight*(nearWidth*0.5f);//new Vector3(-camRight.x * (nearWidth*0.5f), farCenter.y - (nearHeight*0.5f), -camRight.z * (nearWidth*0.5f));
        Vector3 nearBottomRight = nearCenter - camUp*(nearHeight*0.5f) + camRight*(nearWidth*0.5f);//new Vector3( camRight.x * (nearWidth*0.5f), farCenter.y - (nearHeight*0.5f),  camRight.z * (nearWidth*0.5f));
        Plane[] planes = {
            new Plane(nearTopLeft,farTopLeft,farBottomLeft),
            new Plane(nearTopRight,nearBottomRight,farBottomRight),

            new Plane(farBottomLeft,farBottomRight,nearBottomRight),
            new Plane(farTopLeft,nearTopLeft,nearTopRight),

            new Plane(nearBottomRight,nearTopRight,nearTopLeft),
            new Plane(farBottomRight,farBottomLeft,farTopLeft)};

        return planes;
    }
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I simply want to show that how much area covered by main camera. like i map any mesh along side my camera rect. \$\endgroup\$ – Muhammad Faizan Khan Dec 13 '16 at 7:28
  • \$\begingroup\$ You want to display the FOV volume? Then I misunderstood. \$\endgroup\$ – Draco18s no longer trusts SE Dec 13 '16 at 16:23
  • \$\begingroup\$ yes. I want to visualize fov \$\endgroup\$ – Muhammad Faizan Khan Dec 15 '16 at 7:11
  • \$\begingroup\$ Ah. In which case, you can either use GeometryUtility.CalculateFrustumPlanes and render the resulting planes (transparent, low opacity) or use them or the code I posted to generate a mesh based on the planar intersection points (the 8 points of the view frustum are in the code I posted). Then render that mesh (I'd suggest using a wireframe shader in that case). Or you could render just the far-view portion (over the top of everything, obviously). \$\endgroup\$ – Draco18s no longer trusts SE Dec 15 '16 at 18:07
  • \$\begingroup\$ The main problem with approach is that if any object occur ahead of fov then at that point FOV mesh points should be stopped. \$\endgroup\$ – Muhammad Faizan Khan Dec 16 '16 at 4:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.