SpeedTree
    Show / Hide Table of Contents

    Example wind shader

    SpeedTree's wind system can be used in either a full Runtime SDK integration or a light/partial integration. The example code below is a DirectX 11 example of using the Runtime SDK shader wind functions. It also shows how to unpack the wind data if it was packed with the standard Runtime 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.
    SWindStateRuntimeSdk 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
        SWindInputRuntimeSdk 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_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
        WindRuntimeSdk(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.

    fxc.exe /Tvs_5_0  /I "..\..\..\Include" "speedtree_wind_example_vs.hlsl" /O2 /nologo /DST_DIRECTX11=1
    
    Copyright © 2023 Unity Technologies
    • Legal
    • Privacy Policy
    • Cookies
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)
    "Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
    Generated by DocFX.