Views and perspective

Eyepoint and centerpoint

Thebes takes a simple view of life. There's a global Thebes realm which is created when you start using it. It's a good idea to check and/or set the currentbviewing parameters when you start a new Luxor document, in case you're inheriting anything from a previous run.

Here are the functions that control your view of the 3D scene:

  • helloworld()
  • eyepoint()
  • centerpoint()
  • perspective()

The first one is a useful one to remember: it simply resets all the viewing parameters to the defaults.

The eyepoint() function moves the eyepoint, and centerpoint() changes the location that is the center of your view. There's also an uppoint() function, usually sitting above centerpoint, which determines which way is up.

So, to see the side view of the helix, continued from the previous chapter, we can just lower our viewpoint a bit, from the default 100 in z down to 50:

helix = [Point3D(150cos(θ), 150sin(θ), 5θ) for θ in 0:π/48:4π]

setline(0.2)

eyepoint(500, 500, 50)

axes3D()

for p in helix
    pin(p, Point3D(0, 0, p.z))
end

point example

Perspective

As yet we've seen no perspective. The defaut value of the perspective parameter, as returned by perspective(), is 0. This means that there's none of that foreshortening or converging of lines that head off into the distance. And if you look at a cube, it has that familiar unrealistic appearance of cubes drawn without perspective.

function makecube()
    cube = [
        Point3D(1,   1, -1),
        Point3D(1,  -1, -1),
        Point3D(-1, -1, -1),
        Point3D(-1,  1, -1),
        Point3D(1,   1,  1),
        Point3D(1,  -1,  1),
        Point3D(-1, -1,  1),
        Point3D(-1,  1,  1)]
    r = Point3D[]

    for e in (
        [1, 2, 3, 4, 1],
        [5, 6, 7, 8, 5],
        [5, 1, 2, 6, 7],
        [7, 3, 4, 8, 5])
        append!(r, cube[e])
    end
    return r
end


pin(50makecube())

finish()

isometric cube example

This animation views the cube and changes the perspective slowly, starting at 0, then moving from 300 up to 1400.

perspective cube example

As the value of perspective increases, the apparent magnification increases, and parallel lines start to converge. The next example tries to show the converging parallel lines.

function makecube()
    cube = [
        Point3D(1,   1, -1),
        Point3D(1,  -1, -1),
        Point3D(-1, -1, -1),
        Point3D(-1,  1, -1),
        Point3D(1,   1,  1),
        Point3D(1,  -1,  1),
        Point3D(-1, -1,  1),
        Point3D(-1,  1,  1)]
    r = Point3D[]

    for e in (
        [1, 2, 3, 4, 1],
        [5, 6, 7, 8, 5],
        [5, 1, 2, 6, 7],
        [7, 3, 4, 8, 5])
        append!(r, cube[e])
    end
    return r
end


eyepoint(200, 50, 100)
perspective(150)
pts = pin(50makecube())

sethue("red")
setline(0.1)
for p1 in pts
    for p2 in pts
        p1 == p2 && continue
        rule(p1, slope(p1, p2))
    end
end

cube in perspective

There are enough converging parallel lines there to give an ancient Egyptian architect nightmares.

Orbits

To fly around the scene, you can move the eyepoint around, while looking at the center.

using Thebes, Luxor
function frame(scene, framenumber, object)
    background("skyblue")
    setlinejoin("bevel")

    setline(3.0)
    sethue("grey30")
    carpet(500)
    eased_n = rescale(scene.easingfunction(framenumber, 0, 1,
        scene.framerange.stop), 0, 1, 0, 2π)

    sethue("white")
    perspective(200)
    eyepoint(200cos(eased_n), 200sin(eased_n), 40)
    pts = pin(50object)

    sethue("orange")
    setline(0.5)
    for pair in ((1, 2), (2, 3), (3, 4), (4, 1))
        rule(pts[first(pair)], slope(pts[first(pair)], pts[last(pair)]))
    end

    axes3D()
end

function makecube()
    cube = [
        Point3D(1,   1, -1),
        Point3D(1,  -1, -1),
        Point3D(-1, -1, -1),
        Point3D(-1,  1, -1),
        Point3D(1,   1,  1),
        Point3D(1,  -1,  1),
        Point3D(-1, -1,  1),
        Point3D(-1,  1,  1)]
    r = Point3D[]

    for e in (
        [1, 2, 3, 4, 1],
        [5, 6, 7, 8, 5],
        [5, 1, 2, 6, 7],
        [7, 3, 4, 8, 5])
        append!(r, cube[e])        
    end
    return r
end


function main()
    w = 600
    h = 400
    movie1 = Movie(w, h, "3D movie")
    cube = makecube()
    d = animate(movie1,
            Scene(movie1, (s, f)  -> frame(s, f, cube),
                    1:150, easingfunction=easeinoutsine),
        creategif=true,
        framerate=20,
        pathname="/tmp/orbiting-a-cube.gif")
    return d
end

main()

animation