-
Notifications
You must be signed in to change notification settings - Fork 11
Shader Builders (.shader_builder)
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
.
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.
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
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.
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.
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 of a working shader builder file (TerrainDecalAboveShader.shader_builder
):
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.