Makie.jl
Makie.jl copied to clipboard
Add clipping options to GLMakie
Description
This adds the option to specify a world space clipping box which excludes anything outside it from rendering.
f, a, p = mesh(
Sphere(Point3f(0), 1.2f0), color = :yellow,
clip_planes = Rect3f(Vec3f(-1), Vec3f(2))
)
Currently this is a per-plot attribute that defaults to what the scene defines. Can be nothing
, a Rect3
or WorldAxisLimits
.
Working so far
- [x] mesh
- [x] meshscatter
- [x] scatter, text
- [x] volume
- [x] surface
- [x] heatmap, image
- [x] lines, linesegments
lines, linesegements, scatter and text may need to work differently since they transform to along the way.
Type of change
- [x] New feature (non-breaking change which adds functionality)
Checklist
- [ ] Added an entry in NEWS.md (for new features and breaking changes)
- [ ] Added or changed relevant sections in the documentation
- [ ] 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(display(fig))
using | create | display | create | display | |
---|---|---|---|---|---|
GLMakie | 51.93s (51.20, 53.89) 0.95+- | 23.61s (23.00, 24.38) 0.49+- | 22.06s (21.24, 23.05) 0.67+- | 17.71ms (17.25, 18.15) 0.32+- | 197.88ms (194.11, 208.37) 4.99+- |
master | 52.07s (51.23, 53.91) 0.88+- | 23.56s (23.15, 24.10) 0.34+- | 21.77s (21.30, 22.32) 0.39+- | 17.59ms (17.45, 17.72) 0.11+- | 195.59ms (187.37, 203.53) 5.03+- |
evaluation | -0.27%, -0.14s invariant (-0.15d, 0.78p, 0.91std) | +0.22%, 0.05s invariant (0.12d, 0.82p, 0.42std) | +1.30%, 0.29s invariant (0.52d, 0.36p, 0.53std) | +0.72%, 0.13ms invariant (0.53d, 0.35p, 0.22std) | +1.16%, 2.29ms invariant (0.46d, 0.41p, 5.01std) |
CairoMakie | 35.38s (35.17, 35.63) 0.18+- | 17.56s (17.23, 18.11) 0.30+- | 2.56s (2.51, 2.68) 0.06+- | 11.47ms (11.24, 11.65) 0.17+- | 5.57ms (5.33, 5.92) 0.23+- |
master | 35.27s (35.13, 35.45) 0.13+- | 17.49s (17.35, 17.77) 0.16+- | 2.57s (2.52, 2.71) 0.07+- | 11.41ms (11.11, 11.93) 0.26+- | 5.81ms (5.55, 6.16) 0.19+- |
evaluation | +0.29%, 0.1s invariant (0.65d, 0.25p, 0.16std) | +0.38%, 0.07s invariant (0.27d, 0.62p, 0.23std) | -0.47%, -0.01s invariant (-0.20d, 0.72p, 0.06std) | +0.49%, 0.06ms invariant (0.26d, 0.64p, 0.21std) | -4.22%, -0.23ms invariant (-1.12d, 0.06p, 0.21std) |
WGLMakie | 43.50s (43.26, 43.92) 0.24+- | 21.52s (21.20, 21.69) 0.19+- | 21.77s (21.41, 22.28) 0.30+- | 13.66ms (13.25, 14.08) 0.35+- | 769.96ms (729.65, 830.57) 37.01+- |
master | 43.70s (43.49, 44.13) 0.23+- | 21.64s (21.43, 21.96) 0.18+- | 21.85s (21.43, 22.45) 0.34+- | 13.71ms (13.06, 14.08) 0.41+- | 751.34ms (731.07, 771.44) 14.11+- |
evaluation | -0.47%, -0.2s invariant (-0.87d, 0.13p, 0.23std) | -0.55%, -0.12s invariant (-0.65d, 0.25p, 0.18std) | -0.36%, -0.08s invariant (-0.25d, 0.65p, 0.32std) | -0.33%, -0.05ms invariant (-0.12d, 0.83p, 0.38std) | +2.42%, 18.62ms invariant (0.66d, 0.25p, 25.56std) |
I tried two options for lines - one uploading two buffers, one with world space positions and one with screen space positions; and one that only uploads world space positions, i.e. lets the screen space positions calculated for last_len go to waste. In the end they both perform about equal for me, but the latter saves some memory which I assume is valuable for some. It's also a bit less code, so that's what I went with.
https://stackoverflow.com/questions/22628186/glclipplane-is-there-an-equivalent-in-webgl I guess for WGLMakie we could use the three.js implementation for clipping planes?
we also need polygons for clipping, for example for nonlinear axes. is that something that would fit the scope of this pr or not at all?
Short summary of how this works:
Each vertex has a ClipDistance
which can hold some number of float distances. These values each get interpolated when going to the fragment shader, and if any of them fall below 0 the fragment will be discarded. For a plane you can get inside vs outside by doing something like distance = plane_distance_from_zero - dot(plane_normal, position)
.
If you have a complex polygon or mesh to check against you'll need lots of clip planes, and you can only pass so many ClipDistance
s. (Minimum 8) So you'll probably run into issues quickly like this. A circle would be very easy to do though, since that's just one distance.
If the clipping shapes are 2D you can also go through stencil buffers. Conceptually it shouldn't be too difficult to render an arbitrary poylgon to the stencil buffer and then use that as a mask for clipping. In practice our renderloop needs to be more adjustable for this, I think.
If the clipping shapes are 2D you can also go through stencil buffers. Conceptually it shouldn't be too difficult to render an arbitrary poylgon to the stencil buffer and then use that as a mask for clipping. In practice our renderloop needs to be more adjustable for this, I think.
Yes this would have to be the mechanism for weird axis shapes, I think.
Closing this in favor of #3958