SunnySuite / Sunny.jl

Spin dynamics and generalization to SU(N) coherent states
Other
86 stars 19 forks source link

Orbit controls and axis compass for 3D viewers #147

Closed kbarros closed 10 months ago

kbarros commented 1 year ago

We're using the Makie LScene object which uses three Euler angles to represent the camera rotation. This maintains a sense of the "up" direction, but suffers from gimbal lock.

For crystals, it would be more natural to have something like the OrbitControls of three.js. This could be implemented using quaternions. Perhaps there is a way to do it using the camera interface or perhaps we will need help on the Makie forums.

As part of this work, we should implement a "compass" to visualize the global coordinates for the current orientation state of the camera.

kbarros commented 1 year ago

Partially resolved in https://github.com/SunnySuite/Sunny.jl/pull/157

Remaining pieces: [ ] Compass to visualize global coordinates. [x] Diagnose apparent Makie bug in cam3d_cad!. (The solution was to use cam3d!with args fixed_axis=false and zoom_shift_lookat=false)

kbarros commented 1 year ago

As of Makie 0.20-beta, camera control only works in GLMakie, but not WGLMakie. This was confirmed by Simon Danisch.

kbarros commented 11 months ago

Regarding the "compass" feature, here are two relevant resources:

https://discourse.julialang.org/t/how-to-display-moving-objects-in-makie-jl/54282/9 https://discourse.julialang.org/t/makie-linking-cameras-in-multiple-3d-plots/83309/6

Not clear whether this will work also for WGLMakie.

kbarros commented 10 months ago

Feature added in https://github.com/SunnySuite/Sunny.jl/commit/26b49cfaf606901bd73330a383015e3b19da88ca

There is still a question about how to make an inset BBox LScene interact well with its parent following https://juliadatascience.io/makie_layouts. Here is a reduced text case:

using GLMakie, LinearAlgebra

function add_cartesian_axes_inset(fig, lscene; left=0, right=450, bottom=0, top=450)
    ax = LScene(fig, bbox=BBox(left, right, bottom, top), show_axis=false)

    # Draw arrows at origin
    pts = [Makie.Point3f0(0, 0, 0), Makie.Point3f0(0, 0, 0), Makie.Point3f0(0, 0, 0)]
    vecs = 0.8 * [Makie.Point3f0(1, 0, 0), Makie.Point3f0(0, 1, 0), Makie.Point3f0(0, 0, 1)]
    Makie.arrows!(ax, pts, vecs; color=[:red, :green, :blue], arrowsize=0.3, depth=100.0)

    # Link ax camera to lscene camera
    cam = lscene.scene.camera_controls
    onany(cam.eyeposition, cam.lookat, cam.upvector; update=true) do cam_eye, cam_lookat, cam_upvector
        eye = 4normalize(cam_eye - cam_lookat)
        lookat = Makie.Point3f0(0, 0, 0)
        update_cam!(ax.scene, eye, lookat, cam_upvector)
    end

    return ax
end

begin
    fig = Figure()
    lscene = LScene(fig[1,1])
    inset = add_cartesian_axes_inset(fig, lscene)
    meshscatter!(lscene, rand(Point3f, 50), color=:gray)
    fig
end

Remaining questions: