- Home /
How to get where my camera borders a plane
Hello, I have a game where I need to know the x values of where my camera is bordering a plane which is my background. To achieve this I used the following code: cam.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, System.Math.Abs(transform.transform.position.z)));
This worked perfectly until I implemented the feature of random camera rotation. Now I am trying to get the x values based on the current angel. I have 2 ideas of how to achieve this. The first one is by using rays. I am new to ray casting and don't know how to send a ray from my cameras vertices or my cameras frustum's vertices (a frustum is a shape that the field of view casts https://docs.unity3d.com/Manual/UnderstandingFrustum.html). the second method I thought about is to use a simple tan=a/b (function) a being the border on the right and b being transform.postion.z, but to do this I need to know the x and y angel of my field of view or my "Frustum" if you will. I have tried many methods to get this angel. In the unity manual, it says that you have to use the screens Aspect ratio. Which makes a lot of sense but I tried it and couldn't seem to figure out how I must multiply it (I have tried multiplying the angel itself and also the result from the Tan function. Neither has worked)
Long story short, I would like to know how to get the rays that my field of view casts, or the angel that my field of view has.
I hope someone can help me, Thanks in advance.
Answer by banana111 · Nov 07, 2018 at 05:42 PM
Hello, I have figured it out. I kind of reverse engineered it in a way. So I'm still looking for a better answer, but if any one else has this problem here is my solution. FIrs of I found this code in the manual
Vector3[] frustumCorners = new Vector3[4];
camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
it creates a vector variable at the end of your cameras field of view corners. then I created a new vector 3 from my camera's position to one of the corners (I chose 2 since all of it's values are positive you can choose which ever one you like (that's not higher then 4 lol)). with this code: Vector3 big_vector=frustumCorners[2]-transform.position;
then I used an Atan function to get the angel by dividing the big vectors (the vector from the camera/this object to one of the corners of the camera ) x value with its z value (). with this code:
angel = (float)(System.Math.Atan(big_vector.x / big_vector.z));
then I calculated the x right and left borders on my plane (my plane is a z value of 0) and the y up and down values of the plane (I calculated separately for right and left and up and down since my camera is rotated) I did this by multiplying the tan function with the transform.position.z since this is where my camera is located and since my plane is on a z of 0 the length form my camera to the plane is the same as my cameras z position. here is the how I did it(screen_x borders is a float array of 2 items declared over the start function the same goes for the y ones):
//these are the x values
screen_x_borders[0] = (float)System.Math.Tan(angel+transform.rotation.y) * System.Math.Abs(transform.position.z)+transform.position.x;
screen_x_borders[1] = (float)System.Math.Tan(-angel+transform.rotation.y) * System.Math.Abs(transform.position.z) + transform.position.x;
//these are the y values:
angel = (float)(System.Math.Atan(big_vector.y / big_vector.z));
screen_y_borders[0] = (float)System.Math.Tan(angel) * System.Math.Abs(transform.position.z + transform.rotation.x) + transform.position.y;
screen_y_borders[1] = (float)System.Math.Tan(-angel) * System.Math.Abs(transform.position.z + transform.rotation.x) + transform.position.y;
when calculating the y values I calculated a new angel as you can see. this is basically it but for easier usage in other scripts I stored the borders length/distance from each other into a Vector 2 and then also calculated a Vector2 offset so when I use the code in other scripts I can just say for example if( border.x + offset < this position){ do something }
the border lengths (screen_border is a public variable ):
screen_borders.x = screen_x_borders[0] - screen_x_borders[1];
screen_borders.y = screen_y_borders[0] - screen_y_borders[1];
the offset(is also a public Vector 2 ):
border_offset = new Vector2(screen_x_borders[0]-screen_borders.x/2 ,screen_y_borders[0] - screen_borders.y / 2 - transform.position.y );
I subtracted the y position of my camera from the offset since my camera is moving in the y position all the time and I will subtract it when I need to call it in other scripts rather then doing it here every frame for eg. : if( screen_borders.y+border_offset < this position){ do something } the whole code :
public GameObject object_;
public Vector3[] frustumCorners;
public Vector3 big_vector;
public float angel;
public float[] screen_x_borders = new float[2];
public float[] screen_y_borders = new float[2];
public Vector2 screen_borders;
public Vector2 border_offset;
void Start() {
var camera = GetComponent<Camera>();
Vector3[] frustumCorners = new Vector3[4];
camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
Vector3 big_vector=frustumCorners[2]-transform.position;
angel = (float)(System.Math.Atan(big_vector.x / big_vector.z));
Debug.Log("angel1: " + (-angel * 180 / System.Math.PI));
Debug.Log("angel2: " + transform.rotation.eulerAngles.y );
Debug.Log("angel3: " + (angel + transform.rotation.y) * 180 / System.Math.PI);
Vector2 cur_object_angels = new Vector2(0,0);
cur_object_angels.y = (transform.rotation.eulerAngles.y > 180) ? transform.rotation.eulerAngles.y - 360 : transform.rotation.eulerAngles.y;
cur_object_angels.x = (transform.rotation.eulerAngles.x > 180) ? transform.rotation.eulerAngles.x - 360 : cur_object_angels.x;
cur_object_angels *= (float)System.Math.PI / 180;
screen_x_borders[0] = (float)System.Math.Tan(angel + cur_object_angels.y) * System.Math.Abs(transform.position.z)+transform.position.x;
screen_x_borders[1] = (float)System.Math.Tan(-angel + cur_object_angels.y) * System.Math.Abs(transform.position.z) + transform.position.x;
screen_borders.x = screen_x_borders[0] - screen_x_borders[1];
angel = (float)(System.Math.Atan(big_vector.y / big_vector.z));
screen_y_borders[0] = (float)System.Math.Tan(angel + cur_object_angels.x) * System.Math.Abs(transform.position.z + transform.rotation.x) + transform.position.y;
screen_y_borders[1] = (float)System.Math.Tan(-angel + cur_object_angels.x) * System.Math.Abs(transform.position.z + transform.rotation.x) + transform.position.y;
screen_borders.y = screen_y_borders[0] - screen_y_borders[1];
border_offset = new Vector2(screen_x_borders[0]-screen_borders.x/2 ,screen_y_borders[0] - screen_borders.y / 2 - transform.position.y );
screen_borders /= 2;
object_.transform.position = new Vector3(screen_borders.x+border_offset.x, screen_borders.y+border_offset.y+transform.position.y, 0);
}
At the end, I have an object_ Gameobject variable which I have to test if the code worked and my corners are like they are supposed to be.
I know this was long but I wanted to explain my train of taught behind it since the code is very specific for my example of a camera moving in the y position. I hope this helps someone I was stumped on this problem for about 4-5 days I think. By posting this I can say that my problem is finally ...over.