Wiki
Clone wikiCore / CheckerShader
Checker Shader
Introduction
'Checker' is an example shader provided in Codea's 'Patterns' Shaders Pack. Based on the location of a fragment on the Viewer, it produces a black-and-white checker-board effect.
Vertex shader
The vertex shader does nothing other than set the gl_Position
of the vertex by applying the modelViewProjection
matrix to the position
attribute:
void main()
{
...
gl_Position = modelViewProjection * position;
}
gl_Position
is a variable that is intended for outputting the vertex position in homogenous co-ordinates (that is, as a vec4
value). All vertex shaders must write a value into that variable. (See Section 7.1 'Vertex Shader Special Variables' of the GLSL ES specification.) Here, the modelViewProjection
4x4 matrix is applied to the vertex's position
. modelViewProjection
is a 'uniform' mat4
variable supplied automatically by Codea when the shader is used with a mesh. It is the current model matrix * view matrix * projection matrix. position
is a vec4
'attribute' variable, also supplied automatically by Codea from the mesh.
Fragment shader
The fragment shader makes use of a 'uniform' variable size
, which represents the length of the sides of the squares in the check, in pixels. (The other 'uniform' variable, resolution
, is not used in the code and is redundant.)
The fragment shader sets gl_FragColor
to a vec4
constructed from color
(a vec3
) and an alpha (opacity) value of 0.9
:
gl_FragColor = vec4(color, 0.90);
color
is constructed with all three components the same (col
:
color = vec3(col, col , col);
A more succinct syntax with the same effect is (see Section 5.4.2 'Vector and Matrix Constructors' of the GLSL ES specification):
color = vec3(col);
color
is declared and initialised as:
vec3 color = vec3(0.0);
The initialisation is redundant because another value is always assigned to the variable.
col
is set to 0.0
or 1.0
, depending on the components of gl_FragCoord
. Those components are initially reduced in scale by size
and rounded down to integer values:
vec2 position = (gl_FragCoord.xy);
...
float xpos = floor(position.x/size);
float ypos = floor(position.y/size);
As gl_FragCoord
is itself a vec2
value this could be rewritten more succinctly as:
float xpos = floor(gl_FragCoord.x / size);
float ypos = floor(gl_FragCoord.y / size);
col
is then calculated as:
float col = mod(xpos, 2.);
if (mod(ypos, 2.) > 0.)
if (col > 0.)
col = 0.;
else
col = 1.;
If xpos
(an integer) is even, then mod(xpos, 2.0)
is 0.0
. Otherwise the expression is 1.0
.
If ypos
(also an integer) is odd (and mod(ypos, 2.0)
is 1.0
and greater than 0.0
) then the value of col
is swapped (0.0
for 1.0
and vice versa).
The same result can be acheived by:
float col = mod(xpos + mod(ypos, 2.0), 2.0);
In summary, an equivalent fragment shader is:
precision highp float;
uniform float size;
void main()
{
float xpos = floor(gl_FragCoord.x / size);
float ypos = floor(gl_FragCoord.y / size);
float col = mod(xpos + mod(ypos, 2.0), 2.0);
gl_FragColor = vec4(vec3(col), 0.90);
}
Example of use
The code below is a simple example of the use of the shader:
function setup()
x = WIDTH / 2
y = HEIGHT / 2
a = 0
xm = 5
ym = 7
am = 3
myMesh = mesh()
myMesh:addRect(0, 0, 200, 200)
myMesh.shader = shader("Patterns:Checker")
parameter.integer("size", 20, 100, 50)
end
function draw()
background(255, 255, 0)
x = x + xm
y = y + ym
a = (a + am) % 360
if x < 0 then
x = -x
xm = -xm
end
if x > WIDTH then
x = 2 * WIDTH - x
xm = -xm
end
if y < 0 then
y = -y
ym = -ym
end
if y > HEIGHT then
y = 2 * HEIGHT - y
ym = -ym
end
translate(x, y)
rotate(a)
myMesh.shader.size = size
myMesh:draw()
end
Updated