- Home /
How to determine if a line intersects with a frustum
I am creating 2D lines using planes and a ortho camera. This renders on top of my 3d camera. The points provided to the 2d lines are WorldToScreenPoint-ed from 3d points so they are in 2D space, as I don't want perspective in my lines. This all works fine.
Trouble is, since they're 2D lines, I need to determine when the lines are in front or behind the camera. I flip the x and y values of the 2d point if the point is behind the camera, using Vector3.Angle from the 3d camera's forward vector to the 3d version of the point. That works fine.
But my issue is that some lines have 1 point in front of the camera, and 1 behind. I may need these lines to draw as they have the potential to be inside the camera's view frustum. But I need to know if a segment of the line intersects with the camera's view frustum or not.
Here's a visual description of my problem:
The red lines shouldn't be drawn, the green lines should be. My problem lies with the lower green line. How do i know if a line is the lower green line or the higher red line?
What's the best way to do this check? I prefer to make this fast, as this is for a mobile game and there may be up to 15 or so lines at a time, and each line is recalculated/moved every frame.
Any input would be greatly appreciated. Thanks!
So here's my only answer I can think of, but it might prove too expensive...
Use GeometryUtility.GenerateCameraPlanes to get Planes from the camera. Call Plane.Raycast for the 4 planes. Detect if the point of intersection is behind or in front of the camera plane. If in front, keep, otherwise, discard.
This means 4 Raycasts PER LINE, PER UPDAT$$anonymous$$.. Which I'd like to avoid if at all possible.
Is there a better way?
That actually doesn't sound too bad - 60 plane raycasts per frame. Have you done any ti$$anonymous$$g tests to verify how long it actually takes? You can use System.Diagnostics.Stopwatch to time it.
Yeah as it turned out, it wasn't horrible... BUT I was wrong in my answer. It doesn't give the effect I need.
The Plane objects are infinite planes, so any intersection with them has no correlation to my camera position. The test which I described doesn't work, since there could be a line that doesn't intersect with the frustum volume, but that does intersect with one of those planes.
Answer by OP_toss · May 08, 2013 at 10:11 PM
SWEET! I believe I figured it out with the help of a friend!
For those who like this stuff, here's how I fixed it:
Instead of determining when to draw the line or not, I instead clip the line by the camera's plane, thus if the line goes behind the camera, that part of the line won't be visible. This is also how Clipping Planes work in general, so I'm dumb for not considering it earlier.
Specifically, I will create a Plane from the camera's normal and position. Then I call Plane.Raycast, casting from the point of the line in front of the camera, to the point of the line behind the camera. If I hit the plane, I change the position of pointB to be the hitpoint, thus clipping the line. MUCH easier!
Thanks for trying guys! Hope this solves someone else's issue sometime!
Answer by Vonni · May 08, 2013 at 06:22 PM
What if you wait with making the points 2D and check if its visible by the camera, as the camera already is checking these things.
// OnWillRenderObject, Renderer.isVisible, Renderer.OnBecameVisible, and OnBecameInvisible
And then make them 2D. Just some food for thought!
I thought of this at one point..
Problem is, if you look at the lower green line, neither of its points are within the Frustum, so neither point would have Renderer.isVisible true, nor do they have renderers for that matter.
I need to check if the line they defined would render, not the points themselves.
The line will have a renderer. Check the line itself to see if it's visible / being rendered.
http://docs.unity3d.com/Documentation/ScriptReference/Renderer-isVisible.html - It's a part of the definition for Renderer, so anything that derives from Renderer (like LineRenderer) will have it too.
There is no 3D line. I'm not using LineRenderer. I'm making a line myself in 2D space. That's why I'm having issues, otherwise 3d depth sorting and frustum culling would do this for me.
All I have in 3D is 2 points, from there everything is done with 3d math, then converted to 2d for display on a separate camera. $$anonymous$$ake sense?
You might be making this whole thing more complicated than it needs to be. What, exactly, are you trying to do? What do you want your end result to be?
Also, when you say '2D space', what do you mean? Do you mean you're doing it in OnGUI (which it doesn't sound like)? Otherwise, there is no 2D space in Unity.
Sorry, I briefly explained it above but I'll clarify here:
End goal is to get textured lines with various thicknesses pointing to things in 3D, rendered on top of my 3d Render, without perspective.
$$anonymous$$y solution so far:
Create an orthographic camera that only renders stuff on a particular layer. This is my 2D camera, and it renders on top of my 3D camera. I create planes that are scaled between points using 2D coordinates. By constraining the Z axis, I get "2D" behavior in Unity. This is common practice to get 2D in a 3D engine. No one should use OnGUI for anything final. It's slow and bad.
Problem is, since my lines are now in "2D", they don't respect camera frustum culling, or z-testing. So I have to do this myself. I believe my particular issue is described enough in detail above.
Does this clear up any questions with the issue? If there's an easier way, I'm all ears, but I believe this is the only way to go for the desired effect.