Tutorial: Creating custom shaders for Spore

The opportunity of giving Spore better graphics is finally here! With the 2.1.0 update, SporeModderFX allows you to create new shaders!

This tutorial will be a brief example of how shaders are used. You can find more detailed information in the GitHub documentation. Before getting started, there’s some general concepts you need to know:

  • Shader: It’s the code that is executed when rendering an object. Spore uses the programming language HLSL, model 3. A shader is divided in two: the vertex shader, that is executed for every vertex in an object, and the fragment shader, that is executed in every “fragment” (pixel) of that object.
  • Material: A set of properties that define how an object is rendered. These properties include which shader it uses, textures, etc. Every model has at least one material.

Enabling custom shaders

In the future, the ModAPI Launcher will automatically load custom shaders. That is not ready yet, however, so for now you have to enable them manually, creating a simple .dll with the ModAPI SDK. If you intend to publish a shader mod, we also recommend that you wait until that new launcher is released so you don’t need to provide extra dlls.

To load the shaders (replace CustomShaderPack with whatever name your files used), insert this code into the Initialization function of the mod. You will need to include <Spore\Graphics\IMaterialManager.h>.

App::MessageManager()->AddListener([](uint32_t messageID, void* data) {
    Graphics::IMaterialManager::ReadCompiledShaders(id("CustomShaderPack"));
    Graphics::IMaterialManager::ReadMaterials(id("CustomShaderPack"));
    return false;
}, { App::kMsgAppInitialized });

Creating a basic shader

As an introduction to get started with shaders, we will write our shader in plain HLSL code. Let’s start by creating our custom shader pack. In your project, create a folder called materials_shaders~. Inside of it, you have to create a folder with your shader pack name ending with .smt.unpacked. For example, I’ll call it CustomShaderPack.smt.unpacked.

Now, as we explained before a shader is divided in two: the vertex and the pixel. Therefore, we will need to create two files: one with the .vshader.hlsl extension (vertex shader) and the other with the .pshader.hlsl (pixel shader). Both files must have the same name, which will be the name we use to call the shader.

Captura.PNG

Vertex Shader

Since we want to use this shader for static models, we don’t need animations, and so the shader is super simple. For now, we just need to convert the input vertex coordinates into clip space. If you look at the Shader Data documentation, you will see we can do that with the modelToClip shader data.

struct cVertIn
{
    float4 position : POSITION;
};

struct cVertOut
{
    float4 position : POSITION;
};

extern uniform float4x4 modelToClip;

cVertOut main(cVertIn In)
{
    cVertOut Out;
    Out.position = mul(In.position, modelToClip);
    return Out;
}

Pixel Shader

To be honest, the pixel shader we used there was just a random test to ensure shaders worked. As with the vertex shader, we will use Shader Data, particularly the time variable which changes over time (unfortunately does not work on creatures). The color is also based on the time and the texture coordinates of the pixel; again this was just random, I encourage you to experiment with different things.

struct PS_INPUT
{
float4 position : POSITION;
float2 texCoords : TEXCOORD;
};

extern uniform float time;

float4 main(PS_INPUT In) : COLOR
{
    // This shader computes the color depending on the time and UV coordinates
    return float4(sin(time), In.texCoords.x, In.texCoords.y, 1.0);
}

Modifying materials

Alright, we got the shader. But how do we get our models to use it? The answer is materials. Materials control the visual appearance of game objects, defining things such as: color, shader, textures, etc. You can check the full documentation on GitHub.

In Blender

If you have the latest version of the Blender add-ons, you can export a model that uses the shader you want. Go to the Materials pane and scroll down to RenderWare4 Material Config. There you can choose from a bunch of prefabricated materials; we are interested in the one called Custom Shader Material. In the Shader Name field you must write the name of the shader or shader builder (more on that later) you want to use: in our case, that’s CustomTestShader.

Captura

RW4 Materials

You can also modify the material of existing .rw4 models. To do it, you must open them in SporeModder FX. The model viewer will show up, and in the right side of the window there will be a list with all the materials, called Compiled States.

Captura

When you click on one of those compiled states, a text editor will show up where you can edit it. The available attributes are explained in more detail in the GitHub documentation linked before. For now, we are only interested in the shaderID attribute, which decides which shader or shader builder (more on that later) is used:

Captura

Compiled Materials

