Skip to content

Live rendering ​

render! generates new plots on every call. For animations and interactive applications, where components are moved and the system is re-solved many times per second, use live_render! instead. It returns a handle that re-synchronizes the existing plots with the current simulation state via update_render!:

julia
using GLMakie, BeamletOptics

fig = Figure()
ax = LScene(fig[1, 1])

hsys = live_render!(ax, system)   # geometry is generated once
hbeam = live_render!(ax, beam)    # all ray segments bundled into a single plot

zrotate3d!(mirror, 1e-3)
solve_system!(system, beam)
update_render!(hsys)              # moved components: only their model transformation changes
update_render!(hbeam)             # beam path: point buffer is replaced in place
BeamletOptics.live_render! Method
julia
live_render!(axis, thing; kwargs...)

Renders thing into the axis like render!, but returns an AbstractRenderHandle that can be updated in place via update_render!. Intended for animations and interactive applications, e.g. moving components that require the system to be solved repeatedly.

  • objects and systems: the geometry is generated once, kinematic changes are applied as a model transformation of the existing plots

  • rays, beams and beam groups: all segments are bundled into a single plot

  • GaussianBeamlet, AstigmaticGaussianBeamlet and AstigmaticBeamGroup: the envelope of all segments is bundled into a single mesh

Keyword arguments are passed on as for render!, but the envelope meshes of Gaussian beamlets are drawn with coarser default resolutions r_res/z_res: 24/40 for a GaussianBeamlet (render!: 50/100) and 10/8 per beamlet of an AstigmaticBeamGroup (render!: 64/100). Change them via the keywords or later via render_settings!.

If no suitable backend is loaded, a MissingBackendError will be thrown.

source
BeamletOptics.update_render! Method
julia
update_render!(handle)

Re-synchronizes the plots of the handle with the current state of the rendered object or beam, e.g. after moving components or calling solve_system!. Keep render handles on root beams and groups: child beams and all rays after the first are new objects after every solve.

If no suitable backend is loaded, a MissingBackendError will be thrown.

source
BeamletOptics.remove_render! Method
julia
remove_render!(handle)

Deletes all plots of the handle from its axis.

If no suitable backend is loaded, a MissingBackendError will be thrown.

source

live_render! draws the same plots as render!, see Rays and beams and Gaussian beamlets; it only keeps the data they are drawn from. The envelope meshes of Gaussian beamlets use coarser default resolutions r_res and z_res than render! (24/40 instead of 50/100 for a GaussianBeamlet, 10/8 instead of 64/100 per beamlet of an AstigmaticBeamGroup). Change them via the keywords or with BeamletOptics.render_settings!.

Which live_render! method draws a thing, which handle it returns and how update_render! refreshes it are described in Live rendering dispatch and Updating a handle.

Changing a live scene ​

An object that is added to a system at runtime, see Changing a system, is rendered into the handle of the system, and removed from it again, by:

BeamletOptics.live_render! Method
julia
live_render!(h::AbstractSystemRenderHandle, obj; kwargs...) -> Vector{<:AbstractObjectRenderHandle}

Live-renders obj, an object or object group, into the axis of the system handle h and adds it to h, e.g. an object that was added to the system via push!(system, obj) after h was created. An object group is rendered per object, with its hierarchy known to render_parent, like the groups of live_render!(ax, system). Returns the new object handles, one per rendered object. The system of h is not changed. An obj that h already renders throws an ArgumentError.

Keyword arguments are passed on as for render!. Implemented by the handle returned by live_render!(ax, system). A system handle that does not implement it throws an ArgumentError: render obj via live_render!(ax, obj) and add its handle via push!(h, oh) instead.

source
BeamletOptics.remove_render! Method

Removes obj, an object or object group, from the system handle h: deletes the plots of obj (of all objects of an object group) from the axis and removes their object handles from h, e.g. after delete!(system, obj). The system of h is not changed. Nothing happens for an obj that h does not render. An object within a group can not be removed on its own and throws an ArgumentError: remove the group instead.

