0
\$\begingroup\$

Here is the function to draw a triangle that represents the camera field of view in a minimap. The problem with this code snippet is that when I rotate up and down (Change the pitch of camera) the viewport triangle also rotates up/down.

void makeViewPortCube()
{
    if (player.GetComponent<Camera>() == null)
    {
        // Debug.LogError("Please assing a Main Camera to Follow");
        return;
    }

    if (viewPortMesh == null)
    {
        viewPortGameobject = new GameObject();
        viewPortGameobject.AddComponent<MeshFilter>().mesh = makeStartingMeshForViewPort(2.0f, 2.0f);
        viewPortGameobject.AddComponent<MeshRenderer>().material = materiaForViewPortGameobject();
        viewPortGameobject.name = "View Port Object";
        viewPortMesh = viewPortGameobject.GetComponent<MeshFilter>().mesh;
        viewPortGameobject.layer = LayerMask.NameToLayer("MiniMap");
        viewPortGameobject.transform.position = new Vector3(viewPortGameobject.transform.position.x, /*transform.position.y-*/100, viewPortGameobject.transform.position.z);
    }

    // change vertices of the viewport
    Vector3[] aVertexList = viewPortMesh.vertices;

    if (stopRotation == false)
    {
        //Orignial
        aVertexList[1] = player.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Screen.width, 0, 10f));
        aVertexList[2] = player.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Screen.width, 0, player.GetComponent<Camera>().nearClipPlane));
        aVertexList[3] = player.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, Screen.height / 4, player.GetComponent<Camera>().nearClipPlane));

        aVertexList[0] = player.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(0, Screen.height / 4, 10f));

        for (int i = 0; i < 4; i++)
        {
            aVertexList[i].y = 3;
        }
    }

    viewPortMesh.vertices = aVertexList;
    viewPortMesh.RecalculateBounds();
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Note that we refer to the axes of rotation by which axis we're rotating around. So ordinarily "y-axis rotation" means rotation around the y axis, meaning yaw left and right. The pitching up & down rotation you describe here would usually be termed an x-axis rotation — you'll notice when you do this rotation in Unity and look and the Euler angle fields in the inspector, it's the x component that's changing. \$\endgroup\$
    – DMGregory
    Commented Mar 20, 2020 at 8:41
  • \$\begingroup\$ Thanks for reminding the terms. Yes, I want to to restrict the impact of camera pitch on on triangle. \$\endgroup\$ Commented Mar 20, 2020 at 11:01

1 Answer 1

1
\$\begingroup\$

Instead of using ScreenToWorldPoint, I would do something like the following:

// Get the camera once. GetComponent is an expensive call, so cache the result whenever
// you can instead of calling it repeatedly.
Camera theCamera = player.GetComponent<Camera>();

// The camera's far plane gives the view distance
float viewDistance = theCamera.farClipPlane;

// The camera's current orientation (defined by its "forward" direction) gives the view
// direction. Project onto the ground plane to ignore the up/down part.
Vector3 viewDirection = Vector3.ProjectOnPlane(theCamera.forward, Vector3.up).normalized;

// Get the view width from the camera's field of view
float verticalFoV = theCamera.fieldOfView;
float horizFoV = Camera.VerticalToHorizontalFieldOfView(verticalFoV, theCamera.aspect);

// Get the left and right sides of the view
Quaternion q = Quaternion.AngleAxis(horizFoV / 2f, Vector3.up);
Vector3 rightDir = q * viewDirection;
Vector3 leftDir = -q * viewDirection;

// And finally, to get all three vertices
// (Not sure why you have four in your question...)
Vector3 start = theCamera.transform.position;
Vector3 rightEnd = start + rightDir * viewDistance;
Vector3 leftEnd = start + leftDir * viewDistance;

If you are not comfortable with Quaternions, then you could replace that part with:

float rightAngle = (theCamera.transform.eulerAngles.y + horizFoV_rad/2f) * Mathf.Deg2Rad;
float leftAngle = (theCamera.transform.eulerAngles.y - horizFoV_rad/2f) * Mathf.Deg2Rad;

Vector3 rightDir = new Vector3(Mathf.Sin(rightAngle), 0, Mathf.Cos(rightAngle));
Vector3 leftDir = new Vector3(Mathf.Sin(leftAngle), 0, Mathf.Cos(leftAngle));
// Note that I might have the Sin & Cos backwards, none of this has been tested

By the way, Sebastian Lague made a great tutorial series on field of view visualization, available on Youtube. It's not quite what you are doing, but it should be similar enough to be helpful.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .