MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.38k stars 302 forks source link

WGLMakie DataInspector does not cover everything #3773

Open kbarros opened 5 months ago

kbarros commented 5 months ago

Consider the following code:

fig = Figure()
ax = LScene(fig)
fig[1, 1] = ax
meshscatter!(ax, [Point3f(0,0,0), Point3f(1,0,0), Point3f(1,1,1/2)]; color=:white, markersize=0.2)
text!(ax, Point3f(1,1,1/2); text="Not hidden!", color=:red, align=(:center, :center), fontsize=16, overdraw=true)
arrows!(ax, [Point3f(1,0,0)], [Vec3f(0,1,0)]; color=:yellow)
DataInspector(ax)
fig

In WGLMakie, I get the behavior shown below, where the "Not hidden!" red text appears inside the DataInspector panel.

image

In GLMakie, the red text is properly hidden, which is the behavior I want.

I'm using text! with the overdraw=true option (a "sledgehammer") because I want to add labels to the spherical markers. Is there a way to fix DataInspector so that its panel always draws on top of the entire scene? Or alternatively, is there some alternative to overdraw=true that I could be using for the red text?

EdsterG commented 1 month ago

As a workaround you can replace overdraw=true with depth_shift=-1f0.

kbarros commented 1 month ago

The workaround seems to solve the problem!

SimonDanisch commented 1 month ago

I'm going to close this then. We may actually want to deprecate overdraw altogether, since its an ancient leftover, which hasn't really been tested and pretty much just allows to set some opengl state I found useful 8 years ago to make things draw over others - without having a guarantee that it overdraws stuff and without being able to influence what exactly it overdraws ^^

ffreyer commented 1 month ago

Using depth_shift with large values like this is likely to cause issues with the text getting clipped as you move the camera. It also doesn't technically solve the problem here, because there will still be a range where text is in front of the tooltip.

I think refactoring rendering to happen scene-by-scene rather than squashing everything together would give us a way to fix this. With that we could have tooltips on an overlay scene so they are always on top, regardless of what happens in another scene.

EdsterG commented 1 month ago

Using depth_shift with large values like this is likely to cause issues with the text getting clipped as you move the camera.

Ah, wasn’t aware. For this specific scene a depth shift of -0.1f0 also does the trick. It’s a function of how large the objects are, if the objects were any larger the depth shift would also have to decease.

ffreyer commented 3 weeks ago

I'm confused as to why this doesn't happen in GLMakie. Depending on how WGLMakie and CairoMakie play with it, #4150 might end up fixing this.

kbarros commented 3 weeks ago

For this specific scene a depth shift of -0.1f0 also does the trick. It’s a function of how large the objects are, if the objects were any larger the depth shift would also have to decease.

This is a good workaround for the Perspective camera view. Is there a workaround that would also work for an Orthographic camera view?

Here's what it looks like in our code when I switch between camera types (note the missing atom labels in the second image):

image image
ffreyer commented 3 weeks ago

You could also try calculating the position where the text actually needs to be. E.g.

f, a, p = meshscatter(rand(Point3f, 10))
pos = map(p.marker, p[1], p.markersize, a.scene.camera.view_direction) do marker, trans, scale, dir
    # For default (marker = :sphere)
    dist = 1.0

    # for passed Sphere(...) just set dist to sphere radius

    # generic case (somewhat expensive, maybe good to calculate once beforehand)
    # mesh = Makie.convert_attribute(marker, Makie.key"marker"(), Makie.key"meshscatter"())
    # dist = mapreduce(p -> abs.(p), (a, b) -> max.(a, b), Makie.coordinates(mesh))

    # pos of marker + scale .* dist .* (-view_direction)
    return broadcast((t, s) -> t .+ s .* dist .* (-dir), trans, scale)
end
text!(a, pos, text = map(ps -> string.(eachindex(ps)), pos), align = (:center, :center), color = :yellow)
f

This may break in the future though, since Simon and I have been thinking about replacing camera.view_direction with camera.lookat. If that's the case you can just calculate it as normalize(lookat - eyeposition) instead.