source
julia
push!(system, lens)
live_render!(hsys, lens)     # draws the lens, hsys now updates and picks it
delete!(system, lens)
remove_render!(hsys, lens)   # deletes its plots and its handle

Beam handles report how they were drawn, and can change it at runtime, e.g. the drawn length of the final rays or the color (a single color or the color of the wavelength of each ray), without creating new plots:

BeamletOptics.render_settings Function

The settings with which the beam handle h draws its beam, at least flen (length of a final ray without intersection [m]) and render_every (every how many beams of a beam group are drawn, 1 for other beams), e.g. to find the drawn segments of a beam, and color (the color of the rays or of the envelope as it was given, e.g. :blue or :wavelength). The handles of Gaussian beamlets and of beam groups of beamlets also report the resolution of the envelope, r_res and z_res. Change them via render_settings!.

source
BeamletOptics.render_settings! Function
julia
render_settings!(h::AbstractBeamRenderHandle; kwargs...) -> h

Changes the settings of the beam handle h and draws the beam again with them, without creating new plots: the plots of render_plots(h) stay in the axis, with their other attributes (visibility, opacity, line width, clip planes, ...) unchanged. The keywords are among the keys of render_settings(h):

  • flen: length of a final ray without intersection [m], positive and finite

  • render_every: every how many beams of a beam group are drawn, a positive integer (no effect on other beams)

  • r_res, z_res: radial and longitudinal resolution of an envelope mesh, integers of at least 2

  • color: the color of the rays or of the envelope, a single color that Makie knows (e.g. :red, (:red, 0.3)), or :wavelength or (:wavelength, alpha) for the color of the wavelength of each ray, see wavelength_color

Any other keyword, e.g. r_res for a ray, throws an ArgumentError, and then h is not changed. The beam is drawn as it is, i.e. nothing is solved, like update_render!. The overlays of the handle, e.g. show_beams or show_pos, follow the settings; the generating rays of show_beams and the polarization curve keep their colors.

The plots of a handle that draw the color hold one color per vertex, which the handle sets together with the positions. Change the color via render_settings!, not via the color attribute of the plots, which the next update overwrites. A color that is neither a single color nor the wavelength, e.g. a vector of colors, is passed on to Makie by live_render! and can not be changed here.

julia
h = live_render!(ax, beam; flen = 0.1)
render_settings!(h; flen = 0.5)             # the final ray is now 0.5 m long
render_settings!(h; color = :wavelength)    # each ray in the color of its wavelength
render_settings!(h; color = :orange)        # and all in one color again

If no suitable backend is loaded, a MissingBackendError will be thrown.

source

Overlays that are not part of a component, e.g. markers, are drawn with the function form of live_render!, which returns a handle for the plots draw creates and moves them together with x:

BeamletOptics.live_render! Method
julia
live_render!(draw, axis, x) -> AbstractObjectRenderHandle

Live-renders x via the function draw: draw() plots x in its current pose into the axis, and the returned handle moves these plots with x like those of an object, see live_render!, e.g. a marker of a thing that render! does not draw. x has a position and an orientation (or a direction), e.g. a source or an own movable type (see kinematic_trait_of):

julia
h = live_render!(ax, src) do
    scatter!(ax, [Point3f(position(src))]; color = :orange)
end

If no suitable backend is loaded, a MissingBackendError will be thrown.

source

The object that owns a picked plot is found by pick_object:

BeamletOptics.pick_object Method
julia
pick_object(handle, plot)

Returns the object of a live-rendered object or system handle that is visualized by the plot (one of its pickable_plots, or a child plot of one), or nothing if the plot does not belong to the handle. For a system handle, the top-level object, i.e. the outermost group of the picked object, see render_parent. Beams cannot be picked, a beam handle returns nothing.

If no suitable backend is loaded, a MissingBackendError will be thrown.

source

Packages built on BeamletOptics access the handles through the Render handle protocol.