Skip to main content
GameDev.net gamedev.net
🔒 Locked

Instanced rendering and frustum culling.

Started by NekoCode Jan 5, 2015 at 7:38 PM 12 replies 8.6k views
Original Post
NekoCode
NekoCode

Hey guys&girls, I am doing trees renderer, I need to render A LOT of trees. So the question: I have some problems implementing frustum culling and instanced rendering together ( because it picks random positions in world ) - is instanced rendering is good enough to hold a lot of rendered models ( 200-1000 models ) without frustum culling? All models are low-poly.

Thanks in advance!

swiftcoder
swiftcoder




because it picks random positions in world

Not if you are doing it right.

Frustum culling chooses a coherent region of the world. It is generally a contiguous region, roughly in the shape of a trapezoid. Provided you store your trees in a suitable data structure, you should be able to quickly extract the matching set of trees for a given region query, and render those.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
NekoCode
NekoCode

because it picks random positions in world

Not if you are doing it right.

Frustum culling chooses a coherent region of the world. It is generally a contiguous region, roughly in the shape of a trapezoid. Provided you store your trees in a suitable data structure, you should be able to quickly extract the matching set of trees for a given region query, and render those.

I mean I have method which picks random position ( XYZ ) to spawn a tree.

NekoCode
NekoCode

Well, I just have tested one thing:

Rendering 500 lo-poly trees using Instance rendering -> 30-40 fps.

Rendering 500 lo-poly trees using Frustum culling with Level of detail -> 45-60 fps. ( 60 fps is max ).

Rendering 500 lo-poly trees without any "technique" -> 15-25 fps.

But I got one interesting question: Is there function to draw only one instance(object) from instanced array?

kalle_h
kalle_h

Frustum culling should not have any relation to instancing. Could you explain why you think it does?

NekoCode
NekoCode

Frustum culling should not have any relation to instancing. Could you explain why you think it does?

I don't want to render not-visible trees while using instancing.

L. Spiro
L. Spiro

I don't want to render not-visible trees while using instancing.

Why don’t you just render the visible trees while using instancing (dynamic instancing)?

Fill out the instance buffer after culling and draw. In concept this is very simple, but thanks to the relationship between the CPU and the GPU you will have to handle a few problems to get it working smoothly.

#1: Start with a simple approach that just refills the instance buffer each frame.
#2: Double- or triple- buffer that in order to avoid GPU stalls. Fill buffer 0, then 1, then 0, then 1, etc.
#3: A very small amount of book-keeping will allow you to quickly tell if the buffer needs to be updated at all.
-#A: If all the same trees are in the view from one frame to the next, the instance buffer is already up-to-date and does not need to be re-filled at all. This is likely to happen frequently enough that it justifies this entire algorithm. Taking advantage of temporal coherence is always a major gain.
-#B: #A is for objects you know already will never move to a new position. You can make the routine more generic by storing a parallel array of pointers back to the original objects that made submissions to the instance buffer and via a callback ask them if their instance data has changed at all. This allows you the same temporal coherence as above, but works with objects that you don’t know will always be static, at the expense of just a little more book-keeping.


While this is likely to give you an overall gain in performance, there is clearly a minimal number of trees below which you do not want to using instancing at all, let alone dynamic instancing as above. If you only have 1 tree, for example, instancing period will be slower. For dynamic instancing, perhaps you should only use it when you have to draw 3 or more trees. You will have to benchmark to discover the optimal cut-off for your case.


L. Spiro
I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid
NekoCode
NekoCode

Sorry if I bother frustum culling with another stuff. I don't know how its called "on English". It's like when you turn camera, every mesh which is placed behind you is going to be hidden, so that's saves a lot of performance.

That's an idea! I can just take visible objects positions and upload this data to instance shader. Thanks! I am going to try this.

L. Spiro
L. Spiro

How do you turn off frustum culling?

Don’t run your CPU code that performs culling.

This is normally done automatically on the video card as far as I know.

The GPU has no idea what a frustum is. It performs screen-space clipping of pixels, not culling of objects.

How do you know that your instanced trees are rendered???
They are out of your visible area so you shouldn't notice it.

Rendering things off-screen still submits vertices to be processed etc. The GPU can’t clip anything not visible on the screen until it determines where on the screen each pixel should go, hence you want to cull objects that you can already determine are not on the screen on the CPU before you submit any rendering commands for them, hence frustum culling.

Do you use a CPU side frustum culling method additionaly?

That is the only type of frustum culling that exists in games.

Sorry if I bother frustum culling with another stuff. I don't know how its called "on English". It's like when you turn camera, every mesh which is placed behind you is going to be hidden, so that's saves a lot of performance.

That's an idea! I can just take visible objects positions and upload this data to instance shader. Thanks! I am going to try this.

Your terminology is correct. AppropriateUserName is mistaken.


L. Spiro
I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid
swiftcoder
swiftcoder




I mean I have method which picks random position ( XYZ ) to spawn a tree.

Does it do this as you render each tree, or are the tree positions generated ahead of time?

If they are generated ahead of time, you can insert them into a suitable spatial partitioning system (a quad tree, a spatial hash, ...), which will allow you to make region queries.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]
NekoCode
NekoCode

I mean I have method which picks random position ( XYZ ) to spawn a tree.

Does it do this as you render each tree, or are the tree positions generated ahead of time?

If they are generated ahead of time, you can insert them into a suitable spatial partitioning system (a quad tree, a spatial hash, ...), which will allow you to make region queries.

I've already made quadtree system, but when it picks random position it is also looking for the closest chunk, so there are random chunks. I know, I could write system which picks positions by indexes, but don't want to now.

But thanks anyways! I will try to get visible object positions and upload them to Instance matrix ( model view ).

NekoCode
NekoCode

Well, I don't know why, but instanced rendering is sloow. I tried to render 8-vertice mesh 32000 times and I got 10-15 fps. I got Intel HD 4000, OSX OpenGL 4.1 core profile.

I think I will leave frustum culling only.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.