Animating tree growth 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_fGrowthFrame at each frame and SSteGeometryOptions::m_bGrowthActive must be set to true.
The number of frames of growth is defined in the timeline window in SpeedTree Cinema.
This growth example is nearly identical to the wind example.
/////////////////////////////////////////////////////////////////////// // 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_Growth bool Example_Growth(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_fFramesPerSec = 30.0f; sGeometryOptions.m_bGrowthActive = true; // this is a key flag // set up time loop const int c_nNumFrames = SteGetNumGrowthFrames(pEngine); SSteGeometry* pGeometry = NULL; for (int nFrame = 0; nFrame < c_nNumFrames; ++nFrame) { sGeometryOptions.m_fGrowthFrame = static_cast<float>(nFrame); // 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. pGeometry = SteGetGeometry(pEngine, &sGeometryOptions); if (pGeometry) { // each of these children will have new, wind-affected data for (int i = 0; i < pGeometry->m_pGeometryRoot->m_nNumChildren; ++i) { const SSteGeometryBlock* pChild = pGeometry->m_pGeometryRoot->m_pChildren[i]; // process the wind-updated data (void) pChild; // quiet compiler warning } } else bSuccess = false; } // using C, so no destructors if (pGeometry) SteDeleteGeometry(pGeometry); } // using C, so no destructors SteDelete(pEngine); } return bSuccess; }