I’m currently trying to display a background image behind a LScene.
I tried to translate! the Axis containing the image behind the LScene as recommended for inset axes in Makie - Inset axes and their drawing order, but even big translation offsets do not seem to work. Is there something specific to do for LScenes ?
Il also tried plotting the image in a LScene but I have trouble orienting it properly (horizontally and in the screen plane).
Here isa MWE below with the famous cow example.
# Setup
using GLMakie
using FileIO
img = load(assetpath("cow.png"))
# Try with image in `Axis` but it is always in foreground
f = Figure()
ax = LScene(f[1,1])
zoom!(ax.scene,0.1)
ax_inset = Axis(f[1,1],aspect=DataAspect())
image!(ax_inset, rotr90(img))
f
# Try with image in `LScene` but orientation of the image in background is not easy
f = Figure()
ax = LScene(f[1,1],show_axis=true)
image!(ax, rotr90(img))
f
Hm I can also not get that to work in any way I try, the image is always in front. @sdanisch or @ffreyer might know why.
(In CairoMakie, 3D images don’t work because you don’t have 2D transforms available that would work for 3D perspective projections, we’d have to mesh render this)
Thanks @jules, I’ve also tried to replace the sub-Scene in the Scene Tutorial (Scenes and subwindows), but it seems the scene inside the LScene does not quite behave the same way as a standalone Scene
The modified scene example below
f = Figure()
lscene = LScene(f[1,1],scenekw=(backgroundcolor=:gray,))
scene = lscene.scene
subwindow = Scene(scene, px_area=Rect(100, 100, 200, 200), clear=true, backgroundcolor=:white)
scene
cam3d!(subwindow)
meshscatter!(subwindow, rand(Point3f, 10), color=:gray)
center!(subwindow)
scene
subwindow.clear = false
relative_space = Makie.camrelative(subwindow)
# this draws a line at the scene window boundary
lines!(relative_space, Rect(0, 0, 1, 1))
scene
campixel!(scene)
w, h = size(scene) # get the size of the scene in pixels
# this draws a line at the scene window boundary
image!(scene, [sin(i / w) + cos(j / h) for i in 1:w, j in 1:h])
scene
translate!(scene.plots[1], 0, 0, -10000)
scene
If you just want to have a background image you don’t need to have a whole Axis for it. The simplest way to do it is probably this:
f = Figure()
ax = LScene(f[1,1])
# ...
x = map(r -> minimum(r)[1] .. maximum(r)[1], pixelarea(ax.scene))
y = map(r -> minimum(r)[2] .. maximum(r)[2], pixelarea(ax.scene))
ip = image!(f.scene, x, y, rotr90(img))
translate!(ip, 0, 0, -10_000)
f
To get your subscene example to work you need to translate scene.plots[end]. Otherwise you’re translating an axis3d that LScene generated. I would also suggest you use the LScene for plotting and the extra Scene to add a background, since LScene has stuff like axis3d by default and Scene does not
Hey @ffreyer, your solution works fine when the plotted object is a 2D one, but would you know if it is possible to achieve the same thing with an 3D scene inset into another one ? For that case, the translate only moves (typically the mesh) plotted object, in the scene…
Kind of… GLMakie currently shares one depth buffer for everything that’s shown, so if you want something to show up in front or behind something you need to adjust the depth value it ends up at. For 2D you can do that easily with translate!() because the camera/view direction is fixed.
For 3D you can rotate the view so translate, which applies before that, is not helpful. You can set the closest and farthest point the camera shows though, which becomes the lowest and largest depth respectively.
fig = Figure()
main = LScene(fig[1, 1])
cat = Makie.FileIO.load(Makie.assetpath("cat.obj"))
tex = Makie.FileIO.load(Makie.assetpath("diffusemap.png"))
mesh!(main, cat, color = tex)
inset = LScene(fig, bbox = Makie.BBox(200, 400, 100, 300), show_axis = false)
mesh!(inset, Sphere(Point3f(0), 1f0), color = :lightblue)
cam = cameracontrols(inset.scene)
cam.settings.clipping_mode[] = :static # v0.20+
display(fig)
# Need to happen after display & plotting to not get overwritten
# move plot back by moving min depth closer to camera (must be > 0)
cam.near[] = 1f-5
# move plot forward by moving the max depth further from the camera
cam.far[] = 100f0
You can also adjust the depth value of a plot after all the other transformation with depth_shift. That’s probably not helpful here though, since it only translates the plot and doesn’t avoid one plot clipping into another. Adjusting near and far effectively squishes the plot into a smaller percentage of the depth range so it’ll help with clipping issues.