How to check if a node is actually visible on the screen?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

How to check if a node is actually visible on the screen?

Post by Robert Y. »

Hi Guys,

after searching this forum I still get stuck with this:
I want to test if a small object is visible in the window, as I want to put some 2D marker over it when it is. Say for instance several satellites orbiting a planet. The marker shouldn't be drawn when a satellite is behind the planet.

My first idea was to render all meshes, then calculate the 2D coordinates of the satellite and do a collision check on these coordinates with GetRayFromScreenCoordinates and GetCollisionPoint. This works, but the collision checking is far too slow, as I use very high resolution models (500k triangles) and have to check for every satellite. So my framerate drops drastically.

Fortunately, I thought of a faster solution: If I draw my satellite in a specific colour, I could check its visibility by simply checking the pixel colour at its 2D coordinates. So, I first render all meshes, then want to check some pixel values and then draw some 2D stuff on them.

There are a few problems with this, however:

1. When I render all meshes, I could use an endScene(), so everything is drawn to a window. And then I can use GetPixel on the device context to get the pixelvalues to see what markers have to be drawn and do another beginscene-endscene (without erasing the background) to add the 2d stuff to the screen. But this will lead to flickering of the 2D markers, as also an image without them is presented.

2. When I just use one begin-endscene, the pixelvalues of the previous render are taken. But if a marker has been drawn over my satellite, the pixelvalue has changed, so in the next render the marker won't be drawn. So this will also give flickering.

3. The best solution I can come up with now, is to draw all 3d objects, then do the getPixels on the backbuffer, and finally draw the 2D stuff. This should work, but I have no idea how to do a getpixel on the backbuffer.

And (finally :wink:) my questions: how can I read a pixelvalue from the backbuffer or is there a simpler way to check if an object is visible?

Any help greatly appreciated...
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I don't know how precise you want this to be, but it seems you could use the bounding box of the satellite and do pick tests that. Something like the code I posted http://irrlicht.sourceforge.net/phpBB2/ ... 11708]here a while ago. If you wanted you could check to see how many of the 8 bounding box corners are in view. If more then say 4 corners are in view you could assume that the object is in view.

If you want it to be really accurate, I mention that you could use the D3D query mechanism to find out if the object was occluded or not. More information is available here if you are interested.
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

Thanks Travis,
I don't know how precise you want this to be, but it seems you could use the bounding box of the satellite and do pick tests that. Something like the code I posted http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=11708]here a while ago. If you wanted you could check to see how many of the 8 bounding box corners are in view. If more then say 4 corners are in view you could assume that the object is in view.
I want it to be very precise - I have to make sure it gives a true when the center of the satellite is visible. It seems this code won't work if the satellite is within the bounding box of my round planet.
If you want it to be really accurate, I mention that you could use the D3D query mechanism to find out if the object was occluded or not. More information is available here if you are interested.
Cool! But I want to have my program compatible with OpenGl and software mode too :cry: Is there something similar available in Irrlicht itself?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

No, not yet implemented. OpenGL also has occlusion queries, we'd just have to develop a proper integration into Irrlicht. Suggestions are welcome, the actual implementation does not seem to be very complex for both architectures.
The software renderer won't implement this, you'll have to do triangle testing as the best method. The render-based occlusion technique is not suitable for the software renderer. It's only possible because the hardware provides a high fill rate such that it is cheaper to test for visible pixels that to test the triangle relations with other elements.
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

There is an OpenGL extionsion for occlusion queries called GL_ARB_occlusion_query. Irrlicht doesn't provide a way to do them. If it is something you need, you'll get to do it yourself.

If everything has a triangle selector, you could do the quick bb test above, and if that failed, then you could cast rays to the corners of the bounding box and see if those intersect the triangle selectors of the nodes that are intersecting each ray.

Edit: Dang. You get up to have some lunch...

Travis
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

If everything has a triangle selector, you could do the quick bb test above, and if that failed, then you could cast rays to the corners of the bounding box and see if those intersect the triangle selectors of the nodes that are intersecting each ray.
Unfortunately, due to the many triangles, one ray collision takes 1 second on my system and I want to keep track of about 20 satellites - so this becomes sloooowww...


Is there maybe a way to access the backbuffer in Irrlicht (no Z-values, but just the drawn pixels) or is this only used in software mode?
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

if you are just looking for a solution for planets rather than a more general case, then colliding the line with a sphere might be a better solution.
to cut down collision times you can use a combination of very low poly collision geometry, and only checking a few of them each frame.
The z-buffer exists on the card in the hardware drivers, dragging it out every frame would be rather expensive.
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

Hi Bitplane,

unfortunately I need the more general case... Otherwise 500k triangles would be a bit much to draw a sphere :wink: :lol: As I already reduced my model from 5M triangles, there is no gain there either...
The z-buffer exists on the card in the hardware drivers, dragging it out every frame would be rather expensive.
I know about the Z-buffer, but is that also true for the rendered backbuffer? I don't need the Z data if I can somehow access the drawn pixels in the backbuffer. Is this backbuffer kept somewhere in Irrlicht or is it also in the graphics card and blitted directly onto the screen?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The backbuffer is (of course) not directly accessible by the CPU as this would require a complete transport into main memory on each frame. This would easily fill the RAM bus. But you can access it on demand by making a screenshot.
I don't understand what your problem with sphere collision is. It's just to avoid unnecessary testing. So you simply check if the mesh is inside some maximal distance to the planet. In case it is not you can immediately stop, otherwise you do a more exact test.
Ico
Posts: 289
Joined: Tue Aug 22, 2006 11:35 pm

Post by Ico »

Just another ideas - as i don't know when your highlight/selection should disappear (once the object touches the planet, once the objects centre is hidden, once the whole object is hidden):

Don't draw a 2d image to highlight the planet/satellite/whatever. Instead attach a billboard to it's center with the planet/satellite being it's parent.

Add another (far more simple) sphere to your planet and use it for collision detection?
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

@Hybrid:
I don't understand what your problem with sphere collision is. It's just to avoid unnecessary testing. So you simply check if the mesh is inside some maximal distance to the planet. In case it is not you can immediately stop, otherwise you do a more exact test.
I used the planet-satellite situation as an example. What I actually want to do is to have floating labels on any model. For instance an engine model, with little tags saying valve, spark plug etc. So a sphere can't be used. If the model is rotated and these parts become obscured by other engine parts, I don't want the tags to be visible. As the models are very large, normal collision detection is too slow. As there may be about 40 labels on the engine, I would have to do the collision check for all of them. So, on my computer, one scene could take 40 seconds to render. That's why I'm looking for another way to detect if a part is visible.

As I'm interested in only a few pixels on the screen, maybe it would be possible to only get those pixels from the graphics card? Or is the Screenshot function limited by hardware and always returns a full screen?
Ico
Posts: 289
Joined: Tue Aug 22, 2006 11:35 pm

Post by Ico »

Hm... How about attaching billboards and/or text nodes to your satellites as childs?
Brainstorm
Posts: 5
Joined: Wed May 23, 2007 1:30 pm

Post by Brainstorm »

I am rather new to irrlich and I don't know if this will work at all but can't you make custom scenenodes (example 3) for the planet and the satellites . Then in the render function you can check if the satelite was drawn before (behind) or after (in front of) the planet.

Code: Select all

//main loop
while(device-run()){
driver->beginScene()
planetDrawn = false

smgr->drawAll()
        //here all satelites behind the planet are drawn before the planet
        //the planet is drawn and the var planetDrawn is set to true
        //all satelites that are drawn after the planet also draw a marker

driver->endScene()

}
I am not sure if it is actually so that the order of redering is changed at all. and if the order is changed I don't know exactly when the satellite is behind the planet. I think that the marker will not be drawn when the satelite is longer away from the planet but the planet is not above the satelite. So maybe this is not the best solution. Also it won't work with more than one camera as the planetDrawn variable is not reset when the other "cameras" begin their rendering. The scene is rendered once per camera and scene, right?
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

As the models are very large, normal collision detection is too slow.
If your model has many polys and you are doing lots of collision testing, it might be worthwile to make a seperate collision mesh to use for triangle selection. It doesn't have to be shaped exactly like the actual engine, it just needs to have the general shape and a minimal number of polys.

If you did that, you could use the simple test with getSceneNodeFromRayBB() and a ray from the camera to the center of the part of interest. If the node that gets picked is not that part, then you would use getCollisionPoint() to see if the other object meshes are in the way or not.

Travis
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

Thanks for your suggestions!

@Ico:
Billboards will work, but they will be drawn even if the part is not visible. Finding out if it is visible is the problem here...

@Brainstorm:
I doubt this will work because most of the time the 'satellites' are within the same Z-range of the 'planet'. Indeed I use 1 camera and scene.

@Travis:
Thanks, maybe that is the best solution thus far.

Never thought that something that looks so simple, would be so hard to achieve...
Post Reply