Animating dynamic wind-blown trees with vertex blending
Jeff Thelen, www.jeffthelen.com

A pine grove as rendered by the Quixote terrain engine
If you have played any outdoor 3D game recently, you may have found yourself gazing as often at the trees overhead as at the enemy on the horizon. Graphics developers are putting more and more effort into the recreation of the outdoors, and the results are often convincing, and occasionally more overwhelming than the game itself. Ghost Recon is one of the more striking applications in recent experience. The very first thing that caught my eye when playing the game was that not only were the oaks and pines exquisitely modelled, but the trees actually swayed in the breeze. Such small touches of versimilitude only make a game environment more believable and more pleasureable, and thus more immersive.
Rendering a convincing terrain in real-time is fraught with perils for the developer. All but the most desolate environs is host to a myriad of trees and variety of flora, each casting a shadow, each shifting in the breeze. Conquering such a terrain remains an active field of interest for many. In this article, I would like to focus on one very small patch in the landscape: the rendering of dynamic wind in modelled trees.
The keyword is dynamic, that is, wind which changes direction and speed just like in the real world. In my current terrain engine, Quixote, I am attempting to code a world where the seasons, the weather, the sun and moon, are as inconstant as the one we inhabit. The wind should range from light breezes to hurricane gales, and the trees should respond to it. I approached this challenge using a very simple application of vertex blending. Although by no means a perfect simulation of reality, the method is simple to understand, easy to implement, lightweight, efficient, and more importantly, gives a convincing illusion of actuality. Here is my approach.
The Tree Model
How to seed a 3D landscape with vegetation is itself a vast topic of discussion. As a starting point, I will assume that we have a lone tree standing somewhere in a desert. In my own work, I have unfortunuately had to create my own tree models myself, using Max 3D. Not being an artist, or at least not a very good one, the models in my landscape are often less than desired. On the other hand, they are sufficient for coding and testing. I have included such a model in the sample code with this article. The tree, it should be noted, is meant to be viewed from below, in the shade, looking up; looking down on it will reveal gaps since I am a miser with geometry.
The tree model is a few hundred faces, no more. It includes a trunk, some stick-like things resembling branches, and many quads or textured "leafy" panels that are rendered using alpha compare. With the proper texture and the right alpha rejection value, the textures look remarkably realistic against the sky, particularly when in motion. In the sample demo, I have encapsulated the tree mesh in a class called qxTree, but in a workable application the mesh object would be separate from the hundred or so tree instances, which would all reference the same mesh, textures and materials.
When the mesh is loaded, I set the blend weight for each vertex, depending on a few properties of the tree type. If you are unfamiliar with vertex blending, it is in simplest terms the application of two or more matrices, using blend weights, to vertices, allowing for animation between the matrices.
Currently, I use only one blend matrix, although more could be applied with industry and imagination. The blend matrix is set with the current wind angle, and will move vertices in that direction depending on the blending weight. A vertex with a weight of 1.0 is unaffected by the wind angle, and will simply be rendered according to its static world position. A vertex with a weight of zero, on the other hand, is wholly affected by the wind angle. A vertex with a weight between these two extremes will be a blend between the wind angle and its static world position.
In practice, I set the weight for vertices at the root of the tree
at a value
of 1.0. That is, they will never be affected by the wind, as they are rooted in
the ground. This only makes sense. At the opposite extreme is
the treetop, whose weight I set to 0.90. That is,
the vertex is 90% unaffected by the wind, and 10% affected. Vertices
between the roots and the treetop have a weight that is lerped based on their
height and the difference between the lowest and the highest weights. Halfway
up the tree, for instance, vertices will weigh 0.95.
The net result of this method is that the higher up the tree you climb, the greater the impact of the wind on the vertices. We are in effect embedding a resistance factor in the vertices. The treetop and higher branches sway in the wind more than lower branches. This method fits best tall trees like pines and palms; for those with low or pendulant branches like the oak or willow, however, it may not be a perfect fit. As an alternate, which I have not investigated, one could also take into account a vertex's horizontal distance, setting the blending weight of vertices farther from the center of the trunk to be more affected by wind. Here may also be an opportunity to use more than one blend matrix. In addition, it may be possible for blending weights to be set explicitly in the model through your modelling package, which would be ideal, if tedious.
Wind
I've coded into the demo a small class called qxWind, a lightweight wind generator that, although not meteorologically accurate, fairly mimicks the wind. The user can set a handful of parameters for the wind, including a range of wind directions and range of wind speeds. The model itself is just a series of "gusting phases", whereby the wind rises to a maximum speed then falls to a user-established minimum, before gusting again after a random period of time. The wind also has a current direction, again selected randomly between gusts from a user-established range of directions. The direction is a point on the compass, expressed as a 2-dimensional normalized vector.
So, how does the wind interact with the tree model? Each frame tick, we adjust the tree's current angle by the wind; at the same time, we have to account for the tree's physical resistance to the wind. First we get the current wind speed, and add it to the current angular velocity of the tree. The velocity is then added to the current angle, clamped to no more than 90 degrees, and we then adjust the velocity by the angle. The "physics model" here, such as it is, is a kind of inverted pendulum; for a fuller discussion, see this brief article by Hugo Eliot. In code it looks like this:
void
qxTree::Frame(){
// Code omitted
float fTime = m_pApp->GetElapsedTime();
qxWind* pWind = m_pApp->GetWind();
// Adjust angle of tree based on current wind parameters float fWindSpeed = pWind->GetCurrentSpeed(); float fWindSpeedIncrement = (fWindSpeed * fTime)*0.02f; //Increase current velocity incrementally if( m_fVelocityCurrent < fWindSpeed )m_fVelocityCurrent += fWindSpeedIncrement;
// Adjust angle by current velocitym_fAngleCurrent = (m_fAngleCurrent + m_fVelocityCurrent);
// Restrain the angle to 90 degreesm_fAngleCurrent = fmin(m_fAngleCurrent, RADIANS(
90.0f));m_fAngleCurrent = fmax(m_fAngleCurrent, RADIANS(-
90.0f)); float s = sinf(m_fAngleCurrent);m_fVelocityCurrent = m_fVelocityCurrent + ((-s) / m_fAngleLength);
m_fVelocityCurrent = m_fVelocityCurrent * m_fAngleDampening;
// Code omitted
}
You can see that it is conceivable for the tree angle to reach 90 degrees. However, the tree itself will never achieve 90 degrees unless the blend weight is 0.0, meaning that there is zero resistance to the wind. As mentioned above, I generally do not set the blend weight to less than 0.90 at its most extreme tiptop. Thus, a tree will never rotate in the direction of the wind more than 9 degrees. In the demo, however, feel free to experiment with any blend factor you like.
The last thing we need to do is render the tree. Each render frame, we have to set the blend matrix and inform the driver that we would like to use vertex blending. First, I get the current direction of the wind as the rotation axis. We will only be rotating in the x-z plane. This is then set to a matrix using the current angle, and then multiplied by the world matrix. Again, in code:
void qxTree::ApplyBlendMatrix(D3DXMATRIX& mat,LPDIRECT3DDEVICE9 pd3dDevice)
{
// Code omitted
// Get the Wind Direction Axis
qxWind* pWind = m_pApp->GetWind();
D3DXVECTOR3 vAxis = pWind->GetCurrentDirection();
D3DXMATRIX matBlend;
D3DXMatrixRotationAxis( &matBlend, &vAxis, m_fAngleCurrent );
D3DXMatrixMultiply( &matBlend, &mat, &matBlend);
// Set the blend matrixpd3dDevice->SetTransform( D3DTS_WORLD1, &matBlend );
pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS );
// Code omitted
}
As a final note, this method is not limited to trees, but can be readily applied to other types of vegetation. I use it, for instance, to put the wind into simple billboards of weeds and grass and shrubs, composed of a few triangles. The end result is a convincing illusion of greenery swaying in a breeze or gale, and from any point on the compass.
The Demo

