- Home /
Calculate camera frustum intersection with plane
We have play area composed of hex gameobjects. We only display/load what is visible. Impossible to load large maps at one time. We want to calculate the polygon intersection with the game board plane. We cannot load every possible game object and test if in the frustum or ray cast to the screen.
We need custom code to see which gameobject positions are in the visibility polygon? How do you get the corner rays of the camera frustum?
Answer by troien · Sep 10, 2015 at 08:20 AM
As for the :
How do you get the corner rays of the camera frustum?
To get the ray of each corner you can simply use camera.ViewportPointToRay.
Ray bottomLeft = camera.ViewportPointToRay(new Vector3(0, 0, 0));
Ray topLeft = camera.ViewportPointToRay(new Vector3(0, 1, 0));
Ray topRight = camera.ViewportPointToRay(new Vector3(1, 1, 0));
Ray bottomRight = camera.ViewportPointToRay(new Vector3(1, 0, 0));
If your plane is on a fixed height you perhaps don't even have to raycast. As a method like this should return the rays intersection on a given y position. (I used this method because I needed a similar thing, but I didn't have a collider to raycast against as I used Graphics.DrawMesh).
public static Vector3 GetPointAtHeight(Ray ray, float height)
{
return ray.origin + (((ray.origin.y - height) / -ray.direction.y) * ray.direction);
}
Note that this method can thow a division by zero if ray.direction.y is 0.
The GetPointAtHeight function works great. I was wondering if you could elaborate on the maths involved. Clearly you're multiplying the direction vector by a scalar, I'm just confused how dividing the origin.y by the -direction.y results in a scalar that reaches the intersection point.
Well, that's just simple linear math, nothing special. First of all you should read the forumla carefully. We do not divide origin.y by direction.y but the difference between the origin.y and the desired height. So that's the distance from our "plane" (since the plane is parallel to the x-z plane at a certain y height). Since ray.direction is a normalized vector (a vector with length 1.0), it means the y component is the sine of the pitch angle of the ray. So dividing the vertical height by the sine gives you the length of the hypotenuse or the length along the ray which is exactly what we need. You can also view it like this:
When you multiply the direction by a scaler you move along that direction vector towards our plane. Of course our hit point needs to have the same y value as the plane we want to hit. So we want to know which scaler we need in order to make our ray point to have the desired y component. He has the values flipped around and therefore needs to flip the sign again. It makes more sense to do it like this:
float dist = (height - ray.origin.y) / ray.direction.y;
return ray.origin + dist * ray.direction;
Again "height" is the worldspace y position of the plane we want to hit. By subtracting the ray origin's y component we get the vertical difference. So how far are we above the plane. So the first line calculates how many direction vectors do we need until we get from the ray origin down to the height of the plane. Since the y component of the direction is the amount we move in the y direction, we just need to divide the relative vertical distance by the y component of the direction. This tells us how many direction vectors we need to reach down to the plane. By multiplying the whole direction vector by that distance and adding the start of the ray, we get the actual hit point on the plane.
Answer by musaranya · Sep 10, 2015 at 08:07 AM
I think Unity performs its frustum culling by default so you should not worry about it. Also keep in mind that if the objects are very large culling is less efective because when a vertex gets into the frustum the entire object is rendered. If you still want to get dirt with frustum culling, this couple of functions may interest you:
GeometryUtility.CalculateFrustumPlanes
GeometryUtility.TestPlanesAABB
regards