Okay but, how do we change the material of a creature? There’s no rw4 we can modify, because creatures are generated in-game. The answer is compiled materials: a list of materials that are used by the game when not applied to a specific model: for creatures, water, terrain, UI, etc. These materials are found in the materials_compiled_states_link~ folder.

Just like with shaders, you can also create your own material pack. Inside of the materials folder, you have to create a folder with your material pack name ending with .smt.unpacked. For example, I’ll call it CustomShaderPack.smt.unpacked. Inside your pack you should only include your own materials and those of Spore that you modify; don’t include everything you unpacked from Spore.

Some Spore materials have a known name, but others just have an ID; to find the one you want, it’s usually easier to first find the shader and then find which materials use it. In this tutorial we will be modifying creatures, whose material is 0xD7BE35F9.smt_t (it’s also the material for plants when close to the camera). So modify it in your own materials pack to use our new shader.

Captura

And done! Now just pack the mod, and everything should look like in the video. Except because the creature doesn’t move. I mean, it’s logical: did you write anything about animations in the shader?

Shader Builders

Some shaders have lots of variations. For example, the generic_skinning shader is sued in creatures, plants, parts,… basically everything that uses skeletal animations. Therefore, it has many variations, depending on which shader data is available, how much data is defined in the model vertices,…

Since writing different shaders for all these simple variations would require too much effort, Spore introduces a new feature: shader builders. Instead of defining a whole HLSL file, you create multiple shader fragments, pieces of code, and then a shader builder will combine those fragments depending on a set of rules evaluated when the shader is used. Shader builders go in the same folder as standard shaders, and you can include them in your custom shader pack as well. You have more information in the GitHub documentation.

By the way, notice how the file is actually called 0x80000004(generic_skinning).0.shader_builder. This means that the actual ID to use the shader is 0x80000004. This can also happen with standard shaders.

Shader Fragments

Shader fragments are those pieces of code I talked about. They are found in the materials_shader_fragments~ folder, and they are separated between pixel shader and vertex shader fragments. You have more information in the GitHub documentation.

They have a serious limitation though: only one mod can modify them at once. This means that two mods that use custom shader fragments won’t be compatible: instead, you should probably contact the other mod developer to try to include his shader fragments in your code, and use them as necessary.

All custom shader fragments go in a folder called 0x00000003.smt.unpacked, inside the fragments folder mentioned before. Unlike with materials, now you MUST include all existing Spore fragments into the folder as well, so you can keep existing Spore shaders working. Even though The setup will look something like this:

Captura.PNG

The skinning animation is done by the vertex shader, so we don’t need to modify anything of that. We will just create a testTimeColor.pixel_fragment file with this contents:

pixelFragment testTimeColor
    input -texcoords 1
    output color

    declareCode
        extern uniform float time;
    endCode

    code
        Current.color = float4(time, In.texcoord0.x, In.texcoord0.y, 1.0);
    endCode
end

Now, back to the shader builder. In the shader pack where we have the HLSL shaders, we will create a file called CustomTestSkinning.shader_builder. Since we called it different now, you will have to change the creature material again.

A shader builer file has two blocks, one for the vertex and one for the pixel shaders. You have more information in the GitHub documentation, but basically: an add instruction adds a single fragment (if certain conditions are met, or always), and a group block chooses from one of the fragments defined inside.

We can copy the vertex builder from the generic skinning builder we mentioned earlier. In our builder file, after the vertex shader, we will add the pixel builder, which just uses the fragment we created:

pixelShader
    add testTimeColor
end

Precompilation

Spore is able to compile the fragment shaders on runtime; when developing that is really conveninent, so we should enable it. Inside the DataEP1 folder where mods are installed, there’s another folder called Config. There you have to modify two files like this, to enable the FragmentCompilation property:

unknown

And done!! Pack the mod, and now you will see how creatures are affected by our color test but still can move.

But this is still not ready to release: a user that downloaded the mod would also have to enable the fragment compilation thing. That’s why SMFX includes **precompilation**: it is possible to precompile combinations of fragment shaders so that Spore never has to compile them.

Precompilations go in the files precompiled_vsh.txt (for vertex shaders) and precompiled_psh.txt (for pixel shaders). Every line in those files will be a precompiled shader: a line consists in the names of the shader fragments used, in order, and separated by spaces. In this example, we want to precompile a pixel shader that only consists of the fragment testTimeColor.

This was a random example to show how shaders work, but you can do much more complex things. Time to improve Spore’s graphics!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

Up ↑

%d bloggers like this: