meta data for this page
  •  

This is an old revision of the document!


Vertex Packing

In export formats that support it (currently only STSDK, used with the SpeedTree SDK), vertex packing lets you have complete control over the data stored in each vertex in the exported file, which allows the file data to be loaded directly into render buffers at runtime.

An XML file describes the vertex attribute setup, while a small script written in the Lua language allows you full control over packing data into each vertex however you wish.

Description XML

You define a vertex packer by placing an XML file describing it in the <app install>/vertex_packing directory.

Vertex streams represent separate buffers of data that can be bound to the vertex shader separately (though most common use is to just use one). Each stream can contain multiple vertex attributes. A description of the format is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<SpeedTreeVertexPacker
        Program=[filename of the lua script to run for this packer, 
                 often named the same but with the .lua extension]
        Force32bitIndices=[true/false to always use 32bit indices, or allow the indices
                           to fall back to 16bit if there are fewer than 65k vertices]
>
    <Stream 
        Name=[name of this stream]
    >
        <Attribute
            Type=[type of variable used for this attribute: byte, byte, short, short, int, uint, half, float, or double]
            Count=[integer for how many elements in this attribute, 1-4]
            Normalize=[doesn't affect the packing, but does tell the runtime to normalize this attribute, 
                       for instance a 0-255 ubyte will come into the shader as 0.0-1.0]
            Description=[description of this stream, if wanted]
        >
        ...
    </Stream>
    ...

</SpeedTreeVertexPacker>

Showcasing the above format description, this is the vertex packer file for the Standard packer used with the SpeedTree SDK.

<?xml version="1.0" encoding="UTF-8"?>
<SpeedTreeVertexPacker
		Program="Standard.lua"
		Force32bitIndices="false"
	>
	<Stream Name="Main">
		<Attribute Type="half" Count="4" Description="position(3) / texcoord_u(1)" />
		<Attribute Type="half" Count="4" Description="lod_position(3) / texcoord_v(1)" />
		<Attribute Type="ubyte" Count="4" Normalize="false" Description="normal(1) / binormal(1) / tangent(1) / wind_branch_dir(1)" />
		<Attribute Type="ubyte" Count="4" Normalize="true" Description="wind_weight(1) / wind_ripple(1) / wind_branch_offset(1) / ao_blend_and_2sided_packed(1)" />
	</Stream>
</SpeedTreeVertexPacker>

Packing Script

During vertex packing, the packing script specified in the description XML file is run for each vertex. This script is written in Lua. While this documentation cannot cover every aspect of the Lua language, you can find additional info at www.lua.org and Lua Tutorials.

The input data available to use in the script covers all of the data available for a vertex.

in_anchor(3 float array) - anchor position for node
in_offset(3 float array) - offset from anchor
in_lod_offset(3 float array) - lod offset from anchor
in_texcoord(2 float array) - main UV
in_lightmap_texcoord(2 float array) - lightmap UV, if available
in_normal(3 float array) - vertex normal
in_binormal(3 float array) - vertex binormal
in_tangent(3 float array) - vertex tangent
in_vertex_color(3 float array) - vertex color
in_vertex_alpha(float) - vertex blend value
in_ambient_occlusion(float) - ambient occlusion value
in_wind_branch_position(3 float array) - position used for branch position in wind
in_wind_branch_direction(3 float array) - growth direction for the branch in wind
in_wind_branch_weight(float) - weight/amount for branch wind motion
in_wind_ripple(float) - wind ripple scalar
in_bone_id(integer) - id of the bone attached to this vertex
in_two_sided(boolean) - represents the two-sided flag on the material used on this vertex
in_geometry_type(integer) - Geometry type: Branch=0, Frond, Leaf, FacingLeaf, Billboard
in_original_geometry_type(integer) - Original geometry type before batching: Branch=0, SubDivBranch, Cap, Frond, Leaf, FacingLeaf, Mesh
in_tree_extents(6 float array) - Tree extents: min xyz, max xyz

The functions available to call in the script are as follows.

Function Parameters Description
set_attribute<attribute index>, <component/swizzle index>, <double/float value> save data to the vertex attributes
set_attribute_integer<attribute index>, <component/swizzle index>, <integer value> save integer data to the vertex attributes
set_batch_type
set_batch_priority
kill Completely remove this vertex (and the polygon with which it is associated) from the final mesh.
print<string> output information to the SpeedTree Modeler Console. This is usually used for debugging, but since it is run for every vertex, be careful printing too much.
Saving Vertex Data

To place any of this data into the final vertex attributes in the export file, you use the set_attribute function or the set_attribute_integer function (when strict adherence to integers is wanted).

The value you pass to these functions will get converted to the final data type as close as possible. In this fashion, you don't have to worry about packing a float into a half float or even a byte, as the set_attribute* functions will attempt to do this for you.

Batching Control