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$
2
  • 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$ Commented Mar 31, 2015 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
    Commented Mar 31, 2015 at 20:46

2 Answers 2

2
$\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$
1
  • $\begingroup$ this is great ! $\endgroup$
    – Chebhou
    Commented Apr 1, 2015 at 19:44
1
$\begingroup$

Small correction for the previous answer:

line "loc2 = self.matrix * loc" should be "loc2 = self.matrix @ loc" for the newer versions of Blender

$\endgroup$
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .