Notifications
Clear all

[Closed] Select Visable to Camera

As the title says, I’m trying to figure out how to, in a scene full of nodes that surround the camera, to select only those that the camera can see at any paticular frame.

If anyone can offer a simple way of doing this, or point me in the right direction of reference to look at it would be much appreciated.

Ultimately I want to make a level of detail script that replaces a “placement” helper with an instance of one of several meshes based on the helpers distance from the camera. However I want all the helpers that are outside the cameras view to just remain helpers and not render at all. The goal being that in a scene with 3000+ objects my animated camera only looks at about 1/3 of them at any paticular frame. I want to be able to elimintate the need for there to be meshes in the file anywhere the camera isn’t looking, and the meshes that the camera is looking at to be created by referencing a high, mid, and low detail version of the mesh based on how far away it is from the camera.

Thanks folks.

-mad

5 Replies
1 Reply
(@j-man)
Joined: 11 months ago

Posts: 0

This is what the level of detail (LOD) utility is for.

This is what the renderer does after ‘transforming vertices’. I don’t mean to rain on your parade but this functionality is already build in the core of your rendering engine. So I fail to see how a script is going to do a better or faster job than your rendering engine.
One thing I have done in the past is to delete any objects that are not seen by the camera at all during the movement of the camera, but with todays rendering technology, the speed of raytracing engines and the depth of reflections nowdays I don’t bother anymore. It use to speed up the MAX raytracer significantly but I don’t think it is neccessary.

Josh.

Interesting idea…

You could use the Substitute modifier on the objects (set to display in render only).

Then, you could add a pre-render callback that would use:

[font=Courier New][/font]
camera.fov
camera.targetDistance

Using this, you would have a cone in 3D space…and then you’d have to iterate through the list of potential objects and check to see if they were within the cone or not.

There are 3 complications

  1. The object can be outside of the cone and still penetrate into the cone, so you’d have to check the bounding box as well

  2. In the scene, you are looking at a dummy that doesn’t have the same bounding box

  3. The substitute modifier only allows you to have a single object associated with each dummy

However, all three of these problems can be easily overcome if you use the RenderProxy script in my signature, it’s a lot like Substitute except that it caches the object to a file. In addition, it automatically makes the dummies (I call them proxies) have bounding boxes that that are the same as the original object…and although it only stores 1 object currently, since it is scripted, it could easily be extended to choose from a list of objects depending on the distance from the camera

Of course, you must expect to lose some realism when it comes to shadows and raytracing since the non-visible objects are gone

 
dist = $Camera01.targetDistance
 
fov = $Camera01.fov
 
for o in selection do
 
(
 
for each corner of bounding box of o
 
(
 
if point is within cone
 
make object renderable
 
)
 
)
 

you could run a rayIntersect function shooting rays form different pixel in the screen.
avery time they hit an object you could record it. you might also want to do this based on a percentage of you render ress. that way you can shoot a ray every other pixel and it will run abit faster.
you will most likely have to take a snap shot of all the geomtry in your scence sence the rayintersect funcs only work in editbel meshes.

i wrotte a similar function once to select all faces facing the screen.

Thanks for the replys guys. I should mention that in the immediate the script would be for max 5.1 but soon my company may be upgrading. We do all of our rendering scanline.

j_man,

The LOD utility that’s built into max would work for this except that it fails and produces errors when you instance or copy it around. So in a scene with thousands of objects that require a LOD you’d have to set them up one by one, and that’s just not effective for me. Unless there is some method of doing it that I’m failing to see.

It’s the ‘transforming vertices’ time that I’d be trying to cut down. Currenting there’s a lot of time wasted in our production when animators are making small changes in say lighting then rendering to see the effect of their changes. Frames do render a lot faster after the initial frame, after it’s transformed the verts, but it’s that first frame I want to cut down so our animators are not sitting there twiddling their thumbs for 5 to 8 minutes everytime they click render.

1 Reply
(@j-man)
Joined: 11 months ago

Posts: 0

No time like the present! < : I’d also recommend using a 3rd party renderer like VRay or Brazil (you can download a free trial to see if you like it but the results speak for themselves).

So you want to write your own. You could do this using callbacks either on viewport redraw or at render time, and then use the susbstitute modifier (as Stuh suggested) to replace your objects based on their distance from the camera. You may also be able to use the reaction manager but I’m unsure.

We all twiddle our thumbs. otherwise I wouldn’t have time torespond to posts like this!

Now I still stand by my first words but I can advise you as to how it can be done. You need to use the viewport drawing methods to anaylse your meshes and transform them onto your display device. reading this section in the MXSHelp will tell you everything you need to know.
This script will give you a start. It draws an asterix at the pivot of the selected object. Expand on this to calculate whether the bounding box of each object is in the field of view and you ‘re on your way.


obj=selection[1]	 -- the first object in the selection
gw.settransform(matrix3 1) -- set viewport transform
p=gw.wtranspoint obj.pos -- get the object position as a screenpoint
gw.wmarker p #asterisk	-- draw an asterisk at that point
gw.enlargeupdaterect #whole -- set the viewport redraw
gw.updatescreen()	 -- update viewport

Cheers,

Josh.