Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Undulate: an experiment with vertex shaders and buffers (Codea 1.5)

edited October 2017 in Code Sharing Posts: 489

Buffers are a new feature in Codea version 1.5 that allow per-vertex data to be associated with a mesh and passed to a shader as an attribute. Shaders can be used to manipulate the vertices of a mesh, as well as manipulate how pixels are coloured. The code below shows a simple application.

The code uses the '--#' convention that allows it to be pasted into a new project with the Codea tab structure preserved (by a long touch on 'Add New Project' and then 'Paste Into Project').

image

I believe that, in Codea version 1.5, it is not yet possible to pass a Lua number directly to a GLSL ES float attribute using a buffer. It is, however, possible to pass a Codea vec2 userdata value to a GLSL ES vec2 attribute and this code uses the x coordinate of two-dimensional vectors to achieve its objective in passing data.

The vertex and fragment shaders were developed in the new Shader Lab. Here, they are stored as strings in table Undulate to make the code easier to share on the Forum.

--# Main
--
-- Undulate
--

supportedOrientations(LANDSCAPE_ANY)
function setup()
    local default = 40
    local ti = table.insert -- Cache the function for speed
    function reset()
        local halfN = n/2 - 0.5
        m = mesh()
        m.shader = shader(Undulate.vertexShader,
            Undulate.fragmentShader)
        local dBuffer = m:buffer("d")
        dBuffer:resize(n * n * 6)
        local ver = {}
        local col = {}
        local len = math.min(WIDTH, HEIGHT) / n
        p = n / 2 * len
        for j = 0, n - 1 do
            local y1 = j - halfN
            local ySqr = y1 * y1
            for i = 0, n - 1 do
                local x1 = i - halfN
                local d = math.sqrt(x1 * x1 + ySqr) * default / n
                local x = i * len
                local y = j * len
                local c = rCol()
                ti(ver, vec3(x, y, 0))
                ti(ver, vec3(x + len, y, 0))
                ti(ver, vec3(x, y + len, 0))
                ti(ver, vec3(x, y + len, 0))
                ti(ver, vec3(x + len, y, 0))
                ti(ver, vec3(x + len, y + len, 0))
                for k = 1, 6 do
                    ti(col, c)
                    -- Needs to be a vec2 to work in Codea beta 1.5(16)
                    dBuffer[(i + j * n) * 6 + k] = vec2(d, 0)
                end
            end
        end
        m.vertices = ver
        m.colors = col
    end      
    parameter.integer("n", 1, 100, default, reset)
end

function draw()
    background(0)
    perspective() 
    camera(p, -200, 1000, p, p, 0, 0, 1, 0)
    m.shader.t = ElapsedTime * 3
    m:draw()
end

function rCol()
    return color(
    math.random(255),
    math.random(255),
    math.random(255))
end

--# ShaderUndulate
Undulate = {

vertexShader = [[
//
// Vertex shader: Undulate
//

uniform mat4 modelViewProjection;
uniform float t;

attribute vec4 position;
attribute vec4 color;
attribute vec2 d; // Needs to be vec2 to work in Codea 1.5(16)

varying lowp vec4 vColor;

void main() {
    float z = 50.0 * sin(d.x + t);
    vec4 p = vec4(position.x, position.y, z, position.w);
    vColor = color;
    gl_Position = modelViewProjection * p;
}
]],

fragmentShader = [[
//
// Fragment shader: Undulate
//

varying lowp vec4 vColor;

void main() {
    gl_FragColor = vColor;
}
]]
}
Sign In or Register to comment.