6.3.2 to 7.0 Porting Guide

The 7.0 release notes contain a comprehensive list of everything that has changed in the 7.0 SDK since the last revision. Start by browsing the release notes, then return here for details on select topics.


Overview

This guide was written for SDK users who have already successfully integrated a 6.3.x version of the SDK at any level. While the internals of the SDK have changed a fair amount, the API has remained largely intact. Depending on the level of your integration, some changes may be necessary to maintain your integration.

Porting Guide Sections:


Changes at the Core Library Level

The Core library remains largely unchanged from an API standpoint. Changes are mostly some new functions that facilitate the new 7.0 features and some name changes for consistency's sake. See the section further down the page for details on the new 7.0 features and how it affected the SDK.

As for name changes, in earlier versions of the SDK, some macros were prefixed with “SPEEDTREE_”, while others were “ST_”, while others still had no prefix. In 7.0, they all begin “ST_”, so if you're depending on any of the SpeedTree Core-level macros (e.g. ST_SETS_PACKING_INTERNALLY, ST_DLL_LINK), you'll need to adjust your code.

For evaluators, calls to CCore::Authorize() are no longer necessary. Evaluators now have access to the full source of the SDK during their evaluation.

A few details of changes to the Core library that may affect you:


Population and Culling

Your 6.3.x population and culling code will not compile under 7.0 without a few changes, but fortunately, they're fairly minor. API changes include:

Internal changes that may affect your integration:


Shader Constants

The biggest change in the rendering system is the complete overhaul of the shader constants/buffer system. In earlier versions, shader constants were set using the CShaderConstant::Set*() functions, e.g. TShaderConstantClass::Set3f(g_vFogColor, 1.0f, 1.0f, 1.0f);. In the 6.3.x SDK, shader constants like g_vFogColor were actually structure objects that included a shader constant register offset – a direct mapping to where that shader constant was in the shader (e.g., c[23]).

In 7.0, the SDK takes the more commonly used approach of using constant buffers in the shaders and mapping them to C++ structures on the CPU side. Looking in [SpeedTree SDK 7]\Include\RenderInterface\ShaderConstantBuffers.h, you'll see a series of structures that match constant buffers declared in the SpeedTree shader pool, specifically in [SpeedTree Apps 7]\bin\exporters\ShaderTemplates\Include_Uniforms.fx.

Below there are two example code listings, one for the fog and sky buffer in C++ in ShaderConstantBuffers.h and another for the same values in Include_Uniforms.fx.

// simplified C++ structure describing the SpeedTree fog and sky constant buffer
struct SFogAndSkyConstBuf
{
	st_float32      u_fFogEndDist;
	st_float32      u_fFogSpan;
	st_float32      u_fSunSize;
	st_float32      u_fSunSpreadExponent;
	Vec3            u_vFogColor;
	float           m__Pad0;       // force alignment with GPU constant buffer
	Vec3            u_vSkyColor;
	float           m__Pad1;       // alignment
	Vec3            u_vSunColor;
	float           m__Pad2;       // alignment
};

On the shader side:

// example declaration from Include_Uniforms.fx
ST_CBUFFER(SFogAndSkyCBLayout, ST_CONST_BUF_REGISTER_FOG_AND_SKY)
{
	float           u_fFogEndDist;
	float           u_fFogSpan;
	float           u_fSunSize;
	float           u_fSunSpreadExponent;
	float3          u_vFogColor;
	float3          u_vSkyColor;
	float3          u_vSunColor;
};

Notice that no alignment is necessary in the shader code as most shader compilers follow the packing rules described here (also known in OpenGL circles as std140). The ST_CBUFFER macro is used to abstract the correct constant buffer syntax for our supported platforms. The second parameter to the macro determines with constant buffer register the declaration will be assigned to.

Note: Each of the variables are prefixed with “u_” to indicate that it is a uniform variable. Within the shader source, these are addressed directly (e.g. m_vSunColor, not SFogAndSkyCBLayout.u_vSunColor) and it's easier to know exactly when/where a uniform variable is being access. This is a substantial change from the “g_” prefix used in 6.3.x.

In the SpeedTree SDK, structres like SFogAndSkyConstBuf are set up from a base class to handle synchronizing with the shader-side constant buffer (see CShaderConstantBufferRI in [SpeedTree SDK 7]\Include\RenderInterface\GraphicsApiAbstractionRI.h for full details). That is, users are free to assign values in the structure, but it will also handle syncing to the shaders. Functions that facilitate this, part of every constant buffer declaration in the SDK, include:

Updating Constants

To update a constant, you must find where a particular constant buffer is located in the SDK. The main rendering loops handle most of this, but if you find that other updates must be made, reference the following table:

Constant Buffer Purpose How to Acquire
ST_CONST_BUF_REGISTER_FRAME Holds values that generally change once per frame, e.g. camera position or viewport Each CForestRI object (typically just one per scene) holds one; acquire using CForestRI::GetFrameConstantBuffer(). CMyApplication also houses several to manage deferred rendering and post fx
ST_CONST_BUF_REGISTER_BASE_TREE Each base tree (e.g. each SRT file) contains values like the number of billboard images and LOD distances Each CTreeRI object keeps its own copy and manages it internally
ST_CONST_BUF_REGISTER_INSTANCING Currently used only by the Xbox 360 platform to managing its unique instancing system Housed in the CInstancingMgr360 class
ST_CONST_BUF_REGISTER_MATERIAL Houses most of the material data like diffuse color, shininess, and transmission values Commonly there are multiple material constant buffers per base tree and elsewhere. They're housed in the CRenderStateRI class.
ST_CONST_BUF_REGISTER_WIND_DYNAMICS Holds a great deal about each base tree's wind configuration as defined in the Modeler Each CTreeRI object keeps its own copy and manages it internally
ST_CONST_BUF_REGISTER_FOG_AND_SKY The fog and sky system in the SDK is largely notional and ready to replaced with your system; it's governing values are held here Like ST_CONST_BUF_REGISTER_FRAME, Each CForestRI object holds one; acquire using CForestRI::GetFogAndSkyBufferContents()
ST_CONST_BUF_REGISTER_TERRAIN Like the fog and sky system, the SDK's terrain system is also an example. This buffer holds data like texture splat values Housed in CTerrainRI and managed internally
ST_CONST_BUF_REGISTER_BLOOM Another example system we use to enhance the reference application, this holds values we need for it It's stored outside of the SDK, in the CMyApplication class, of type SBloomConstBufApp.

General Rendering

Most of the changes that affect rendering are confined to ForestRI.h. Diff'd with ForestRI.h in 6.3.2, a considerable list of changes is generated. However, if you use the high level calls CForestRI::RenderTrees(), RenderBillboards(), and RenderGrass(), very little will change. Each of these functions now takes an ERenderPass instead of a SRenderPass object as their first parameter, but remain otherwise unchanged.

There are numerous high-level rendering functions in the reference application in MyRenderFunctions.cpp: some for forward rendering, others for deferred. Find the one that most closely matches your approach and study the calls that are made into the SDK as well as higher-level classes like CMyShadowSystem that are meant to be only place holders for your own shadow system. CMyApplication::ForwardRender() is probably the most straightforward example.

Throughout the rendering functions, you'll see code similar to the listing below for setting the viewport shader constants:

// set the shader view parameters for the main view
m_cForest.UpdateFrameConstantBuffer(m_cView, m_sCmdLine.m_nWindowWidth, m_sCmdLine.m_nWindowHeight);
m_cForest.GetFrameConstantBuffer( ).Bind( );

In 6.x, this was a single call to CForestRI::UploadViewShaderParameters().


Shaders

See the release notes regarding changes to the shader templates used the Compiler application to generate SpeedTree shaders during asset compilation.

One of the biggest changes is the addition of the “Unified Shaders” compilation mode. Done by request for a AAA developer, this mode moves away from the many/shorter shader model to a fewer/longer approach in order to reduce the number of shader context switches in the render loop. Under this mode, instead of a host of oddly-named/hashed shader filenames, only the following few shaders are created (the depth and shadow variations are created depending on the compilation settings):

These shaders should yield identical visual and animation results to the more standard “Aggressive Up” or “Aggressive Down” modes, but in order to do this, a great deal of new conditionals were added to the shader templates. This was necessary so that, for example, branches_vs/ps.fx could support trees that both used branch seam blending and those that didn't. Or that leaves_vs.fx supports both high-detail wind or just general global.

These conditionals are #defined as macros, which take on different values depending on the compilation mode. These macros are generally prefixed with “ST_EFFECT_”. In modes other than Unified Shaders, these macros are defined to be “true” or “false” so that, for example, when “if (ST_EFFECT_DETAIL_LAYER)” is encountered, the shader compiler will optimize this conditional out since ST_EFFECT_DETAIL_LAYER will always be either true or false.

In Unified Shader mode, ST_EFFECT_DETAIL_LAYER will be assigned to a boolean value somewhere in the uniform shader variables. Before each draw call, a constant buffer will be bound that has the assigned value of ST_EFFECT_DETAIL_LAYER for the geometry about to be drawn and the conditional will evaluate as needed.

While reducing the number of shaders generated (and hence, the number of shader context switches needed), it does add a great number of instructions to the shader, even if large sections may be bypassed, depending on the render states. We expect that users wishing to use this mode will modify the shader templates for their own purposes, removing conditionals they know will always be true or false for their particular system or approach. By default, our shaders are worst-case in this regard – they will work for every possible combination of render state (e.g. every single combination in the “Edit Effect LOD…” and “Edit Wind LOD…” dialogs in the Compiler application).

Note: The Unified Shader mode is not supported under DirectX 9.0 or PlayStation 3.

Accessing New 7.0 Features

Optimizations and bug-fixes are accessed by simply using the 7.0 SDK, but to access some of the more important new features, you'll need to know where they reside in the code.

Rolling Wind

A short overview of the rolling wind feature can be found here.

The rolling wind effect is set per compilation session in the Compiler application. In Compile settings, it's under Effects → Enable rolling wind. Note that it's a fairly expensive effect and shouldn't be used lightly.

The addition of rolling wind had a pretty significant impact on the CWind class in the SDK. Specifically:

The effect itself is based on a Perlin noise texture lookup. The associated shader functions are found in the shader template file Include_RollingWindNoise.fx. You can see in Include_Wind.fx where calls to these functions are made, bracketed by conditionals that check ST_WIND_EFFECT_ROLLING, ST_WIND_LOD_ROLLING_FADE, and ST_ROLLING_WIND_ENABLED_DURING_COMPILE.

Rolling wind is only used in a shader if ST_WIND_LOD_FULL is also true, meaning the extra instructions won't be executed in lower-LOD wind scenarios. The rolling wind effect fades seamlessly as the full wind effect LODs to a lesser wind effect.

Hue Variation

Hue variation adds semi-random hues to individual instances or individual vertices based on parameters and a shader-based algorithm. Because this feature wasn't part of the 6.x SDK, porting isn't an issue. Details on how the system works.

Image-Based Ambient Lighting

This is new lighting effect that can be activated per base tree from the Compiler application. Details here.