====== Example: Wind ====== Animating a tree with wind is about as straightforward as a [[example_typical|typical geometry query]]. The only difference is that **SSteGeometryOptions::m_bWindActive** must be true and **SteGetGeometry** must be called per frame of animation with a new value for **SSteGeometryOptions::m_fWindTimeInSecs** 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 [[example_growth|animated growth example]]. #include #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; SSteGeometry* pGeometry = NULL; for (float fTime = 0.0f; fTime < c_fExampleTime; fTime +=c_fFrameTime) { sGeometryOptions.m_fWindTimeInSecs = 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. 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; }