Monument Valley-style orthogonal projection 3D

I had thought about this yonks ago in terms of trying to do old fashioned isometric style games but with 3d assets, but never got my head around what I’d have to do to the projection matrix. Didn’t know you could ortho with parameters like this…

Below is an instanced shader example from the forum, but patched to ortho projection. It messes with your head because my brain assumes it’s perspective so I think they slope away from each other, but it’s all parallel. Very cool. You could build a Fez like thing using this very well as well I think…

function setup()
    m = mesh()

    m.vertices, m.texCoords = addCube()
    m:setColors(color(255,200,0))
    m.shader = shader(vert, frag)
    m.texture = readImage("Planet Cute:Wall Block")
    numInstances = 100

    dummy = m:buffer("dummy") --test vec4 attribute
    transform = m:buffer("transform") --test mat4 attribute

    -- Here we resize the transform buffer to
    -- the number of instances, rather than vertices
    -- note that the buffer can be any size:
    --  if you render N instances with a buffer sized to M
    --  where N > M then the instances will use a divided
    --  version of the buffer
    --
    -- E.g. I render 10 instances with 5 transforms then
    --  instance 1,2 use transform 1
    --  instance 3,4 use transform 2
    --  instance 5,6 use transform 3
    --  ... etc
    transform:resize(numInstances)

    -- We have to tell Codea to treat this buffer as an
    -- instanced buffer, that is, it is not per-vertex
    transform.instanced = true

    for i=1,m.size do
        -- Set per vertex
        dummy[i] = vec4(0,0,0,0)
    end

    for i=1,numInstances do
        -- Sets one transform *per instance*
        local x = ((i-1)%10) - 5.5
        local y = math.floor((i-1)/10) - 5.5
        transform[i] = matrix():translate(x * 2, y * 2, 0)
    end
    rot = 0
    pos = vec3(0,0,0)
end

function draw()
    background(40, 40, 50)

    --perspective()
    ortho(-10,10,-10,10,-2000,2000)
    camera(30,40,20, 0,0,0, 0,0,1)
    --another angle:
    --camera(30,0,0,0,0,0,0,0,1)
    -- mesh:draw can now take a number of instances
    -- it draws this many, instanced buffers can be
    -- used to differentiate each instance within a
    -- shader
    rot = (rot + 0.2%360)
    --pos = pos + vec3(-0.02,0,0)
    translate(pos:unpack())
    rotate(rot)
    m:draw(numInstances)
end

vert=[[
uniform mat4 modelViewProjection;

attribute mat4 transform;
attribute vec4 position;
attribute vec4 color;
attribute vec4 dummy;
attribute mediump vec2 texCoord;

varying lowp vec4 vColor;
varying mediump vec2 vTexCoord;

void main()
{
    vColor = color;
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * (transform * position + dummy); } ]]

frag=[[
uniform sampler2D texture;
varying lowp vec4 vColor;
varying mediump vec2 vTexCoord;
void main()
{
    gl_FragColor = texture2D(texture, vTexCoord) * vColor; } ]]

function addCube()
        local vertices = {
      vec3(-0.5, -0.5,  0.5), -- Left  bottom front
      vec3( 0.5, -0.5,  0.5), -- Right bottom front
      vec3( 0.5,  0.5,  0.5), -- Right top    front
      vec3(-0.5,  0.5,  0.5), -- Left  top    front
      vec3(-0.5, -0.5, -0.5), -- Left  bottom back
      vec3( 0.5, -0.5, -0.5), -- Right bottom back
      vec3( 0.5,  0.5, -0.5), -- Right top    back
      vec3(-0.5,  0.5, -0.5), -- Left  top    back
    }


    -- now construct a cube out of the vertices above
    local cubeverts = {
      -- Front
      vertices[1], vertices[2], vertices[3],
      vertices[1], vertices[3], vertices[4],
      -- Right
      vertices[2], vertices[6], vertices[7],
      vertices[2], vertices[7], vertices[3],
      -- Back
      vertices[6], vertices[5], vertices[8],
      vertices[6], vertices[8], vertices[7],
      -- Left
      vertices[5], vertices[1], vertices[4],
      vertices[5], vertices[4], vertices[8],
      -- Top
      vertices[4], vertices[3], vertices[7],
      vertices[4], vertices[7], vertices[8],
      -- Bottom
      vertices[5], vertices[6], vertices[2],
      vertices[5], vertices[2], vertices[1],
    }

    -- all the unique texture positions needed
    local texvertices = { vec2(0.03,0.24),
                          vec2(0.97,0.24),
                          vec2(0.03,0.69),
                          vec2(0.97,0.69) }

    -- apply the texture coordinates to each triangle
    local cubetexCoords = {
      -- Front
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Right
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Back
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Left
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Top
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
      -- Bottom
      texvertices[1], texvertices[2], texvertices[4],
      texvertices[1], texvertices[4], texvertices[3],
    }
    return cubeverts, cubetexCoords
end
1 Like