SpeedTree's wind system can be used in either a full SDK integration or a light/partial integration. The example code below is a DirectX 11 example of using the SDK shader wind functions. It also shows how to unpack the wind data if it was packed with the standard SDK/Standard games vertex packers in the SpeedTree Modeler. These is the approach we used for the reference application, but developers can override any or all of it as needed.
// this header sets up a series of macros that help us write a single shader that // covers dx11, dx12, opengl, ps5, and xbox series x #include "SpeedTree/Core/UnifyHlslAndGlsl.h" // set up the example constant buffers used by the SDK and reference application; // this source file is meant to be compiled into both C++ and shader source; // #define ST_WIND_CODE_GPU for shaders #define ST_WIND_CODE_GPU #include "SpeedTree/Core/SdkConstantBuffers.h" // the speedtree wind system supports several modes (e.g. vfx, games, legacy) that // are all defined in WindShaders_All.h; define ST_WIND_SHADER_MODE_SDK to activate // the games 8 sdk mode #define ST_WIND_SHADER_MODE_SDK 1 #include "SpeedTree/Core/WindShaders_All.h" /////////////////////////////////////////////////////////////////////// // Utility_UnpackNormalFibonacci // // Used for unpacking normals packed in our vertex packing example // using our Lua function pack_normal_fibonacci(). float3 UnpackNormalFibonacci(float fPacked) { float fZ = 0.99609375 - 0.0078125 * fPacked; float fRadius = sqrt(1.0 - fZ * fZ); float fTheta = fPacked * 2.39996322973; return float3(cos(fTheta) * fRadius, sin(fTheta) * fRadius, fZ); } /////////////////////////////////////////////////////////////////////// // Utility_UnpackInteger3 // // This is used for unpacking integers in the speedtree vertex packing // example using our Lua function pack_integer(). float3 UnpackInteger3(float fValue, float3 vCoef) { float3 vReturn; float fXY = vCoef.x * vCoef.y; vReturn.z = floor(fValue / fXY); fValue -= vReturn.z * fXY; vReturn.y = floor(fValue / vCoef.x); fValue -= vReturn.y * vCoef.x; vReturn.x = fValue; return vReturn / (vCoef - float3(1,1,1)); } // example shader constants // // in our reference application, these values are made available in the // shader constant "u_sBaseTree" float3 vTreeExtentsMin; float3 vTreeExtentsMax; /////////////////////////////////////////////////////////////////////// // main void main(// mesh input float4 vPos : POSITION, float3 vNormal : TEXCOORD0, float3 vBinormal : TEXCOORD1, float3 vTangent : TEXCOORD2, float4 vWindData : TEXCOORD3, // per-instance input float4 vInstance0 : TEXCOORD4, // xyz = position, w = scalar float3 vInstance1 : TEXCOORD5, // xyz = up vector float3 vInstance2 : TEXCOORD6, // xyz = right vector // output out float4 vOutputPos : SV_POSITION, out float3 vOutputNormal : TEXCOORD0) { // skipping several routine vs items for brevity, including orienting pos // and normals based on instance orientation // pass data into speedtree's game wind system -- SWindInputSdk has // four sections: // - m_sVertex: all per-vertex data // - m_sInstance: data about the pos and orientation of this instance // - m_sOptions: compile-time flags for which wind effects to enable // - m_sState: values from the CWindStateMgr class running on CPU SWindInputSdk sWindInput; // vertex sWindInput.m_sVertex.m_vPosition = vPos.xyz; sWindInput.m_sVertex.m_vNormal = vNormal; sWindInput.m_sVertex.m_vBinormal = vBinormal; sWindInput.m_sVertex.m_vTangent = vTangent; // unpack vWindData (packing is same used by // on "Standard" vertex packer in the Modeler): // // .x = packed wind branch direction // .y = wind weight // .z = wind ripple // .w = wind_branch_offset sWindInput.m_sVertex.m_vWindBranchDir = UnpackNormalFibonacci(float(vWindData.x)); sWindInput.m_sVertex.m_fWindBranchWeight = vWindData.y; sWindInput.m_sVertex.m_fWindRippleWeight = vWindData.z; sWindInput.m_sVertex.m_vBranchNoiseOffset = UnpackInteger3(vWindData.w * 255, float3(6, 6, 7)) * (vTreeExtentsMax - vTreeExtentsMin); // instance sWindInput.m_sInstance.m_vPosition = vInstance0.xyz; sWindInput.m_sInstance.m_fScalar = vInstance0.w; sWindInput.m_sInstance.m_vOrientationUp = vInstance1; sWindInput.m_sInstance.m_vOrientationRight = vInstance2; sWindInput.m_sInstance.m_fLodValue = 0.0; // unused sWindInput.m_sInstance.m_fLodTransition = 0.0; // unused // options sWindInput.m_sOptions.m_bDoShared = true; sWindInput.m_sOptions.m_bDoBranch = true; sWindInput.m_sOptions.m_bDoRipple = true; sWindInput.m_sOptions.m_bDoShimmer = true; sWindInput.m_sOptions.m_bLodFade = false; sWindInput.m_sOptions.m_bIsGrass = false; sWindInput.m_sOptions.m_fWindIndependence = 0.5; // cpu-side state sWindInput.m_sState = u_sBaseTree.m_sWind; // call main wind function WindSdk(sWindInput); // WindSdk modifies position and can modify the normal (if m_bDoShimmer is enabled) vOutputPos = float4(sWindInput.m_sVertex.m_vPosition, 1.0); vOutputNormal = sWindInput.m_sVertex.m_vNormal; // position projection skipped for brevity... }
The vertex shader above can be compiled using the following HLSL compiler fxc.exe compilation command for DirectX 11, assuming a working directory of [SDK]/SampleForest/Shaders/
and a source filename of example_vs.hlsl
.