Wiki

Clone wiki

Core / BricksShader

Back to Built-in Shader Packs


Bricks Shader

Introduction

'Bricks' is an example shader provided in Codea's 'Patterns' Shaders Pack.

Vertex shader

The vertex shader simply passes the 'attribute' variables position and color on to the accompanying fragment shader as 'varying' variables vPos and vColor:

void main()
{
    ...
    vColor = color;
    vPos = position;
    ...
    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 sets the gl_FragColor in main() as an opaque colour constructed from color (of type vec3) and a final component (the alpha channel) of 1.0:

gl_FragColor = vec4(color, 1.0);

color is calculated based on the 'varying' variable vPos and four 'uniform' variables: brickColor, mortarColor, brickSize and brickPct.

Only the xyz components of vPos (of type vec4) are used. Those components are scaled by the corresponding components of brickSize (of type vec3) and the result held in variable position:

position = vPos.xyz / brickSize.xyz; // Equivalent to: vPos.xyz / brickSize;

Only the rgb components of the two 'colour' variables are used.

color is also tinted by multiplying it, component-by-component, by the rgb components of vColor.

color = mix(mortarColor.rgb, brickColor.rgb, useBrick.x * useBrick.y * useBrick.z);
color *= vColor.rgb;

The built-in mix() function (see Section 8.3 'Common Functions' of the GLSL ES specification) is used to set color to either the mortarColor or the brickColor. The brickColor is selected only if all of the components of useBrick are 1.0.

useBrick is set using the built-in step() function (see Section 8.3 'Common Functions' of the GLSL ES specification):

position = fract(position);
useBrick = step(position, brickPct.xyz);

Example of use

The code below is a simple example of the use of the shader:

supportedOrientations(LANDSCAPE_LEFT)
function setup()
    if deviceMetrics().platformName == "iPad 1G" then
        print("This code needs a gyroscope."..
            " An iPad 1 does not have one.")
    else
        print("Rotate the Viewer about the stack of bricks.")
    end
    local size = math.min(HEIGHT, WIDTH) / 2
    d = size * 3
    m = cubeMesh(size)
    dirz = vec3(0, 0, 1)
    diry = vec3(0, 1, 0)
    dirx = vec3(1, 0, 0)
    fill(255)
end

function draw()
    background(0)
    perspective()
    local mat = matrix()
    local dxa = RotationRate.x
    local dya = RotationRate.y
    local dza = RotationRate.z
    mat = mat:rotate(dza, dirz.x, dirz.y, dirz.z)
    mat = mat:rotate(dya, diry.x, diry.y, diry.z)
    mat = mat:rotate(dxa, dirx.x, dirx.y, dirx.z)
    dirx = mult(mat, dirx)
    diry = mult(mat, diry)
    dirz = mult(mat, dirz)
    local x = dirz.x * d
    local y = dirz.y * d
    local z = dirz.z * d
    camera(x, y, z, 0, 0, 0, diry.x, diry.y, diry.z)
    m:draw()
end

function cubeMesh(size)
    local v = {}
    for i = 0, 7 do
        local x = (i % 2) * 2 - 1
        local y = (math.floor(i / 2) % 2) * 2 - 1
        local z = (math.floor(i / 4) % 2) * 2 - 1
        v[i] = vec3(x, y, z) * size / 2
    end
    local ver = {}
    for v1 = 1, 3 do
        local v2 = v1 * 3 % 7
        local v3 = 7 - v1
        local v4 = 7 - v2
        local vt = {v[0], v[v1], v[v2],
            v[0], v[v3], v[v4], 
            v[7], v[v2], v[v1],
            v[7], v[v4], v[v3]}
        for i = 1, #vt do
            ver[(v1 - 1) * #vt + i] = vt[i]
        end
    end
    local m = mesh()
    m.vertices = ver
    m:setColors(255, 255, 255)
    m.shader = shader("Patterns:Bricks")
    m.shader.brickColor = color(187, 57, 41, 255)
    m.shader.mortarColor = color(150, 131, 131, 255)
    m.shader.brickSize = vec3(225, 75, 112)
    m.shader.brickPct = vec3(215/225, 65/75, 102/112)
    return m
end

function mult(mat, vec)
    local v1 = mat[1] * vec.x + mat[5] * vec.y + mat[9]  * vec.z
    local v2 = mat[2] * vec.x + mat[6] * vec.y + mat[10] * vec.z  
    local v3 = mat[3] * vec.x + mat[7] * vec.y + mat[11] * vec.z
    return vec3(v1, v2, v3)    
end

Updated