Tutorial
[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:
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:
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