There’s a few questions here relating to the same end-goal effect. Trying to figure out what my options are, what level of flexibility those options have, and what limitations each will come with.
-
How expensive is CalculateFrustumPlanes? i.e. is there a more efficient method to calculating whether or not an object is visible from a camera than CalculateFrustumPlanes and TestPlanesAABB? If I can get a close-enough approximation that’s faster, that’d be ideal. There will be a bunch of these checks being called regularly (both #2 and #3).
-
Is there a way to generate a set of frutstum planes from a given point, direction, and field of view angle as if there was a camera there without needing a camera (I don’t need to render the view). Reusing code that triggers off a camera for non-camera entities as well would be awesome.
-
Is there a way to calculate the camera view for a non square field of view (assume the camera will be rendering to a texture that would be used elsewhere in the scene, vs. the main camera). If not, I can use a square view, but getting non-square results would allow some flexibility. There will be fewer of these at any given time, but likely still several (security camera, with companion displays).
Figured out #2 on my own. This answer got me the points needed to construct 6 planes, combined with tracing out the results of CalculateFrustumPlanes() I was able to construct this function:
/**
* Returns a set of Planes equivalent to the frustum returned by GeometryUtility.CalculateFrustumPlanes(Camera).
* @param origin - the point the virtual camera exists at
* @param direction - the normalized look-vector to calculate on; must be
* non-parallel to Vector3.up
* @param fovRadians - field of view in radians; 1.047 is ~60 degrees
* @param viewRatio - width/height ratio
* @param distance - the far-clip plane
**/
public static Plane[] CalculateFrustum(Vector3 origin, Vector3 direction,
float fovRadians, float viewRatio, float distance) {
Vector3 nearCenter = origin + direction * 0.3f;
Vector3 farCenter = origin + direction * distance;
Vector3 camRight = Vector3.Cross(direction,Vector3.up) * -1;
Vector3 camUp = Vector3.Cross(direction,camRight);
float nearHeight = 2 * Mathf.Tan(fovRadians / 2) * 0.3f;
float farHeight = 2 * Mathf.Tan(fovRadians / 2) * distance;
float nearWidth = nearHeight * viewRatio;
float farWidth = farHeight * viewRatio;
Vector3 farTopLeft = farCenter + camUp*(farHeight*0.5f) - camRight*(farWidth*0.5f);
//not needed; 6 points are sufficient to calculate the frustum
//Vector3 farTopRight = farCenter + camUp*(farHeight*0.5f) + camRight*(farWidth*0.5f);
Vector3 farBottomLeft = farCenter - camUp*(farHeight*0.5f) - camRight*(farWidth*0.5f);
Vector3 farBottomRight = farCenter - camUp*(farHeight*0.5f) + camRight*(farWidth*0.5f);
Vector3 nearTopLeft = nearCenter + camUp*(nearHeight*0.5f) - camRight*(nearWidth*0.5f);
Vector3 nearTopRight = nearCenter + camUp*(nearHeight*0.5f) + camRight*(nearWidth*0.5f);
//not needed; 6 points are sufficient to calculate the frustum
//Vector3 nearBottomLeft = nearCenter - camUp*(nearHeight*0.5f) - camRight*(nearWidth*0.5f);
Vector3 nearBottomRight = nearCenter - camUp*(nearHeight*0.5f) + camRight*(nearWidth*0.5f);
Plane[] planes = {
new Plane(nearTopLeft,farTopLeft,farBottomLeft),
new Plane(nearTopRight,nearBottomRight,farBottomRight),
new Plane(farBottomLeft,farBottomRight,nearBottomRight),
new Plane(farTopLeft,nearTopLeft,nearTopRight),
new Plane(nearBottomRight,nearTopRight,nearTopLeft),
new Plane(farBottomRight,farBottomLeft,farTopLeft)};
return planes;
}
The answer to #1 at this point becomes apparent, as there’s not a whole lot in that function that is terribly expensive, with #3 being included in with the viewRatio parameter.