Finding a point on the edge of the screen

Given a vector which points from the centre of the screen to an object offscreen, I want to find the point on the line which is at the edge of the screen. More specifically, I want to find the height up the edge of the screen where this point sits.

I’ve tried projecting the object’s position onto the same plane as the camera (e.g. the normal of the plane is camera.transform.forward) and then calculate the line between the middle of the camera and that projected point. Then getting the gradient of that line and calculating the point that way.

However, I feel I might be getting the conversion between world and screen space confused and I’m not particularly sure how to resolve it.

Vector2 centre = new Vector2(Screen.width / 2, Screen.height / 2);
Vector2 reader = cam.WorldToScreenPoint(Vector3.ProjectOnPlane(transform.position, cam.transform.forward));

float m = (centre.y - reader.y) / (centre.x - reader.x);

// y = mx
float height = Screen.width / 2 * m;

Basically I’m trying to replicate how the doors are used in SCP: Containment Breach

You need frustum planes of the camera to come up with the edges properly.
In fact, even better than frustum planes, you can compute corners with CalculateFrustumCorners.
Make sure to supply the adequate z depth and observe that the results are in view space.
Once you get the points, you can easily build a ray for each corner.

Depending on your game view, your camera might be oriented in 3D space, in that case make sure to convert the view space coordinates to world space, then intersect the ray with some plane (of your content, i.e. ground or floor), and there is your clipped region, guaranteed to follow the edges of your viewport. This is the typical scenario for drawing the view sights on a minimap for example.

If you just want to make a HUD for some icons to move on the edges of the screen, then do the opposite: convert the world space object to view space, now its z component is the view space depth. Call CalculateFrustumCorners with that z to obtain the corners valid for that depth. You can easily correct the final computation for a desired z via linear interpolation (because its on the edge of some plane normal to frustum, it scales linearly).

There is some planning and fiddling about to make this right, but now you have all the necessary pieces, you just need to come up with an optimal computation. Friendly advice: Try to make this without allocating anything, i.e. you can initialize your output array just once – you don’t want your GUI to constantly produce unnecessary garbage, and allocations are slow.

Oh btw, you can ignore CalculateFrustumCorners completely, if this is just about the HUD icons.

You want WorldToViewportPoint then ViewportToScreenPoint.
Remember, viewport is (0, 0, 1, 1) so you can very easily snap the point to edge by projecting from (0.5, 0.5) to whatever you get as a result. However, I can tell you without experimenting how aspect ratio affects viewport, so I can’t really write any code from the top of my head.