Skip to content

[Tutorial] Writing screen shaders⚓︎

Example Shaders:⚓︎

Create your own shader:⚓︎

Reload shaders of mods via console command: reloadshaders

In order to write your screen shader you need to create 'shaders.xml' in the 'content' folder that is part of your Mod folder.

shaders.xml should have the following structure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<shaders>
    <shader name="SHADER_NAME">
        <parameters>
            <param name="PARAMETER_NAME" type="PARAMETER_TYPE"/>
            ...
        </parameters>
        <vertex><![CDATA[
            VERTEX_SHADER
        ]]></vertex>
        <fragment><![CDATA[
            FRAGMENT_SHADER
        ]]></fragment>
    </shader>
    <shader name="...">
        ...
    </shader>
</shaders>

where:

  • SHADER_NAME is the shader name
  • PARAMETER_NAME is the name of each custom parameter you want to pass from Lua
  • PARAMETER_TYPE is one of the following: float, vec2, vec3, vec4
  • VERTEX_SHADER is your vertex shader which should always include these attributes:
1
2
3
4
5
6
7
8
attribute vec3 Position;
attribute vec4 Color;
attribute vec2 TexCoord;
attribute vec4 RenderData;
attribute float Scale;
...your attributes...
uniform mat4 Transform;
...
  • FRAGMENT_SHADER is your fragment shader which again should contain at least these:
1
2
3
4
5
varying lowp vec4 Color0;
varying mediump vec2 TexCoord0;
varying lowp vec4 RenderDataOut;
varying lowp float ScaleOut;
uniform sampler2D Texture0;

RenderData.xy contains the window size, while RenderData.zw is the texture size.

Scale contains Isaac's room scale based on the window size. You can see the scale in action when you resize the window and the game keeps its content fixed for a certain amount of pixels then snaps to another zoom level.

Because of engine limitation we can only pass data through the vertex shader.

Shader Example Code:⚓︎

An example of a shader with custom parameters that changes the color tint of the screen based on the player position and the ingame framecounter.

Code: → Download this example mod here ←

Result of this shader.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<shaders>
    <shader name="RandomColors">
        <parameters>
            <param name="PlayerPos" type="vec2"/>
            <param name="Time" type="float"/>
        </parameters>
        <vertex><![CDATA[
            attribute vec3 Position;
            attribute vec4 Color;
            attribute vec2 TexCoord;
            attribute vec4 RenderData;
            attribute float Scale;
            attribute vec2 PlayerPos;
            attribute float Time;
            varying vec4 Color0;
            varying vec2 TexCoord0;
            varying vec4 RenderDataOut;
            varying float ScaleOut;
            varying vec2 PlayerPosOut;
            varying float TimeOut;
            uniform mat4 Transform;
            void main(void)
            {
                RenderDataOut = RenderData;
                ScaleOut = Scale;           // Passing data to fragment shader
                PlayerPosOut = PlayerPos;   // Passing data to fragment shader
                TimeOut = Time;             // Passing data to fragment shader
                Color0 = Color;
                TexCoord0 = TexCoord;
                gl_Position = Transform * vec4(Position.xyz, 1.0);
            }
        ]]></vertex>
        <fragment><![CDATA[
            varying lowp vec4 Color0;
            varying mediump vec2 TexCoord0;
            varying lowp vec4 RenderDataOut;
            varying lowp float ScaleOut;
            varying mediump vec2 PlayerPosOut;
            varying lowp float TimeOut;
            uniform sampler2D Texture0;
            void main(void)
            {
                vec4 Color = Color0 * texture2D(Texture0, TexCoord0);
                Color.r *= PlayerPosOut.x * 0.5f;
                Color.g *= PlayerPosOut.y * 0.5f;
                Color.b *= sin(TimeOut * 0.1f);
                gl_FragColor = Color;
            }
        ]]></fragment>
    </shader>
</shaders>

To pass the parameters we use the following Lua code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
local mod = RegisterMod("ShaderMod", 1)
function mod:GetShaderParams(shaderName)
    if shaderName == 'RandomColors' then
        local playerPos = Isaac.GetPlayer().Position
        local params = {
            PlayerPos = {   playerPos.X / 100.0,
                            playerPos.Y / 100.0 },
                            Time = Isaac.GetFrameCount()
            }
        return params;
    end
end
mod:AddCallback(ModCallbacks.MC_GET_SHADER_PARAMS, mod.GetShaderParams)


Last update: September 14, 2022