Visibility set

Started by
9 comments, last by xgalaxy 17 years, 1 month ago
Hello! I'm wondering how performance will be in a system where you let the visibility tree class create a visibility set for a specific camera each frame, something like this:

class RenderableSet {
public:
   std::list<Renderable *> renderables;
};

class Renderer {
public:
   void Render(const RenderableSet & set);
};

class Octree : public VisiblityDeterminer {
public:
   RenderableSet & getVisibilitySet(const Camera & camera);
};

...

void Game::Render() {
   RenderableSet renderables = MyOctree.getVisibilitySet(camera);
   MyRenderer.Render(renderables);
}
The design appeals to me, but how will the performance be, I mean, creating and filling a list of renderables each frame will surely take some time when there are many objects to render? Is it a better idea to use a large std::vector instead of the std::list? And what is the "VisibilityDeterminer" usually called?
Advertisement
It is hard to say. The performance depends on the cost of the visibility test and it also depends on the effectiveness of the culling, so the performance could be good or bad.

Use a list when you are mostly inserting and/or removing from the middle of the list.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
I would recommend that you avoid re-creating the list each frame. Most games (and most 3d scenes) exhibit high coherency between frames, so it's generally more efficient to update a list repeatedly based on the assumption that things are going to mostly stay the same.

Depending on your circumstances, you might also want multiple cached sets. For example, if you have a car with a rear view mirror, and you're rendering the scene to draw the mirror's view, the set of visible things is likely to be significantly different than when you're rendering the main scene & the car. So, you'd want to have cached lists per view.
I was in your shoes many years ago. That design is intuitive but its not at all practical. The problem is you are designing your software from a top down functional point of view instead of bottom up. For a realtime application the hardware and operating system dictate your implementation. Looking at your design its going to be full of bad code thats going to stall your process. Filling a container of N items will be nothing compared to a few context switches to draw them.
Maybe I'm totally wrong, but as far as static world geometry goes, why not pre-calculate visibility? This will be the bulk of the culling/calculations required any way.

World geometry much more significant then entity geometry. And having pre-calculated visibility of world geometry can help you calculate the visibility of entities using their position in relation to world geometry and that geometries known visibility.
==============================
A Developers Blog | Dark Rock Studios - My Site
Quote:Original post by Anonymous Poster
I was in your shoes many years ago. That design is intuitive but its not at all practical. The problem is you are designing your software from a top down functional point of view instead of bottom up. For a realtime application the hardware and operating system dictate your implementation. Looking at your design its going to be full of bad code thats going to stall your process. Filling a container of N items will be nothing compared to a few context switches to draw them.


This is a useless post. Whatever visibility mechanism is required to perform well on a given piece of hardware is independent of the notion of having a visibility mechanism that selects a set of items to render. The design that was presented has no inherent flaws. As I suggested as an implementation detail, caching the list would be a significant win for most scenarios.

As to Wavesonics' post: Yes, under some circumstances it makes sense to use precomputed visibility information in the implementation of the selection mechanism.
Sure there are inherent flaws, if you actually wrote a high-performance game engine then you would know the minefields that lay ahead. Look at the code again and if you still don't see it then you just don't know how the computer hardware or graphics API works.

Quote:Original post by JasonBlochowiak
Quote:Original post by Anonymous Poster
I was in your shoes many years ago. That design is intuitive but its not at all practical. The problem is you are designing your software from a top down functional point of view instead of bottom up. For a realtime application the hardware and operating system dictate your implementation. Looking at your design its going to be full of bad code thats going to stall your process. Filling a container of N items will be nothing compared to a few context switches to draw them.


This is a useless post. Whatever visibility mechanism is required to perform well on a given piece of hardware is independent of the notion of having a visibility mechanism that selects a set of items to render. The design that was presented has no inherent flaws. As I suggested as an implementation detail, caching the list would be a significant win for most scenarios.

As to Wavesonics' post: Yes, under some circumstances it makes sense to use precomputed visibility information in the implementation of the selection mechanism.


Thanks for all the posts!

Quote:Original post by Anonymous Poster
Sure there are inherent flaws, if you actually wrote a high-performance game engine then you would know the minefields that lay ahead. Look at the code again and if you still don't see it then you just don't know how the computer hardware or graphics API works.


This is what I'm wondering. Could you please point those flaws out for me? If I could see them for myself I wouldn't have posted this question.

And this is merely the design; I will support caching and possibly pre-calculated visibility sets in the implementation.

I've been thinking a bit and thought that I should really try to minimize list copying, the RenderableList could be some kind of proxy class containg a pointer to the real RenderableList. This would result in only copying the address of a cached visibility set if the view hasn't changed (Or I could just return a pointer). But this would require allocation.. hm.
Quote:Original post by Anonymous Poster
Sure there are inherent flaws, if you actually wrote a high-performance game engine then you would know the minefields that lay ahead. Look at the code again and if you still don't see it then you just don't know how the computer hardware or graphics API works.



Hmm. I'm actually posting under my real name, and can point to finished, published front-line titles for which I was primarily responsible for writing high performance render cores on challenging platforms. You are hiding behind AP, and have provided no specific comments - just "if you don't see the flaws, you're not l33t enough." Sorry, I call BS.

As I said before, the basic notion of a having a visibility mechanism that determines which subset of renderable things will be ultimately rendered presents no fundamental design problems for any recent PC or console, including "last-gen" PS2/Xbox 1/GameCube. It certainly isn't a problem for any of the current crop (PS3/Xbox 360/Wii) or modern PCs, on any engine on top of any version of DirectX or OpenGL.

Keeping in mind that I've acknowledged that implementation issues within the design are important to final performance, feel free to point out any specific problems that will result from the fundamental design, on any relevant piece of hardware.

Or, go back to trolling under the bridge.
I'm currently working with a real-world next-gen engine that uses a very similar approach; we build a list of rendering "operations" in a high-level, platform-independent module (actually four different modules that all want to render things), and then pass this list of operations down to a platform-specific layer that sorts (and possibly culls) the list for optimal performance on a particular platform, then issues the required calls to hardware.

So far this approach is working great, and gives us the opportunity to easily do quite a few nifty optimizations - think of it like profile-guided JIT compiling, except for rendering purposes.


The main thing we've run into is overhead in shuffling the list around. We're currently leaning towards using a custom STL allocator to help alleviate the cost of building the list each frame (tests indicate that the vast bulk of the overhead comes from memory allocations and freeing, which can be eliminated using some pooled-memory hackery), but as Jason noted, caching is also a viable and effective option. In our particular situation a cache-based approach would be quite difficult, which is why we're leaning towards a pooled-memory solution instead, but if the game mechanics allow for it there's no reason not to use a caching approach instead.


For the OP, my recommendation would be to go ahead with your design, and if you run into performance issues down the road, profile carefully to find the best way to solve them.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement