User Tools

Site Tools

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.


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:

  • We've added two more custom texture slots. The enumeration ETextureLayer was adjusted accordingly.
  • The enumeration EShaderUse has become ERenderPass with the following changes:
  • SRenderPass was removed from Core.h and most uses replaced by the use of ERenderPass.
  • Values in the The enumeration EResourceType are now prefixed with “GFX_RESOURCE_” instead of “RESOURCE_”.
  • The order of the EVertexProperty enumerants has changed slightly.
  • The class Vec2 was added.
  • Internally, any call to a CRT function has been replaced with a call to a SpeedTree wrapper as defined in PortableCrt.h (e.g. a call to fopen() is now st_fopen() to deal with security requirements under Windows).

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:

  • If you're using our example data structures defined in MyPopulate.h from the reference application, note that SPerCellData has been renamed to SMyPerCellData to match the rest of the data structures in the project.
  • SRowCol made SCellKey redundant (each simply holds an integer pair). SCellKey was removed and replaced with SRowCol.
  • Some key name changes in the population/culling API are listed below. Simply change the name in your calls to these functions:
    • CCell::AppendTreeInstances() in the Forest library was renamed to CCell::SetTreeInstances() because, well, it didn't append instances, it only set them.
    • CVisibleInstances::Update3dTreeLists() was renamed to CVisibleInstances::Cull3dTreesAndComputeLod().
    • CVisibleInstancesRI::Update3dTreeInstanceBuffers() was renamed to CVisibleInstancesRI::Cull3dTreesAndUpdateInstanceBuffers() for clarity's sake.
    • CVisibleInstancesRI::UpdateBillboardInstanceBuffers() was renamed to CVisibleInstancesRI::CopyBillboardInstancesToGpu() also for clarity.
  • CVisibleInstancesRI::Clear() was added for efficiency when all instances needed to be deleted quickly.
  • The class CGrassInstance is now the structure SGrassInstance and Set*() functions have been replaced with direct member variable assignments (e.g. instead of calling sGrassInstance.SetPos(my_pos), you'll assign directly, as in sGrassInstance.m_vPos = my_pos;).

Internal changes that may affect your integration:

  • CInstance has been reworked internally a little:
    • Padded to align with S3dTreeInstanceVertex and S3dBillboardInstanceVertex for streaming efficiency's sake.
    • SPEEDTREE_COMPRESS_INSTANCE_VECTORS was removed. It wasn't being used and broke the new alignment with S3dTreeInstanceVertex and S3dBillboardInstanceVertex.
  • S3dTreeInstanceVertex and S3dBillboardInstanceVertex were moved from InstancingMgrRI_inl.h to Forest.h.
  • CVisibleInstances::VisibleCells() no longer returns const TCellPtrArray& but a const TRowColCellPtrMap&. While our reference application does not access this function, yours might. Note that the return class is now a map instead of an array.

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
	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:

  • CShaderConstantBufferRI::Init(): Parameters include a register index, corresponding to the constant buffer index declared in the shader syntax. The preset register indices are declared at the top of ShaderConstantBuffers.h as macros ST_CONST_BUF_REGISTER_* and again at the top of Include_Uniforms.fx. These must remain in sync.
  • CShaderConstantBufferRI::Update(): Copies the CPU-side values to the GPU-side constant buffer.
  • CShaderConstantBufferRI::Bind(): Binds the current constant buffer to the register supplied to Init(). This is helpful and efficient when there are multiple constant buffers but only a single register. For example, every base tree has a set of shader values declared in struct SBaseTreeConstBuf (e.g. LOD values, etc). When a new base tree is being rendered, its local copy of SBaseTreeConstBuf is simply bound. No need to update or copy values from the CPU to GPU. This is the key to one of the optimizations made for 7.0.
  • CShaderConstantBufferRI::SetTexture(): The texture functions that were resident in CShaderConstantRI in 6.3.x are now housed in CShaderConstantBufferRI in 7.0.

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().


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):

  • leaves_vs/ps.fx, leaves_depth_vs/ps.fx, leaves_shadow_vs_ps.fx
  • fronds_and_caps_vs/ps.fx, fronds_and_caps_depth_vs/ps.fx, fronds_and_caps_shadow_vs_ps.fx
  • branches_vs/ps.fx, branches_depth_vs/ps.fx, branches_shadow_vs_ps.fx
  • rigid_meshes_vs/ps.fx, rigid_meshes_depth_vs/ps.fx, rigid_meshes_shadow_vs_ps.fx
  • grass_vs/ps.fx, grass_depth_vs/ps.fx, grass_shadows_vs_ps.fx
  • billboard_vs/ps.fx, billboard_depth_prepass_vs/ps.fx, billboard_shadowcast_vs_ps.fx

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 CWind::EOptions enumeration used to contain parameters for branch and leaf rolling (specifically BRANCH_ROLLING_1, BRANCH_ROLLING_2, LEAF_ROLL_1, and LEAF_ROLL_2), but these have been replaced with one parameter, ROLLING.
  • The CWind::EShaderValues enumeration has had a similar parameters removed and added, but the order was also overhauled and padded, so that it could be copied straight into the SWindDynamicsConstBuf structure as declared in ShaderConstantBuffers.h.
  • CWind::SParams has had numerous rolling wind parameters added.

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.