Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera3D Improvements #2746

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
066f0b7
switch back to translation zoom, cleanup/reorganize
ffreyer Mar 12, 2023
e4b056a
fix typo
ffreyer Mar 12, 2023
6cbca9e
add example
ffreyer Mar 12, 2023
b54c0ae
remove enable translation/rotation/zoom
ffreyer Mar 12, 2023
3e07289
update test values
ffreyer Mar 12, 2023
11313dc
cleanup docstring
ffreyer Mar 12, 2023
4de5fa3
switch back rotation order to avoid change in upvector
ffreyer Mar 12, 2023
ae7f89a
fix docstring [skip ci]
ffreyer Mar 12, 2023
d31d905
update docs
ffreyer Mar 12, 2023
8185a96
update tests
ffreyer Mar 13, 2023
3c22c47
fix zoom and switch back to more extreme near/far
ffreyer Mar 15, 2023
6786f96
tweak default zoom some more
ffreyer Mar 15, 2023
5274295
Add update_cam! with angles
ffreyer Mar 16, 2023
4fee98b
Merge branch 'master' into ff/camera
ffreyer Mar 19, 2023
c890d34
update NEWS
ffreyer Mar 19, 2023
d6639fc
bring back perspective zoom_shift_lookat
ffreyer Mar 19, 2023
becc8cd
add center in orbital update_cam!
ffreyer Mar 19, 2023
f264360
bring back fov controls
ffreyer Mar 19, 2023
87e7254
deprecate old_cam [skip ci]
ffreyer Mar 19, 2023
6594406
fix whitespace?
ffreyer Mar 28, 2023
ed48aa6
Merge branch 'master' into ff/camera
ffreyer Mar 28, 2023
43e6428
cleanup news
ffreyer Mar 28, 2023
a72abbd
Merge branch 'master' into ff/camera
SimonDanisch Apr 19, 2023
78ee1e5
improve default controls/hotkeys
ffreyer Apr 19, 2023
a7e819b
add on-click refocus of camera
ffreyer Apr 21, 2023
d51ed11
DataInspector fixes
ffreyer Apr 23, 2023
fdc3666
fix wrong tooltip in volumeslices
ffreyer Apr 23, 2023
6945b97
fix line indicator in band
ffreyer Apr 23, 2023
1053b3a
update NEWS
ffreyer Apr 23, 2023
10aff36
update docs
ffreyer Apr 23, 2023
6972303
Merge branch 'master' into ff/camera
SimonDanisch Apr 25, 2023
64f7730
consider transforms when centering on plot object
ffreyer May 5, 2023
fd9a04d
Merge branch 'master' into ff/camera
ffreyer Jun 12, 2023
fc4fcd5
fix type error in cam2d!
ffreyer Jun 12, 2023
a26e6a1
check other ray_at_cursor methods
ffreyer Jun 12, 2023
381eb82
Merge branch 'master' into ff/camera
ffreyer Jun 22, 2023
d89aac0
Merge branch 'master' into ff/camera
ffreyer Jul 4, 2023
001542e
avoid centering on unrelated plots
ffreyer Jul 4, 2023
34e9072
Merge branch 'master' into ff/camera
ffreyer Jul 4, 2023
98c1096
fix test errors
ffreyer Jul 4, 2023
01b1589
Merge branch 'master' into ff/camera
ffreyer Jul 12, 2023
12bcc1c
Merge branch 'master' into ff/camera
SimonDanisch Aug 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions GLMakie/test/glmakie_refimages.jl
Expand Up @@ -65,6 +65,7 @@ end
markersize=size,
axis = (; scenekw = (;limits=Rect3f(Point3(0), Point3(1))))
)
update_cam!(ax.scene, Point3f(2.224431, 2.224431, 2.128731), Point3f(0.5957, 0.5957, 0.50000006))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hard coded the camera setup here (and below) to avoid test errors. I don't know if we want to keep this or update refimgs so I'm pointing it out. The difference is tiny.

Record(fig, [10, 5, 100, 60, 177]) do i
makenew[] = i
end
Expand All @@ -82,6 +83,7 @@ end
end
end
fig, ax, meshplot = meshscatter(RNG.rand(Point3f, 10^4) .* 20f0)
update_cam!(ax.scene, Point3f(45.383663, 45.38298, 43.136826), Point3f(12.246061, 12.245379, 9.999225))
screen = display(GLMakie.Screen(;renderloop=(screen) -> nothing, start_renderloop=false), fig.scene)
buff = RNG.rand(Point3f, 10^4) .* 20f0;
update_loop(meshplot, buff, screen)
Expand Down
2 changes: 1 addition & 1 deletion NEWS.md
Expand Up @@ -2,14 +2,14 @@

