Animating a tree with wind is about as straightforward as a typical geometry query. The only difference is that SteGetGeometry must be called per frame of animation with a new value for SSteGeometryOptions::m_fTimeInSecs at each frame.
Note that there are several parameters in SSteGeometryOptions that apply to wind. Most are set in the example below.
This wind example is nearly identical to the animated growth example.
#include <cstdio> #include "speedtree_engine.h" /////////////////////////////////////////////////////////////////////// // SpeedTree Engine API error callback static void MyEngineApiErrorCallback(const char* pError) { fprintf(stderr, " **[Error Report from SpeedTree Engine API]**: %s\n", pError); } /////////////////////////////////////////////////////////////////////// // SpeedTree Engine API message callback static void MyEngineApiMessageCallback(const char* pMessage) { fprintf(stderr, " [Message from SpeedTree Engine API]: %s\n", pMessage); } /////////////////////////////////////////////////////////////////////// // Example_Wind bool Example_Wind(const char* pModelFilename) { bool bSuccess = false; // register callback message functions; when api calls fail, messages will be sent here SteSetErrorFunction(MyEngineApiErrorCallback); SteSetMessageFunction(MyEngineApiMessageCallback); // uses a C interface -- objects are created and initialized through function calls SSteEngine* pEngine = SteNew( ); if (pEngine) { // this causes the model file to be loaded and parsed, but nothing is computed yet if (SteLoadSpeedTreeFile(pEngine, pModelFilename) == STE_SUCCESS) { bSuccess = true; // geometry export options SSteGeometryOptions sGeometryOptions; SteInitGeometryOptions(pEngine, &sGeometryOptions); sGeometryOptions.m_eGroupType = STE_GROUP_BY_MATERIAL; sGeometryOptions.m_bWindActive = true; sGeometryOptions.m_fWindPrerollInSecs = 10.0f; sGeometryOptions.m_fFramesPerSec = 30.0f; sGeometryOptions.m_fWindStrength = 0.5f; // 0.0 to 1.0 range sGeometryOptions.m_bUseUniquePositions = false; sGeometryOptions.m_bComputeVelocities = false; // set up time loop const float c_fExampleTime = 10.0f; // seconds const float c_fFrameTime = 1.0f / sGeometryOptions.m_fFramesPerSec; for (float fTime = 0.0f; fTime < c_fExampleTime; fTime +=c_fFrameTime) { sGeometryOptions.m_fTimeInSecs = fTime; // SteGetGeometry() is called for each frame. Note that the tree computes internally only // once. After the first query/compute, the time taken by this function is almost entirely // from the wind computation. SSteGeometry sGeometry; SteInitGeometry(&sGeometry); if (SteGetGeometry(pEngine, &sGeometryOptions, &sGeometry) == STE_SUCCESS) { // each of these children will have new, wind-affected data for (int i = 0; i < sGeometry.m_pGeometryRoot->m_nNumChildren; ++i) { const SSteGeometryBlock* pChild = sGeometry.m_pGeometryRoot->m_pChildren[i]; // process the wind-updated data } // using C, so no destructors SteDeleteGeometry(&sGeometry); } else bSuccess = false; } } // using C, so no destructors SteDelete(pEngine); } return bSuccess; }