meta data for this page
  •  

Example wind shader

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.

///////////////////////////////////////////////////////////////////////
//    Main SpeedTree wind system for shaders and C++
 
#include "SpeedTree/Core/SpeedTreeWind.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;
 
// in C++, the SWindStateSdk value is given by the CWindStateMgr class defined
// in SpeedTreeWind.h. Specifically, CWindStateMgr::GetShaderConstants() -- see
// the SDK reference application and online docs for details.
SWindStateSdk sCpuWindState;
 
///////////////////////////////////////////////////////////////////////
//    main
 
void main(// mesh input
              float4 vPos          : POSITION,
              float3 vNormal       : TEXCOORD0,
              float3 vBinormal     : TEXCOORD1,
              float3 vTangent      : TEXCOORD2,
              float4 vWindBranch1  : TEXCOORD3, // x=weight, y=dir, z=offset, w=ripple
              float3 vWindBranch2  : TEXCOORD4, // x=weight, y=dir, z=offset
 
          // per-instance input
              float4 vInstance0    : TEXCOORD5, // xyz=position, w=scalar
              float3 vInstance1    : TEXCOORD6, // xyz=up vector
              float3 vInstance2    : TEXCOORD7, // 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;
 
    // wind data
    sWindInput.m_sVertex.m_fRippleWeight = vWindBranch1.w;
 
    sWindInput.m_sVertex.m_sBranch1.m_fWeight = vWindBranch1.x;
    sWindInput.m_sVertex.m_sBranch1.m_vDir = UnpackNormalFibonacci(float(vWindBranch1.y));;
    sWindInput.m_sVertex.m_sBranch1.m_vNoiseOffset = UnpackInteger3(vWindBranch1.z * 255, float3(9, 9, 3)) *
                                                                    (vTreeExtentsMax - vTreeExtentsMin);
 
    sWindInput.m_sVertex.m_sBranch2.m_fWeight = vWindBranch2.x;
    sWindInput.m_sVertex.m_sBranch2.m_vDir = UnpackNormalFibonacci(float(vWindBranch2.y));;
    sWindInput.m_sVertex.m_sBranch2.m_vNoiseOffset = UnpackInteger3(vWindBranch2.z * 255, float3(9, 9, 3)) *
                                                                    (vTreeExtentsMax - vTreeExtentsMin);
 
    // wind toggles
    sWindInput.m_sOptions.m_bDoShared = true;
    sWindInput.m_sOptions.m_bDoBranch1 = true;
    sWindInput.m_sOptions.m_bDoBranch2 = 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;
 
    // 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
 
    // cpu-side state
    sWindInput.m_sState = sCpuWindState;
 
    // 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 speedtree_wind_example_vs.hlsl.