## master

- Improved 3D camera handling, hotkeys and functionality [#2746](https://github.com/MakieOrg/Makie.jl/pull/2746)
- Fixed DataInspector interaction with transformations [#3002](https://github.com/MakieOrg/Makie.jl/pull/3002)
- Fix incomplete stroke with some Bezier markers in CairoMakie and blurry strokes in GLMakie [#2961](https://github.com/MakieOrg/Makie.jl/pull/2961)
- Added the ability to use custom triangulations from DelaunayTriangulation.jl [#2896](https://github.com/MakieOrg/Makie.jl/pull/2896).
- Adjusted scaling of scatter/text stroke, glow and anti-aliasing width under non-uniform 2D scaling (Vec2f markersize/fontsize) in GLMakie [#2950](https://github.com/MakieOrg/Makie.jl/pull/2950).
- Scaled `errorbar` whiskers and `bracket` correctly with transformations [#3012](https://github.com/MakieOrg/Makie.jl/pull/3012).
- Updated `bracket` when the screen is resized or transformations change [#3012](https://github.com/MakieOrg/Makie.jl/pull/3012).


## v0.19.6

- Fixed broken AA for lines with strongly varying linewidth [#2953](https://github.com/MakieOrg/Makie.jl/pull/2953).
Expand Down
16 changes: 4 additions & 12 deletions ReferenceTests/src/tests/examples3d.jl
Expand Up @@ -29,19 +29,11 @@ end
meshes = map(colormesh, rectangles)
fig, ax, meshplot = mesh(merge(meshes))
scene = ax.scene
center!(scene)
cam = cameracontrols(scene)
dir = widths(data_limits(scene)) ./ 2.
dir_scaled = Vec3f(
dir[1] * scene.transformation.scale[][1],
0.0,
dir[3] * scene.transformation.scale[][2],
)
cam.settings[:projectiontype][] = Makie.Orthographic
cam.upvector[] = (0.0, 0.0, 1.0)
cam.lookat[] = minimum(data_limits(scene)) + dir_scaled
cam.eyeposition[] = (cam.lookat[][1], cam.lookat[][2] + 6.3, cam.lookat[][3])
cam.attributes[:projectiontype][] = Makie.Orthographic
cam.zoom_mult[] = 0.61f0
cam.lookat[] = Vec3f(0.595, 2.5, 0.5)
cam.eyeposition[] = (cam.lookat[][1], cam.lookat[][2] + 0.61, cam.lookat[][3])
update_cam!(scene, cam)
fig
end
Expand Down Expand Up @@ -566,7 +558,7 @@ end
end
end
cam = cameracontrols(ax.scene)
cam.attributes.fov[] = 22f0
cam.fov[] = 22f0
update_cam!(ax.scene, cam, Vec3f(0.625, 0, 3.5), Vec3f(0.625, 0, 0), Vec3f(0, 1, 0))
fig
end
Expand Down
69 changes: 65 additions & 4 deletions docs/documentation/cameras.md
@@ -1,20 +1,26 @@
# Cameras

A `Camera` is simply a viewport through which the Scene is visualized. `Makie` offers 2D and 3D projections, and 2D plots can be projected in 3D!
A `Camera` is simply a viewport through which the Scene is visualized. `Makie` offers 2D and 3D projections, and 2D plots can be projected in 3D!

To specify the camera you want to use for your Scene, you can set the `camera` attribute. Currently, we offer four types of camera:
To specify the camera you want to use for your Scene, you can set the `camera` attribute. Currently, we offer the following cameras/constructors

\apilink{campixel!}
\apilink{cam_relative!}
\apilink{cam2d!}
`cam3d!`
`cam3d_cad!`
\apilink{Camera3D}
\apilink{cam3d!}
\apilink{cam3d_cad!}

which will mutate the camera of the Scene into the specified type.

## Pixel Camera

The pixel camera (\apilink{campixel!(scene)}) projects the scene in pixel space, i.e. each integer step in the displayed data will correspond to one pixel. There are no controls for this camera. The clipping limits are set to `(-10_000, 10_000)`.

## Relative Camera

The relative camera (\apilink{cam_relative!(scene)}) projects the scene into a 0..1 by 0..1 space. There are no controls for this camera. The clipping limits are set to `(-10_000, 10_000)`.

## 2D Camera

The 2D camera (\apilink{cam2d!(scene)}) uses an orthographic projection with a fixed rotation and aspect ratio. You can set the following attributes via keyword arguments in `cam2d!` or by accessing the camera struct `cam = cameracontrols(scene)`:
Expand All @@ -30,6 +36,61 @@ Note that this camera is not used by `Axis`. It is used, by default, for 2D `LSc

{{doc Camera3D}}

`cam3d!` and `cam3d_cad!` but create a `Camera3D` with some specific options.

## Example - Visualizing the cameras view box

```julia
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, far = 3.0)

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
```

## General Remarks

To force a plot to be visualized in 3D, you can set the limits to have a nonzero \(z\)-axis interval, or ensure that a 3D camera type is used.
Expand Down
2 changes: 2 additions & 0 deletions docs/documentation/events.md
Expand Up @@ -376,6 +376,8 @@ Furthermore you can wrap any of the above in `Exclusively` to discard matches wh
- `hotkey = Keyboard.left_control & Keyboard.a` is equivalent to `(Keyboard.left_control, Keyboard.a)`
- `hotkey = (Keyboard.left_control | Keyboard.right_control) & Keyboard.a` allows either left or right control with a.

Note that the way we used `ispressed` above, the condition will be true for "press" and "repeat" events. You can further restrict to one or the other by checking `event.action`. If you wish to react to a "release" event, you will need to pass `event.key`/`event.button` as a third argument to `ispressed(fig, hotkey, event.key)`. This will tell `ispressed` to assume the key or button is pressed if it is part of the hotkey.

## Interactive Widgets

Makie has a couple of useful interactive widgets like sliders, buttons and menus, which you can learn about in the \myreflink{Blocks} section.
Expand Down
24 changes: 18 additions & 6 deletions src/camera/camera2d.jl
@@ -1,8 +1,8 @@
struct Camera2D <: AbstractCamera
area::Observable{Rect2f}
zoomspeed::Observable{Float32}
zoombutton::Observable{ButtonTypes}
panbutton::Observable{Union{ButtonTypes, Vector{ButtonTypes}}}
zoombutton::Observable{IsPressedInputType}
panbutton::Observable{IsPressedInputType}
padding::Observable{Float32}
last_area::Observable{Vec{2, Int}}
update_limits::Observable{Bool}
Expand All @@ -11,14 +11,23 @@ end
"""
cam2d!(scene::SceneLike, kwargs...)

Creates a 2D camera for the given Scene.
Creates a 2D camera for the given `scene`. The camera implements zooming by
scrolling and translation using mouse drag. It also implements rectangle
selections.

## Keyword Arguments

- `zoomspeed = 0.1f0` sets the zoom speed.
- `zoombutton = true` sets a button (combination) which needs to be pressed to enable zooming. By default no button needs to be pressed.
- `panbutton = Mouse.right` sets the button used to translate the camera. This must include a mouse button.
- `selectionbutton = (Keyboard.space, Mouse.left)` sets the button used for rectangle selection. This must include a mouse button.
"""
function cam2d!(scene::SceneLike; kw_args...)
cam_attributes = merged_get!(:cam2d, scene, Attributes(kw_args)) do
Attributes(
area = Observable(Rectf(0, 0, 1, 1)),
zoomspeed = 0.10f0,
zoombutton = nothing,
zoombutton = true,
panbutton = Mouse.right,
selectionbutton = (Keyboard.space, Mouse.left),
padding = 0.001,
Expand Down Expand Up @@ -318,7 +327,9 @@ end
"""
campixel!(scene; nearclip=-1000f0, farclip=1000f0)

Creates a pixel-level camera for the `Scene`. No controls!
Creates a pixel camera for the given `scene`. This means that the positional
data of a plot will be interpreted in pixel units. This camera does not feature
controls.
"""
function campixel!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0)
disconnect!(camera(scene))
Expand All @@ -338,7 +349,8 @@ struct RelativeCamera <: AbstractCamera end
"""
cam_relative!(scene)

Creates a pixel-level camera for the `Scene`. No controls!
Creates a camera for the given `scene` which maps the scene area to a 0..1 by
0..1 range. This camera does not feature controls.
"""
function cam_relative!(scene::Scene; nearclip=-10_000f0, farclip=10_000f0)
projection = orthographicprojection(0f0, 1f0, 0f0, 1f0, nearclip, farclip)
Expand Down