Makie.jl
Makie.jl copied to clipboard
Standardize view and projection matrices
Description
This prepares some things for #3226:
- move translations from projection to view matrices
- track eyeposition in Axis and PolarAxis
- rework Axis3 to use
perspectiveprojection
andlookat
without modification (though I split uplookat
into two steps) - add inv(::Quaternion)
And some random minor cleanup of Axis3 docs (indention, wrong render order in W/GLMakie, double-plotting of Label) + camera controller (name change).
Axis3 comparsion
Axis3 has more extensive changes so things could be different. Here are some new vs old comparisons with docs:
Aspect
Viewing angles
Tick placement seems to be slightly different (e.g. bottom left z is cut off more, top left z's overlap more(?))
Slightly less space to the title here as well
Perspectiveness
viewmodes
Also checked this with perspectiveness = 0.6
, no visible changes.
Tight frustum testing/debugging
This will show you the generated frustum (i.e. what area of the scene will be rendered) with th view space bounding box (+ bounding sphere for :fit) of the Axis3.
using GeometryBasics
function camera_debug(gridpos, ax::Axis3)
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
scene = ax.scene
cam = scene.camera
frustum = map(pv -> frustum_snapshot(cam), cam.projectionview)
scene2 = LScene(gridpos, show_axis = false)
_cc = Makie.Camera3D(
scene2.scene, projectiontype = Makie.Orthographic,
near = 0.001f0, far = 1000.0f0, clipping_mode = :static
)
lines!(scene2, frustum, color = :blue, linestyle = :dot)
# bbox is Axis3 specific
bbox = ax.finallimits
model = ax.scene.transformation.model
bb = map(model, bbox) do model, bb
ps = [(model * to_ndim(Point4f, p, 1))[Vec(1,2,3)] for p in Makie.corners(bb)]
Rect3f(ps)
end
r = map(bb -> maximum(norm.(Makie.corners(bb))), bb)
linesegments!(scene2, bb, color = :black)
wireframe!(scene2, map(r -> Sphere(Point3f(0), r), r), color = (:black, 0.2), transparency = true)
# scatter!(scene2, scene.camera.eyeposition, color = :red)
scatter!(scene2, Point3f(0), color = :blue)
r = map(frustum) do frustum
ps = vcat(frustum[1:12], frustum[14:end])
normal_mesh(ps, faces(Rect3f()))
end
mesh!(scene2, r, color = (:red, 0.3), fxaa = false, transparency = true)
notify(frustum)
return scene2
end
begin
fig = Figure()
# show the extent of each cell using a box
b = Box(fig[1, 1], strokewidth = 0, color = :gray95)
translate!(b.blockscene, Vec3f(0, 0, -10_000))
ax = Axis3(
fig[1, 1]; viewmode = :stretch, protrusions = 0,
aspect = (1,2,3), perspectiveness = 0.5
)
hidedecorations!(ax)
camera_debug(fig[1, 2], ax)
fig
end
Type of change
- [x] internal adjustments
Checklist
- ~~Added an entry in NEWS.md (for new features and breaking changes)~~
- ~~Added or changed relevant sections in the documentation~~
- [x] Added unit tests for new algorithms, conversion methods, etc.
- ~~Added reference image tests for new plotting functions, recipes, visual options, etc.~~
Compile Times benchmark
Note, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. All benchmark results are based on the mean time and negative percent mean faster than the base branch. Note, that GLMakie + WGLMakie run on an emulated GPU, so the runtime benchmark is much slower. Results are from running:
using_time = @ctime using Backend
# Compile time
create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @ctime Makie.colorbuffer(display(fig))
# Runtime
create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @benchmark Makie.colorbuffer(fig)
using | create | display | create | display | |
---|---|---|---|---|---|
GLMakie | 4.80s (4.64, 4.93) 0.11+- | 123.59ms (111.69, 135.03) 8.96+- | 598.81ms (573.31, 610.29) 12.89+- | 9.64ms (9.36, 9.92) 0.24+- | 26.95ms (26.67, 27.12) 0.17+- |
master | 4.77s (4.60, 4.92) 0.10+- | 123.63ms (117.24, 139.49) 7.63+- | 572.82ms (515.75, 623.94) 41.33+- | 9.52ms (8.96, 9.91) 0.32+- | 26.92ms (26.75, 27.10) 0.15+- |
evaluation | 0.99x invariant, 0.03s (0.26d, 0.63p, 0.11std) | 1.00x invariant, -0.04ms (-0.00d, 0.99p, 8.30std) | 0.96x invariant, 25.99ms (0.85d, 0.16p, 27.11std) | 0.99x invariant, 0.12ms (0.44d, 0.43p, 0.28std) | 1.00x invariant, 0.02ms (0.15d, 0.79p, 0.16std) |
CairoMakie | 4.05s (3.95, 4.13) 0.06+- | 108.37ms (104.67, 112.88) 2.80+- | 130.40ms (126.27, 136.61) 3.29+- | 9.02ms (8.45, 9.49) 0.40+- | 987.26μs (970.70, 1006.71) 14.84+- |
master | 3.77s (3.71, 3.85) 0.06+- | 108.67ms (105.03, 114.86) 3.23+- | 132.19ms (129.67, 134.84) 2.13+- | 8.48ms (8.32, 8.73) 0.16+- | 984.89μs (975.54, 994.36) 5.85+- |
evaluation | 0.93x slower❌, 0.27s (4.38d, 0.00p, 0.06std) | 1.00x invariant, -0.31ms (-0.10d, 0.85p, 3.02std) | 1.01x invariant, -1.79ms (-0.65d, 0.25p, 2.71std) | 0.94x slower❌, 0.53ms (1.73d, 0.01p, 0.28std) | 1.00x invariant, 2.37μs (0.21d, 0.70p, 10.35std) |
WGLMakie | 4.72s (4.61, 4.88) 0.09+- | 114.13ms (105.30, 122.54) 6.99+- | 9.60s (9.16, 10.03) 0.31+- | 9.95ms (9.77, 10.19) 0.17+- | 71.99ms (71.41, 73.02) 0.56+- |
master | 4.68s (4.59, 4.74) 0.05+- | 115.60ms (107.27, 124.09) 5.99+- | 9.50s (9.28, 9.65) 0.15+- | 10.18ms (9.43, 10.78) 0.41+- | 74.29ms (70.91, 91.31) 7.52+- |
evaluation | 0.99x invariant, 0.03s (0.45d, 0.42p, 0.07std) | 1.01x invariant, -1.48ms (-0.23d, 0.68p, 6.49std) | 0.99x invariant, 0.1s (0.39d, 0.48p, 0.23std) | 1.02x invariant, -0.23ms (-0.73d, 0.21p, 0.29std) | 1.03x invariant, -2.29ms (-0.43d, 0.45p, 4.04std) |
space 3D
failing is expected because the near and far planes are now tight to the finallimits
in Axis3. This should also change OIT there, but I don't think we explicitly test that.
Failures in CairoMakie are one-pixel offsets of tick labels in Axis3. GLMakie and WGLMakie are the expected space 3D
Were these changes merged in 0.21?
No they weren't.
This came from a thought that we'd implement Float32 scaling based on the model, view and projection matrix, i.e. independently of limits which aren't known by the backend. A consistent structure for those matrices would have been useful for that.
Now this is less important but maybe still useful as a clean up. I.e. maybe it's easier to follow what Axis3 does camera wise after this. It might also be the case that some lighting calculation or SSAO makes some assumptions about camera matrices that aren't true without this (i.e. transpose = inv).
space 3D
failing is expected because the near and far planes are now tight to thefinallimits
in Axis3. This should also change OIT there, but I don't think we explicitly test that.
Still true