Cannot change the init_value of look_at kwarg from Makie.Camera3D

This is the code modified (only 1 line) from Cameras | Makie

HAVE tried some other walkarounds, none works, either…

using GeometryBasics, LinearAlgebra

function frustum_snapshot(cam)
    r = Rect3f(Point3f(-1, -1, -1), Vec3f(2, 2, 2))
    rect_ps = coordinates(r) .|> Point3f
    insert!(rect_ps, 13, Point3f(1, -1, 1)) # fix bad line

    inv_pv = inv(cam.projectionview[])
    return map(rect_ps) do p
        p = inv_pv * to_ndim(Point4f, p, 1)
        return p[Vec(1,2,3)] / p[4]
    end
end


ex = Point3f(1,0,0)
ey = Point3f(0,1,0)
ez = Point3f(0,0,1)

fig = Figure()
scene = LScene(fig[1, 1])
cc = Makie.Camera3D(scene.scene, 
    projectiontype = Makie.Perspective, 
    lookat = [0,0,0]) # --------------> not work, HAVE tried some other walkarounds, none works, either.

linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black)
linesegments!(scene,
    [-ex, ex, -ey, ey, -ez, ez],
    color = [:red, :red, :green, :green, :blue, :blue]
)
center!(scene.scene)

cam = scene.scene.camera
eyeposition = cc.eyeposition
lookat = cc.lookat
frustum = map(pv -> frustum_snapshot(cam), cam.projectionview)

scene = LScene(fig[1, 2])
_cc = Makie.Camera3D(scene.scene, projectiontype = Makie.Orthographic)
lines!(scene, frustum, color = :blue, linestyle = :dot)
scatter!(scene, eyeposition, color = :black)
scatter!(scene, lookat, color = :black)

linesegments!(scene,
    [-ex, ex, -ey, ey, -ez, ez],
    color = [:red, :red, :green, :green, :blue, :blue]
)
linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black)

fig

In this case I think the method you’re using to construct cc doesn’t forward the lookat attribute.

You can set the value by setting cc.lookat[] = Vec3f(0, 0, 0) though! Though it only takes effect when you interact with the scene.

Yep, modifying the built-in observable cc.lookat[] will work, when interacting with EPRL afterwards. But this can be done only after the script finishing running, so it is not that ‘automatic’ for involving unnecessary interaction.

I found that the problem seems to be that Makie updates cc.lookat[] for the overall geometric/gravitational center of all objects drawn.

Therefore, even if the default value of cc.lookat[] was previously set, it will still be automatically reset in the fig line.

It seems that all other 3D scenes involving LScene have this feature or issue. For example: LScene | Makie has the same issue:

using GLMakie

fig = Figure()
pl = PointLight(Point3f(0), RGBf(20, 20, 20))
al = AmbientLight(RGBf(0.2, 0.2, 0.2))
ax = LScene(fig[1, 1], show_axis=false, scenekw = (lights = [pl, al], backgroundcolor=:black, clear=true))
# now you can plot into lscene like you're used to
p = meshscatter!(ax, randn(300, 3), color=:gray)

cc = Makie.Camera3D(ax.scene)
println(cc.lookat[])
on(events(fig.scene).window_open) do event
    if event
        println(cc.lookat[])
    end
end

fig

I found a temporary solution: add a paragraph before the ‘fig’ line:

on(events(fig.scene).window_open) do event
    if event
        cc.lookat[] = [0, 0, 0]
    end
end

The complete code is as follows:

using GeometryBasics, LinearAlgebra

function frustum_snapshot(cam)
    r = Rect3f(Point3f(-1, -1, -1), Vec3f(2, 2, 2))
    rect_ps = coordinates(r) .|> Point3f
    insert!(rect_ps, 13, Point3f(1, -1, 1)) # fix bad line

    inv_pv = inv(cam.projectionview[])
    return map(rect_ps) do p
        p = inv_pv * to_ndim(Point4f, p, 1)
        return p[Vec(1,2,3)] / p[4]
    end
end


ex = Point3f(1,0,0)
ey = Point3f(0,1,0)
ez = Point3f(0,0,1)

fig = Figure()
scene = LScene(fig[1, 1])
cc = Makie.Camera3D(scene.scene, 
    projectiontype = Makie.Perspective, 
    lookat = [0,0,0]) # --------------> not work, HAVE tried some other walkarounds, none works, either.

linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black)
linesegments!(scene,
    [-ex, ex, -ey, ey, -ez, ez],
    color = [:red, :red, :green, :green, :blue, :blue]
)
center!(scene.scene)

cam = scene.scene.camera
eyeposition = cc.eyeposition
lookat = cc.lookat
frustum = map(pv -> frustum_snapshot(cam), cam.projectionview)

scene = LScene(fig[1, 2])
_cc = Makie.Camera3D(scene.scene, projectiontype = Makie.Orthographic)
lines!(scene, frustum, color = :blue, linestyle = :dot)
scatter!(scene, eyeposition, color = :black)
scatter!(scene, lookat, color = :black)

linesegments!(scene,
    [-ex, ex, -ey, ey, -ez, ez],
    color = [:red, :red, :green, :green, :blue, :blue]
)
linesegments!(scene, Rect3f(Point3f(-1), Vec3f(2)), color = :black)

on(events(fig.scene).window_open) do event
    if event
        cc.lookat[] = [0, 0, 0]
    end
end

fig

It seems that other :kwargs of Camera3D cannot be modified from the defaults as well, by testing:

cc.eyeposition[] = Point3f(0.75f0)
println(cc.eyeposition[])
on(events(fig.scene).window_open) do event
    if event
        println(cc.eyeposition[])
    end
end

before the ‘fig’ line.

So I have to add some magics like:

on(events(fig.scene).window_open) do event
    if event
        cc.lookat[] = [0, 0, 0]
        cc.eyeposition[] = Point3f(0.75f0)
    end
end

before the ‘fig’ line,

to fix some bugs like:

thanks @xczphysics for figuring this magic out! very useful.

it would be nice if there were an “official” way to set the initial view of a 3D axis for all Makie backends. the window_open trick you outlined above works well for WGLMakie, but for GLmakie triggering on the event does not work as the window is already open, and so hence to write code that works for both, you have to duplicate what’s inside the do-block:

function init_3d()
    cc.lookat[] = [0, 0, 0]
    cc.eyeposition[] = Point3f(0.75f0)
end
on(e->e && init_3d(), events(fig.scene).window_open)
init_3d()