Makie: programmatic control of camera

I’m trying a 3d visualization and would like to write code to control the view position & angle, and render individual frames that I can assemble into a movie. I expected something like the following to work:

julia> using GLMakie

julia> fig = Figure()

julia> ax = Axis3(fig[1, 1],
           xlabel = "x",
           ylabel = "y",
           zlabel = "z",
           aspect = (1, 1, 1)
       );

julia> scatter!(ax, rand(50), rand(50), rand(50))
Scatter{Tuple{Vector{Point{3, Float32}}}}

julia> cam = Camera3D(fig.scene);

julia> cam.eyeposition[]
3-element Vec{3, Float32} with indices SOneTo(3):
 3.0
 3.0
 3.0

julia> cam.eyeposition[] = (3, 3, 0)
(3, 3, 0)

but the scene did not update when I changed that property. Neither does update_cam!(ax.scene, (3, 3, 0)) or anything else I’ve tried. Any tips?

3 Likes

An Axis3 is not meant to be rotated around by manipulating the camera, it has azimuth and elevation properties for that. It is also not a free-view axis, because it was made to always fit into the rectangle it occupies in the layout. So usually you would use a standalone Scene or an LScene put into a layout of a Figure to get a free camera.

I’m not a 100% sure how to change that scene’s camera correctly, though.

2 Likes

There was a bit of fiddling with cameras in this thread Makie: Linking cameras in multiple 3d plots - #6 by Thomberger. I hope it helps. Maybe try to act on lookat as well.

For 3D axes are you sure update_cam! takes a tuple ? It seems it can take another camera, or update_cam!(scene::Scene, eyeposition, lookat, up = Vec3f(0, 0, 1))

1 Like

Just for completeness, here is a little MWE that shows how to access the camera:

using GLMakie

fig, lscene, plot_obj = meshscatter(rand(Point3f, 10))

# if you want to directly access the camera:
cam3d = Makie.cameracontrols(lscene)

# API with a bit more of convenience:
zoom!(lscene.scene, 1.05)
rotate_cam!(lscene.scene, Vec3f(0, 0, 0.2))
translate_cam!(lscene.scene, Vec3f(0, 0, 1))
4 Likes

The drawback off the free-view axis using Scene is that it doesn’t look good from all angles. But we could in principle improve it as well I think (it’s a very old piece of code so it hasn’t made use of a lot of features we added in the meantime that could help).

Two other questions:

  • Does the Axis3 solution also allow a zoom? For me the best is viewmode=:fit, but there’s a bit more of a border around it than I like.
  • Can I fly in with Axis3, or I should I use the older plain-Scene interface for that?

It is also not a free-view axis, because it was made to always fit into the rectangle it occupies in the layout.

That’s what I tried to convey, you cannot zoom in because then all the axis decorations would break. In my mind you can’t really have both? Full freedom of camera movement and nice axis that behaves well in a layout that is.

Also, the viewmode :stretch fills the rectangle the most, but it ignores axis aspects.

Gotcha, thanks. I think I’m going to want to fly in, so I will probably use the classic scene-based solution in Makie: programmatic control of camera - #4 by sdanisch.

One other obstacle I’ve noticed is that record doesn’t seem to follow cam3d.eyeposition[] = newpos updates that occur in the do-block. display(fig) or display(lscene) doesn’t seem to fix it. However, outside of record those take the intended effect.

cam.eyeposition etc aren’t directly connected to updates of the camera matrices. You have to call update_cam!(scene, cam) for that (or update_cam(scene, cam, eyeposition, lookat[, up])).

2 Likes