View Full Version : Objects in camera cone?

 3rd Dimentia06 June 2011, 07:14 AMIs there a way to calculate what objects are within a camera cone? I don't even know where to start to do this. Hopefully someone can point me down a path. Cheers, Cg.
MatanH
06 June 2011, 08:25 AM
As I have struggled with this problem myself, I found a couple of methods to do it:

1.choose a resolution and cast rays from the camera to "virtual pixels" in front of it.
the higher the resolution you choose the less objects you will miss but it will be very slow.

2. check if the bounding box of the object is in the cone.
you will have to check all 8 corners of the bounding box and switch between 3 cases:
A) At list one corner is in the cone.
B) All corners are out of the cone and on the same side.
C) All corners are out of the cone but in both sides of the cone (the camera cone goes through the middle of an object).

Cases A & C will tell you that the object is probably in the cone.
Case B will tell you that it surely isn't.
The problem is that you might include objects that their bounding box is in the cone but the actual geometry is out of it.

3. You could divide the camera cone into boxes with increasing width and height and test for intersection between these boxes and the objects of the scene.
option 2 is more precise and can be implemented much faster but this is pretty easy to implement.

4. You could look through the camera and use a rectangle to select all objects in the view.
I found this method to be the best because it won't miss any object and it's very fast.
visibleObjs = boxPickNode (box2 [0,0] (getViewSize()))

stigatle
06 June 2011, 08:43 AM
TzMtN (http://forums.cgsociety.org/member.php?u=16371)'s solution above (box selection in viewport) is a very good solution,
thanks for posting this! Very neat trick.

Here's my contribution.. (all though TzMtN's solution is much more easy and elegant).
It needs to be changed to use the boundingbox or mesh faces \ vertex pos, to check
if it REALLY is inside the view.

you could make it like this,
check if boundingbox is inside the view, if it is then go deeper and check the vertexes.
if bounding box is not inside, then just skip that object.

fn isPointInFrustrum pointPos = (
thePos = pointPos * viewport.getTM()
screen_origin = mapScreenToView [0,0] (thePos.z) [renderWidth,renderHeight]
end_screen = mapScreenToView [renderWidth,renderHeight] thePos.z [renderWidth,renderHeight]
world_size = screen_origin-end_screen
x_aspect = renderWidth/(abs world_size.x)
y_aspect = renderHeight/(abs world_size.y)
screen_coords = point2 (x_aspect*(thePos.x-screen_origin.x)) (-(y_aspect*(thePos.y-screen_origin.y)))
(((screen_coords.x >= 0) AND (screen_coords.x < renderWidth)) AND ((screen_coords.y >= 0) AND (screen_coords.y < renderHeight)))
)

TheObjects = objects as Array
FoundObjects = #()

for i = 1 to TheObjects.count do
(
if (isPointInFrustrum (TheObjects[i].pos))do
(
appendIfUnique FoundObjects TheObjects[i]
)
)

for o = 1 to FoundObjects.count do
(
clearSelection()
select FoundObjects
)

06 June 2011, 09:41 AM
This could be a nice one for the next script-challenge, with the added difficulty is has to make a list of all object visible trough the camera in a given time span.

select all visible objects from start to end as seen trough \$camera.

When you make a city flytrough you could use this to remove all objects that will never be seen, taking in account those that are in the viewport area but hidden behind other objects.

3rd Dimentia
06 June 2011, 10:02 AM
Just to fill you all in on why I want to do this: a script that would calculate the Zdepth limits for a Vray Zdepth Pass. Thanks so much for the speedy replies.

Cg.

3rd Dimentia
06 June 2011, 05:15 AM
I ended up using TzMtN's viewport selection method. Thanks for that. Here is the code for the Zdepth limit calculator so far. This will work fine (and quickly) for objects who's boundingbox is small compared to the distance from the center of the object to the cam. So far the only method I have in place is testing the distance from the 8 corners of each object's bounding box to the camera. So great for small things but for larger objects like groundplanes I know I'm going to have to use a different method as there could be an object who's polys are closer to camera than it's bounding box corners. How to then test distances to the larger objects? The only way that I can think of is to attach all large objects and use one of the ray-mesh functions to shoot rays from the cam to test lots of possible hit points. This just seems like it could be very expensive.

