
That’s scene view from above. I have a character (with nav agent) spawning at the red spot in front of the camera. I have this point and rotation angle. Black lines are camera view bounds. I can get those planes with
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
How can i get two intersections - two green points ?
I want to use them as waypoints to make a character go fron side to side in front of the camera
Use Plane.raycast to get the intersection of a line and a Plane.
Well divide your work up. What is a line intersecting with 2 planes? It’s 2 separate line with 1 plane intersections. Just do them in sequence 1 after the other (don’t worry, line/plane intersection is fast).
Then for the intersection Unity has it built into the Plane class using Plane.Raycast:
There are other ways that could work too, such as solving the math yourself, which would resolve infinite lines. But here it is built in by Unity.
[edit]
lol, got a call from my realtor while typing this which held me up and @PraetorBlue came in with the same suggestion. So yeah, just use Raycast.
adding for reference, there’s LinePlaneIntersection() and others:
https://wiki.unity3d.com/index.php/3d_Math_functions
Can’t get it to work ![]()
navAgent = GetComponent<NavMeshAgent>();
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
var pLeft = planes[0];
var pRight = planes[1];
Ray ray = default;
ray.direction = transform.forward;
ray.origin = transform.position;
float enter = 0.0f;
pLeft.Raycast(ray, out enter);
Vector3 WayPoint = ray.GetPoint(enter);
print(WayPoint);
navAgent.SetDestination(WayPoint);
(0, 0, 0) is not a valid direction vector:
ray.direction = transform.TransformDirection(0,0,0);
tried ray.direction = transform.forward; still no luck ![]()
I mean… it works in that you’re casting a ray in that direction.
The problem is if that’s the direction you’re actually wanting to raycast in.
Knowing that is up to you… we don’t know what exactly this specific ‘transform’ represents. But yeah, you’re going to need to know the data in regards to the ‘line’ you expect to be testing for. This includes the position and direction.
Note that you’ll have to then perform the raycast against BOTH planes. And that the relative position of your ‘position’ to the plane is going to effect the direction of the ray as well. For example with your image if your position is the red dot with the arrow… the plane on the right is “behind” the red dot (assuming the arrow points in the direction the red dot faces). To deal with this you either should raycast from a starting point outside of both planes OR cast both + and - versions of the direction vector against both planes.
But lets say that ‘transform’ in this case is the red dot in your image. And the arrow of the red dot is ‘transform.forward’. If this is so I’d go with moving the origin outside of the frustum and staying with the direction.
//lets move the origin 1000 units down the line which should cover most positions inside the view frustum unless you're really really far from the camera
//note there is other ways to do this... like I said the +/- approach, or actually calculating the real position relative to the planes, or the infinite line math that was linked earlier...
//there's always more than 1 way to skin a cat. Just trying to write something that is easy to read and makes sense to a novice
const float OFFSET = 1000f;
var ray = new Ray(transform.position - transform.forward * OFFSET, transform.position);
float lenter, renter;
pLeft.Raycast(ray, out lenter);
pRight.Raycast(ray, out renter);
Vector3 posleft = ray.origin + ray.direction * lenter;
Vector3 posright = ray.origin + ray.direction * renter;
posleft and posright are the 2 green dots in your image
still it doesn’t work ![]()
I wonder what is the way to visualize planes on gizmos to check what goes wrong ?
I mean… if you can’t visualize a point/direction enough to write code to deal with that… I’m willing to bet you’ll accidentally introduce errors into your gizmo code screwing up the on screen visualization just adding more misinformation to your problem.
…
How about this.
What are you trying to do?
Not like “I’m trying to calculate where a line intersects with a plane”… but why? What is your end goal?
“I plan to position UI elements at the edges of the screen” or “I want a turret to point in the direction of some target that exists off screen along this line” or whatever.
Instead of just saying “it doesn’t work” which isn’t going to get you anywhere unless you just expect us to write the code for you in which case… that’s not how most of us work around here. We like to give you the tools to help point you in the direction you need to go. You know… “teach a man to fish” rather than “give a man a fish”.
This works. But i’d like to sort those points - depending on the position (inside or outside the cone) -
first i need the point in front of the character, then point in the back (to make him move forward then back)
or the point further away then closest one (to make him move forward then back)
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
var pLeft = planes[0];
var pRight = planes[1];
const float OFFSET = 1000f;
var ray = new Ray(transform.position, transform.position+ transform.forward * OFFSET);
Debug.DrawLine(transform.position, transform.forward * OFFSET, Color.white, 10f);
float lenter, renter;
pLeft.Raycast(ray, out lenter);
pRight.Raycast(ray, out renter);
Vector3 posleft = ray.origin + ray.direction * lenter;
Vector3 posright = ray.origin + ray.direction * renter;
if (false)
{
GameObject mySphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere.transform.position = posleft;
GameObject mySphere2 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere2.transform.position = posright;
}
navAgent.SetDestination(posright);
What i’m trying to do is spawning people at predefined points (see arrows). Then make them go in front of the camera back and forth. I need two waypoints on camera view edges for this.


I sorted it out. Code now looks like this. But tests showed i need not intersections but a point futher down the ray. i.e not green but red points. I understand i need to play with lenter. but ±depends on relative the position…
List<Vector3> waypoints = new List<Vector3>();
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
var pLeft = planes[0];
var pRight = planes[1];
const float OFFSET = 1000f;
var ray = new Ray(transform.position, transform.position+ transform.forward * OFFSET);
Debug.DrawLine(transform.position, transform.forward * OFFSET, Color.white, 10f);
float lenter, renter;
pLeft.Raycast(ray, out lenter);
pRight.Raycast(ray, out renter);
waypoints.Add(ray.origin + ray.direction * lenter);
waypoints.Add(ray.origin + ray.direction * renter);
if (false)
{
GameObject mySphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere.transform.position = waypoints[0];
GameObject mySphere1 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere1.transform.position = waypoints[1];
}
var rotation = transform.rotation.y;
waypointNext = 1;
if (Mathf.Sin(rotation)<0)
{
waypointNext = 0;
}
navAgent.SetDestination(waypoints[waypointNext]);
// when destination is reached change waypointNext

Well, that’s trivial and a common problem. The difference is a to have a ray vs sphere cast. The easiest solution is to simply offset your planes by your sphere radius outward. That way the intersection point will be that further out so the sphere would essentially touch the outer edge of your plane. Since a plane is given in normal form (normal vector + distance from the origin), all you have to do is modify the distance accordingly. Since the distance is signed and you want to grow your frustum outwards, you just need to add the radius to the plane’s distance value before you do the raycasting.
So it’s literally just:
yourPlane.distance += radius;
If you do that for all planes, you essentially have grown the frustum in each direction by that radius. Note that the plane’s distance is given along the plane’s normal vector. Note there are generally two ways how to store the distance value for a plane in normal form. According to the docs a positive distance indicate a plane that is facing the origin while a negative value represents a plane that is facing away from the origin. That means for a camera that sits at the origin all planes should have a positive distance except the near plane. Of course if the camera has been moved around, the distances could be all over the place. However adding a value to the distance should always make the frustum larger while subtracting a value would make it smaller.
Keep in mind that the Plane struct is not black magic. It’s one of the simplest type imaginable.
Here’s a modified image that illustrates what I mean:

Btw: If you need to calculate those intersections quite often and your camera can actually move around and you want to avoid allocating memory each time for the Plane[ ] array, you can simply use my UpdatePlanes method I posted in a deeply nested comment over here. Unfortunately direct linking that comment does not work since it’s hidden by default.
Just for the sake of code preservation, here’s the snippet:
private static Plane FromVec4(Vector4 aVec)
{
Vector3 n = aVec;
float l = n.magnitude;
return new Plane(n / l, aVec.w/l);
}
public static void UpdatePlanes(Plane[] planes, Matrix4x4 m)
{
if (planes == null || planes.Length < 6)
return;
var r0 = m.GetRow(0);
var r1 = m.GetRow(1);
var r2 = m.GetRow(2);
var r3 = m.GetRow(3);
planes[0] = FromVec4(r3 + r0); // Left
planes[1] = FromVec4(r3 - r0); // Right
planes[2] = FromVec4(r3 + r1); // Bottom
planes[3] = FromVec4(r3 - r1); // Top
planes[4] = FromVec4(r3 + r2); // Near
planes[5] = FromVec4(r3 - r2); // Far
}
public static void UpdatePlanes(Plane[] planes, Camera cam)
{
UpdatePlanes(planes, cam.projectionMatrix * cam.worldToCameraMatrix);
}
UpdatePlanes does not allocate any memory. It just updates an existing array. If you only need the left and right plane, of course you could directly extract only those planes manually. However the computational overhead is miniscule.
That’s the code i come with. It works
But i don’t really like it ![]()
List<Vector3> waypoints = new List<Vector3>();
void Start()
{
navAgent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
var planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);
var pLeft = planes[0];
var pRight = planes[1];
const float OFFSET = 1000f;
var ray = new Ray(transform.position, transform.position+ transform.forward * OFFSET);
Debug.DrawLine(transform.position, transform.forward * OFFSET, Color.white, 10f);
var rotation = transform.rotation.y;
waypointNext = 1;
float offsetDir = 1.5f;
if (Mathf.Sin(rotation)<0)
{
waypointNext = 0;
offsetDir = - offsetDir;
}
float lenter, renter;
pLeft.Raycast(ray, out lenter);
pRight.Raycast(ray, out renter);
waypoints.Add(ray.origin + ray.direction * (lenter- offsetDir));
waypoints.Add(ray.origin + ray.direction * (renter+ offsetDir));
bool debugShow = false;
if (debugShow)
{
GameObject mySphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere.transform.position = waypoints[0];
GameObject mySphere1 = GameObject.CreatePrimitive(PrimitiveType.Sphere);
mySphere1.transform.position = waypoints[1];
}
navAgent.SetDestination(waypoints[waypointNext]);