In the demo, you'll find source code and executable for this implementation of dynamic wind-driven trees. I've implemented the demo using the D3D 9.0 SDK framework and Microsoft Visual Studio .NET (2002). The demo requires DirectX 9.0. /p>
You can experiment with differing variables in the trees and in the wind. Briefly explained:
Upper weight is the blending weight for the tiptop of the tree. The "root" blending weight is fixed at 1.0.
Length is the angle length of the tree's "pendulum" physics. Decreasing the value stiffens the resistance of the tree; increasing it, loosens the resistance.
Wind Speed Min and Speed Max establish the range of the wind speed, which is randomly selected at each gusting phase. A minimum of zero means that the wind will die down to nothing after each gust.
Inc Min and Max control the range of the wind speed increment. It is another random value that dictates how fast we gust up and down in speed on each gusting phase.
Volatility is a number between 50 and 10000, which determines when we start a new random gust. A low of 50 will result in constant gusting. Higher values only decrease probability.
Direction Min and Max establish the arc of the compass that the wind direction can range. The defaults are NW as min and NE as max. Thus, the wind direction will range over the northern portion of the compass.
Controls:
W, A, S, D move the camera
Right-Mouse button rotates the mouse-look
F2 toggles wireframe rendering on and off
You can download the demo here.
Links of Interest
Animating Prairies in Real-Time. Perbet & Cani's treatment of handling wind and vegetation in 3D.
www.vterrain.org. The Virtual Terrain Project. Indispensable resource for those interested in 3D terrain.
www.cbloom.com. Charles Bloom. Of general interest for the coder, very readable and informative matter from a practical point of view.
http://www.darwin3d.com/grass.zip. Fluid flow demo by Jeff Lander.
June, 2003