Can anyone suggest other methods?

For this code to work as is, you need to have a camera called Camera01 and at least one geometry or renderable spline object visible from that camera on at least one of the frames in the animationrange.

(
fn isValidRenderObj camObj = if superclassof camObj == GeometryClass or ((superclassof camObj == shape) and (camObj.render_renderable)) then true else false

fn isValidCamera theCam = if superclassof theCam != camera then false else true

fn collectCamObjs = boxPickNode (box2 [0,0] (getViewSize())) crossing:true

fn getBBoxCorners obj =
(
bb = nodeGetBoundingBox obj obj.transform
xyz = bb[2] - bb[1]
bBoxCorners = #()
for x = -.5 to .5 do for y = -.5 to .5 do for z = -.5 to .5 do append bBoxCorners (([ (xyz[1]*x) , (xyz[2]*y) , (xyz[3]*z) ]-(obj.pos-obj.center)) * obj.transform )
bBoxCorners
)

fn calcLimits theCam =
(
if isValidCamera theCam do
(
viewTemp = viewport.getType()
viewport.setCamera theCam
sliderTemp = sliderTime
local theLimits

for i = animationrange.start to animationrange.end do
(
slidertime = i
(
frameObjs = collectCamObjs()
if frameObjs.count != 0 do
(
if theLimits == undefined do
(
baseDist = distance theCam (frameObjs[1])
theLimits = [baseDist,baseDist]
)
for frameObj in frameObjs where (isValidRenderObj frameObj) do
(
bBoxCorners = getBBoxCorners frameObj

for bBoxCorner in bBoxCorners do
(
point pos:bBoxCorner name:("Point_" + frameObj.name + " " + bBoxCorner as string)
theDist = distance theCam.pos bBoxCorner
if theDist < theLimits[1] then theLimits[1] = theDist
else if theDist > theLimits[2] then theLimits[2] = theDist
)
)
)
)
)
viewport.setType viewTemp
sliderTime = sliderTemp
)

if theLimits == undefined do messagebox "Oh No!!! Total failure!\n\nAny renderable objects visible from\ndefined camera within animation range?\n\nWas there even a valid camera defined?"

theLimits
)

theLimits = calcLimits \$Camera01
format "%\n"theLimits
)

Kickflipkid687
06 June 2011, 05:27 PM
I guess another way to do this, would be to use the IntersectRayEx() I believe? It's that or the normal Ray one. But one of those collects the object that was hit, and it doesn't have to be a EPoly or EMesh I believe. But the hard part/down side of that, is making it fast with good accuracy...

3rd Dimentia
06 June 2011, 11:48 PM
Hey Kickflip, thanks for the reply. I am though, looking for workflows other than the "shooting rays at mesh" method. Which I would think could be quite expensive to calculate. But if I can't think of, or someone else doesn't suggest another method, that's the one I'll go with. I'm just looking to see what my other options might be before I spend the time implementing a ray-mesh method as it looks like it might take me a while to do.

Cheers,

Cg

06 June 2011, 06:30 AM
Here's a little start. It's a g-buffer like approach. Each object should have a different color with the red channel at 100% (.red=255). This is done to filter out the other colors that exists in the viewport for gizmos and background etc.

Before you run it, set the viewport to 'consistent colors', turn off any shadows and disable progressive refinement. Each object should now be visible as a single solid color.

When you run the code it returns an array with unique colors found in the viewport that have a .red=255. You can make the viewport a bit smaller to speed it up. The next step would be match these colors to objects in the scene.

This method returns the objects that are actually visible to the camera. So if its behind another object, but in the camera cone, it can be flagged as invisible.

The viewport settings and color assignments can be automated but I do have a real job to do :)

b=gw.getViewportDib();

tmp=#()
for y=0 to b.height do
(
join tmp (makeUniqueArray (getPixels b [0,y] b.width))
)

out=#()

tmp=makeUniqueArray tmp

for i=1 to tmp.count do
(
if ( (tmp[i]).red == 255) do append out tmp[i]

)

print out

Klunk
06 June 2011, 04:42 PM
interesting opengl tutorial on this here (http://www.lighthouse3d.com/tutorials/view-frustum-culling/)

CGTalk Moderation
06 June 2011, 04:42 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.

1