Skip to content

Shader Builders (.shader_builder)

Emd4600 edited this page Apr 2, 2019 · 7 revisions

Many shaders in Spore are not coded in a single .hlsl file directly. Instead, they are generated by combining different pieces of code, known as Shader Fragments. These fragments are then combined under certain conditions in the Shader Builder files.

A shader builder contains two lists of references to fragments, with certain conditions that the game must meet for that fragment to be selected. When the game needs a shader, all these conditions are checked, the correct fragments are selected and merged, and a shader is generated.

There are two types of list, both must be included in the same file:

  • vertexShader: Can only use those fragments that end with the .vertex_fragment extension.
  • pixelShader: Can only use those fragments that end with the .pixel_fragment extension.

For example, a builder list for a vertex shader might look something like this:

vertexShader
    add copyVertexColor -elements color
    add getAngle
    add toClipSpace
end

In this example, there are fragments that are always selected (getAngle and toClipSpace) and other that depend, in this case, on whether the model has vertex colors.

Shader builders are stored in the material_shaders~ (0x40212004) folder, in a .smt file; when unpacked, they finish with the extension .shader_builder. You will notice that unpacked shader builder have special names, something like 0x70000034(TerrainDebugShader).shader_builder. The real ID that must be used to reference this shader on a material is the one outside the parenthesis, that is, 0x70000034. When you create your custom shader you don't need to do that: to reference MyShader.shader_builder just use MyShader.

Coding custom shader builder

It is possible to create your custom shader builders packs. Like Standard Shaders, you can have your own MyShaders.smt.unpacked folder (where MyShaders is whatever name you want, unique to your mod) containing standard shaders and shader builders. In order to pack it, you also need to have a shader fragments pack in your project.

Pre-compiling shaders

By default, no shader builders are compiled. This means that if you want to use them in the game, you will need to enable the FragmentCompilation property in the DataEP1\Config folder. This way, Spore will compile them on runtime:

This is okay for developing, but when you release your mod you don't want the users to enable that. So instead, you can pre-compile the shaders you use. To do so, you must add two files to your shader pack: precompiled_vsh.txt (for vertex shaders) and precompiled_psh.txt (for vertex shaders). Each file will be a pre-compiled shader. Just add the names of the shader fragments you want to compile, in order. For example:

unpackNormalTangent applyMaterialColor toClipSpace
unpackNormalTangent whiteVertexColor applyMaterialColor toClipSpace

Select groups

Apart from using add to add fragments, it's also possible to choose one from a group of possible selections. For example:

group 0x1
	select applyShadowMapTerrainNest -compareData shadowMapInfo 3
	select applyShadowMapTerrain -compareData shadowMapInfo 2
	select applyShadowMapNull
end

This will select, at most, only one of those fragments; if applyShadowMapTerrainNest cannot be used, it will try with applyShadowMapTerrain, and so on. It is possible that no fragment in the group is selected at all. Notice that inside a group, you use select instead of add.

When defining a group you must also give it a name.

Attributes

Both add and select have the same attributes and options:

add fragmentName
select fragmentName

fragmentName is the name of the fragment to be used; if this is inside a vertex shader only vertex fragments can be used, and the same goes for pixel shaders.

Conditions

Add and select instructions can have certain conditions that define when these will be used. If no conditions are specified, then the fragments are always used.


-elements vertexElements...

Only uses the fragments if the input model has data for the specified vertex elements. The available elements are those accepted as inputs of vertex fragments. For example, add myFragment -elements position color.


-require groups...

Only uses the fragments if all of the selection groups specified have been used as well. For example, if we have a group caled VertexColoring, we can do add myFragment -require VertexColoring.


-exclude groups...

Only uses the fragments if none of the selection groups specified have been used. For example, if we have a group caled VertexColoring, we can do add myFragment -exclude VertexColoring.


These conditions are mutually exclusive, meaning that only one of them can be used:

  • -hasData dataNames...

Uses the fragment if the game has defined data for the specified Shader Data names; you can use from 1 to 3 names. For example, add myFragment -hasData skinWeights cellStage

  • -compareData dataName value

Uses the fragment if the game has defined data for the specified Shader Data, and that has the same value as specified. For example, select myFragment -compareData shadowMapInfo 2

  • -array dataName

Uses the fragment if the game has defined data for the specified Shader Data. Furthermore, it will use that data value as an array index, so if the fragment is at index 123 and the shader data has value 5, it will use the fragment 123+5 = 128. For example, select uvTweak_projectXY -array uvTweak: all fragments after uvTweak_projectXY are also related, the one that is sued is determined by the value of uvTweak.

  • -objectTypeColor value

Uses the fragment if the game has defined objectTypeColor data and it has the same value as specified. For example, select myFragment -objectTypeColor 2

  • -hasSampler index

Uses the fragment if the game has defined a texture sampler for the given inde. For example, select myFragment -hasSampler 0

  • -unk12 value1 value2

Unknown usage.

Example

Example of a working shader builder file (TerrainDecalAboveShader.shader_builder):

Render Types

Spore has a special feature called render types: a single shader can have multiple versions of the code depending on the current render type. For example, there's one shader for rendering creatures (generic_skinning), but it has different code for the hologram render type (15). The only known render types are:

  • 0: the base and default render type
  • 15: hologram

In your custom sahders you can provide the different versions on the code by adding their number at the extension. For example, to make the code for MyShader at render type 15 you must use MyShader.15.vshader.hlsl (and same for .pshader). When no number is specified, the sahder will be packed for the default render type.

You can’t perform that action at this time.