1
$\begingroup$

What are the formulas to calculate the 4 half-planes that define the camera's view volume?

The inputs should be the camera's world matrix, focal length (and maybe sensor size?) and anything else I overlooked. I am not interested in the clipping start/end, but extra credit if you include them.

I plan to use this to calculate if an object would be visible to the camera, (which is slightly harder since the origin could be off-camera, but polygons could still be on-camera, but I can fudge that).

$\endgroup$
  • 1
    $\begingroup$ You should cull the objects with bounding-spheres to avoid the origin problem, its fast. Search for frustum culling, this question is more for Game development stack exchange than blender.. $\endgroup$ – Jaroslav Jerryno Novotny Mar 31 '15 at 17:04
  • $\begingroup$ It is not for game. I want to add more objects (part of a lattice) to the scene, but not in places where they will never be rendered. I could easily add 100,000 objects and only have 10,000 actually show up on camera, so I'd rather just add only the ones that will appear on camera. $\endgroup$ – Mutant Bob Mar 31 '15 at 20:46
1
$\begingroup$

After a couple of quick experiments I determined that for a square camera the following coordinates (expressed in the camera's local coordinate system) would appear in the corners of the image:

x = y = sensor_width/lens /2
[±x, ±y, -1]

For a rectangular image, whichever dimension is larger becomes sensor_width/lens/2, and the smaller dimension is proportionally adjusted.

To define the half-planes in the camera's coordinate system, it's enough to calculate the cross products of the vectors pointing at the vertices of each edge, so

lr = [ x,-y,-1]
ur = [ x, y,-1]
ll = [-x,-y,-1]
ul = [-x, y,-1]
n1 = | lr × ll |
n2 = | ll × ul |
n3 = | ul × ur |
n4 = | ur × lr |

We normalize the vectors to length 1 so that we can use them in distance calculations later on.

When you want to determine if a particular coordinate c is in the camera's view cone convert it to camera local coordinates using

M = cam.matrix_world.inverted()
c2 = M c

Now that we have c2 (in the camera's coordinate system) we can compute the dot product between it and the various half-plane normals.

zi = ni ∙ c2

If all those zis are >=0 then the point is in the camera's view cone. If the original coordinate is for an object, it's useful to incorporate a fudge factor like the radius of the object's bounding sphere (centered on the coordinate) and make sure that zi >= -fudge .

And this is the python class based on all that math:

class CameraCone:

    def __init__(self, matrix, sensor_width, lens, resolution_x, resolution_y):
        self.matrix = matrix.inverted()
        self.sensor_width = sensor_width
        self.lens = lens

        w = 0.5* sensor_width / lens
        if resolution_x> resolution_y:
            x = w
            y = w*resolution_y/resolution_x
        else:
            x = w*resolution_x/resolution_y
            y = w

        lr = Vector([x,-y,-1])
        ur = Vector([x,y,-1])
        ll = Vector([-x,-y,-1])
        ul = Vector([-x,y,-1])
        self.half_plane_normals = [
            lr.cross(ll).normalized(),
            ll.cross(ul).normalized(),
            ul.cross(ur).normalized(),
            ur.cross(lr).normalized()
        ]

    def from_camera(cam, scn):
        return CameraCone(cam.matrix_world, cam.data.sensor_width, cam.data.lens, scn.render.resolution_x, scn.render.resolution_y)

    def isVisible(self, loc, fudge=0):

        loc2 = self.matrix * loc

        for norm in self.half_plane_normals:
            z2 = loc2.dot(norm)
            if z2 < -fudge:
                return False

        return True
$\endgroup$
  • $\begingroup$ this is great ! $\endgroup$ – Chebhou Apr 1 '15 at 19:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.