Rendering animated tree

Started by
7 comments, last by jmakitalo 12 years, 1 month ago
I'm trying to create a procedural tree generator and renderer for my OpenGL 3D engine. I would like to be able to efficiently animate the tree waving in the wind. I'm using VBO to render the trees now so that all vertices of a tree are in one buffer and each branch (and the trunk) have their own index buffer.

At the moment my idea is to use a separate index buffer for each branch to allow different level of detail sets (index buffers) for different branches. This might not be the best way in the end.

There are two ways I can think of to do the animation:

(1) Define each branch in a local space and then transform them to proper position and orientation before calling glDrawElements.

(2) Give vertices a branch/bone index and do the transformations in vertex shaders. This allows to render the whole tree by using a single call to glDrawElements and no OpenGL transformation calls would be needed.

Which one do you think would be faster? Is there a better way?
Advertisement
Hi!


(2) Give vertices a branch/bone index and do the transformations in vertex shaders. This allows to render the whole tree by using a single call to glDrawElements and no OpenGL transformation calls would be needed.

This approach is definitely the better idea. Imagine you have hundreds of branches. You don’t want to fill up your command buffer with hundreds of draw calls (each command would require its own GPU cycle.)

However, you have to think about how to read in the transformation data. You could either read in the data from uniforms or an additional vertex stream. If you go with uniforms you typically encounter “constant waterfalling”, a serialization of the uniform data fetches. The ALUs process multiple vertices simultaneously, but each vertex might need a different constant, so the ALU has to wait until all constants are fetched. If your vertex shader is ALU bound you probably notice it.
The other common solution is, as I said to read data from another vertex stream. Well, third option (but probably slower) is to fetch the data from a texture based on the primitive index.

Cheers!

This approach is definitely the better idea. Imagine you have hundreds of branches. You don’t want to fill up your command buffer with hundreds of draw calls (each command would require its own GPU cycle.)

However, you have to think about how to read in the transformation data. You could either read in the data from uniforms or an additional vertex stream. If you go with uniforms you typically encounter “constant waterfalling”, a serialization of the uniform data fetches. The ALUs process multiple vertices simultaneously, but each vertex might need a different constant, so the ALU has to wait until all constants are fetched. If your vertex shader is ALU bound you probably notice it.
The other common solution is, as I said to read data from another vertex stream. Well, third option (but probably slower) is to fetch the data from a texture based on the primitive index.


Thanks for the insight. I have my skinned mesh system implemented so that bone matrices are passed as uniforms. It has worked well, but I have no idea how much there really would be room for improvement. I think it might not be necessary to animate all brances of a tree. Maybe just every second one.

A branch does not need more than two degrees of freedom in movement: two angles. So maybe I should not pass in a transformation matrix (4-by-4) for each animated branch, but instead two angles and a translation vector (5 floats). Then compute the rotation and translation of each vertex in the shader. Actually the translation is a constant, so that it could be stored as static VBO, so only two floats need to be passed as uniform per branch. This has the drawback that the rotations need to be computed in the shader. Maybe for small rotation angles I could approximate sin and cos to first order to make the computation of rotations fast.

I have my skinned mesh system implemented so that bone matrices are passed as uniforms. It has worked well, but I have no idea how much there really would be room for improvement.

For the trees you could consider to read the skinned data back via transform feedback to another vertex buffer and just reuse the skinned geometry (instancing like).

Or perhaps you can make the animation of a tree entirely procedural, so that it can be computed based on just a single parameter: the time. This uniform would be the same for all branches, so no constant waterfalling. You could give each branch a static random seed (encoded in a second per-instance stream) or some base phase shift, in case you use sines or cosines for the periodic behavior. Well, and perhaps add in some uniform overall direction, so that all leafs would more or less sway in the same direction (so you can change the wind direction).
Single problem I see are sub-branches, since their positions depends on the swaying of the parent branch. How stormy will your scenes be? smile.png

Best regards!

Or perhaps you can make the animation of a tree entirely procedural, so that it can be computed based on just a single parameter: the time. This uniform would be the same for all branches, so no constant waterfalling. You could give each branch a static random seed (encoded in a second per-instance stream) or some base phase shift, in case you use sines or cosines for the periodic behavior. Well, and perhaps add in some uniform overall direction, so that all leafs would more or less sway in the same direction (so you can change the wind direction).
Single problem I see are sub-branches, since their positions depends on the swaying of the parent branch. How stormy will your scenes be?


I'm not trying to make the simulation anything too fancy. Just to give a sense of wind and make the trees look dynamic. So it could be possible to just give the time and then use the same rotation formula for each branch, just with a different phase shift. I could make a VBO with four floats per vertex, the first three being the branch translation vector to "tree" space and the fourth would be a phase shift. Sub-branches would be problematic, as you stated, but just animating on the level of the main branches will probably be good enough. The main trunk would need to be animated also, but this can probably be done by just rotating the whole tree by using glRotatef before glDrawElements.

How do they animate the trees in Battlefield 3?

I'm not trying to make the simulation anything too fancy. Just to give a sense of wind and make the trees look dynamic. So it could be possible to just give the time and then use the same rotation formula for each branch, just with a different phase shift. I could make a VBO with four floats per vertex, the first three being the branch translation vector to "tree" space and the fourth would be a phase shift. Sub-branches would be problematic, as you stated, but just animating on the level of the main branches will probably be good enough. The main trunk would need to be animated also, but this can probably be done by just rotating the whole tree by using glRotatef before glDrawElements.

Sounds good.


How do they animate the trees in Battlefield 3?

Battlefield 3 used the middleware engine SpeedTree. It is used in many games and movies (including Avatar btw).

Cheers!
You could give to every vertex also a weight. Then animate it with a shader.
Depends how you want your animation ofc. parse something like animation time, and wind direction/turbulence what ever.

You could give to every vertex also a weight. Then animate it with a shader.
Depends how you want your animation ofc. parse something like animation time, and wind direction/turbulence what ever.


Weights might make the animation look more detailed. i'll try that.
I implemented the GPU animating of the trees. Check out the video I uploaded to the project page:

http://www.perilouspenguin.com/glfps/?page_id=9

The video is a bit laggy because of the recording software, but the frame rate is actually great.

Thanks for the advice guys!

This topic is closed to new replies.

Advertisement