SpeedTree
    Show / Hide Table of Contents

    Vertex packing for Runtime SDK files

    Customize data packing for SpeedTree Runtime SDK mesh export (STSDK format), using the "Vertex packing" feature.

    Overall process

    To define and apply custom data packing to STSDK export:

    1. Create a description XML file and save it in the <app install>/vertex_packing folder.

    2. Write a packing script in Lua language and save the file at the path specified in the XML file.

    3. In Game export options, under the Format-specific section, select the Vertex packing option that corresponds to your custom packer.

    Description XML

    This XML file defines the vertex packer, which includes mostly:

    • The path to the packing script to run for each vertex, and
    • A description of the vertex attributes, organized in vertex streams.

    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.

    Note

    To be able to select your custom vertex packer from the Modeler at export, you must place the XML file in the <app install>/vertex_packing folder.

    XML file format

    <?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, ubyte, short, ushort, 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 needed]"
            >
            ...
        </Stream>
        ...
    </SpeedTreeVertexPacker>
    

    Example: Standard packer

    Content of the Standard packer description XML file provided by default with the Modeler:

    <?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 (in Lua)

    This script packs the model input data into the vertices of the exported file. During export, the Modeler runs the script for each vertex.

    Note

    To allow the Modeler to run this script, you must name and place it according to the path you specified in the description XML file.

    Script language and capabilities

    You have to write the packing script in Lua language. For more information and examples about this language, refer to www.lua.org and Lua Tutorials.

    The base purpose of the script is to get data from the model and pack it to the exported mesh, but you can also use any built-in Lua functions to pre-process and transform that data before packing it, if you need to. Various additional functions are also available to control batch geometry, delete vertices, or print information for debug.

    Tip
    • Get the list of all input data and SpeedTree specific functions available to write the script.
    • Look at the Standard.lua file provided by default in the <app install>/vertex_packing folder.

    Vertex data packing

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

    To place any of that data into the final vertex attributes in the export file, 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 gets converted to the final data type as close as possible. For example, 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.

    Geometry batching control

    The geometry in the tree is as batched as possible, just like in other file formats. Without any further input, the exported tree is batched into as few draw calls as possible, depending on the number of separate materials produced after atlassing.

    However, you have some control over this from the packing script. The set_batch_type function can pull geometry out into a separate draw call. For example, you might want to pull anything with a blend/alpha value other than 1.0 out into a separate draw call to avoid rendering the whole tree with alpha blending on.

    To do this, you can set any integer you wish to set_batch_type. The default is 0. Any unique integer passed causes a new draw call filled with all of the geometry set to that integer. The batch type value is available in the file and through the SpeedTree SDK to do with as you wish at runtime. You can encode all sorts of things into the batch type, and cause different rendering states or shaders to be used at runtime on that piece of geometry.

    Polygons are made up of multiple vertices, and they may have different values for the code used in set_batch_type. You may want to make sure that a certain vertex value takes priority over the other vertices in that polygon. To do this, use set_batch_priority. With the previous example of pulling out polygons needing alpha blending, you would set the priority to 1 if blend/alpha is less than 1.0 and 0 otherwise. This ensures that any polygon needing to be put into the batch type of 1 gets that value.

    Lua batching examples

    -- batch by geometry type
    set_batch_type(in_geometry_type)
    
    -- batch by two-sided or not
    if in_two_sided then
        set_batch_type(1)
    else
        set_batch_type(0)
    end
    
    -- batch by needing blending
    if (in_vertex_alpha < 1.0) then
        set_batch_type(1)
        set_batch_priority(1.0)
    else
        set_batch_type(0)
        set_batch_priority(0.0)
    end
    
    -- batch by geometry type AND two-sided
    if in_two_sided then
        set_batch_type(in_geometry_type + 5)
    else
        set_batch_type(in_geometry_type)
    end
    

    Reference

    Available input data

    List of all vertex data available as input for data packing customization.

    Variable Type/format Description
    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_branch1_position 3 float array Branch tip position for level-1 branch in wind.
    in_wind_branch1_origin 3 float array Pivot point position for level-1 branch in wind.
    in_wind_branch1_direction 3 float array Growth direction for level-1 branch in wind.
    in_wind_branch1_weight float Weight/amount for level-1 branch wind motion.
    in_wind_branch2_position 3 float array Branch tip position for level-2 branch in wind.
    in_wind_branch2_origin 3 float array Pivot point position for level-2 branch in wind.
    in_wind_branch2_direction 3 float array Growth direction for level-2 branch in wind.
    in_wind_branch2_weight float Weight/amount for level-2 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.

    Available functions

    List of all SpeedTree specific functions you can call in the script, in addition to built-in Lua calls.

    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 <integer> Set the batch type for this vertex. Refer to batching control.
    set_batch_priority <float> Set the batch priority for this vertex. Refer to batching control.
    kill Completely remove this vertex (and the associated polygon) from the exported mesh.
    print <string> Output information to the SpeedTree Modeler Console. Use it for debugging, but carefully, since it prints for every vertex.

    Additional resources

    • Games export options
    • Lua scripting reference manuals
    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.