In this section, we will showcase the cameras that are supported by AutomotiveVisualization.jl.

All cameras make use of the CameraState object to represent the internal camera state.

Missing docstring.

Missing docstring for CameraState. Check Documenter's build log for details.

The following camera types are supported by AutomotiveVisualization: StaticCamera, TargetFollowCamera, SceneFollowCamera, ZoomingCamera, ComposedCamera. The keyword arguments accepted by the CameraState object can also be passed to the constructors of these cameras, and they will be forwarded to the internal camera state. Now, we will show how the different cameras behave based on the simple stadium example.

First, we prepare a sequence of scenes visualize

using AutomotiveSimulator
using AutomotiveVisualization

nlanes = 4
nveh = 5
nticks = 100
timestep = 0.1

roadway = gen_stadium_roadway(nlanes)

scene = Scene([Entity(VehicleState(
    Frenet(roadway[LaneTag(1,rand(1:nlanes))], 10.0*i), roadway, 4.0 + 2.0rand()
), VehicleDef(), i) for i in 1:nveh])

models = Dict((
    i => LatLonSeparableDriver(ProportionalLaneTracker(), IntelligentDriverModel())
    for i in 1:nveh
set_desired_speed!.(values(models), 8.0 .+ 4.0rand(nveh))

scenes = simulate(scene, roadway, models, nticks, timestep)

The following helper function takes care of generating an animation from a sequence of scenes, using a given camera. Note that for camera=nothing, the render function attempts to fit all the renderable objects on the canvas.

using Reel

function animate(roadway, scenes, camera=nothing)
    animation = roll(fps=1.0/timestep, duration=nticks*timestep) do t, dt
        i = Int(floor(t/dt)) + 1
        update_camera!(camera, scenes[i])
        renderables = [
            roadway, scenes[i],
            IDOverlay(scene=scenes[i], x_off=-2, y_off=1),
        render(renderables, camera=camera)
    return animation

The call to update_camera!(camera, scenes[i]) is important as it allows the internal camera state to be updated based on the positions of the vehicles.

Default camera: fit to content

The default camera uses the render instructions that are stored inside the RenderModel in order to compute a bounding box which holds all renderable objects.

animation = animate(roadway, scenes);

default camera

Note that some renderable objects (such as custom objects) may not be considered by the default fit to content camera when the bounding box is computed. Therefore, they may be cut off.

Static Camera

A static camera maintains its position, zoom and rotation. It is the only camera that doesn't change its state when calling update_camera!().

animation = animate(roadway, scenes, StaticCamera(zoom=5.))

static default camera

We can pass in zoom, position and rotation parameters in order to change the camera state.

animation = animate(
    roadway, scenes,
    StaticCamera(position=VecE2(20.,10.), rotation=.2, zoom=8.)

static custom camera

Target Follow Camera

In many applications, we are interested in tracking one particular vehicle. To do this, we can use a TargetFollowCamera which follows a vehicle with a given ID. Let's follow the vehicle with ID 3:

animation = animate(roadway, scenes, TargetFollowCamera(3, zoom=5.))

target follow camera

Sometimes, it is desireable fix the x or y position of the camera. For example, we can use the TargetFollowCamera to track a vehicle horizontally (in x direction), while keeping the vertical position (y direction) fixed. To do this, we simply provide a fixed value for the corresponding keyword argument y.

animation = animate(roadway, scenes, TargetFollowCamera(3, zoom=10., y=40.))

target follow camera, fixed y

Scene Follow Camera

In contrast to the TargetFollowCamera, the SceneFollowCamera tracks the center of mass of all the vehicles in a scene. The padding parameter specifies how man metres of padding there should be around the vehicles in the scene

animation = animate(roadway, scenes, SceneFollowCamera(padding=4.))

scene follow camera

If we desire to follow the scene, but fix the zoom level, we can do so by passing in the corresponding keyword argument zoom.

animation = animate(roadway, scenes, SceneFollowCamera(zoom=20.))

scene follow camera

Zooming Camera

The zooming camera changes its zoom level by an increment dz anytime the update_camera!() function is called, until a zoom level of zoom_target is reached.

animation = animate(roadway, scenes, ZoomingCamera(zoom_target=20., dz=0.4, zoom=2.))

zooming camera

Composed Camera

Finally, the ComposedCamera can be used to combine different camera behaviors. For example, one can use the TargetFollowCamera together with the ZoomingCamera in order to follow a vehicle and zoom in on it. The constructor of the CompostedCamera takes an array of cameras which are applied in the same sequence as they are provided in the array.

animation = animate(roadway, scenes, ComposedCamera([
    ZoomingCamera(zoom_target=25., dz=0.4, zoom=1.),
write("stadium_cam_composed.gif", animation) # hide

composed camera

Custom Camera

Finally, we will show how to build a custom camera. We will build a camera whose angle is always aligned with the axis of the target vehicle with ID target_id

mutable struct TargetRotateCamera{I} <: Camera
TargetRotateCamera(target_id; kwargs...) = TargetRotateCamera(CameraState(;kwargs...), target_id)

In the update_camera!() function, we need to set the camera rotation to be the same as the vehicle yaw angle

function AutomotiveVisualization.update_camera!(camera::TargetRotateCamera{I}, scene::Scene{E}) where {I,E<:Entity}
    target = get_by_id(scene, camera.target_id)
    yaw = posg(target.state)[3]
    set_camera!(camera.state, rotation=-yaw)
    return camera.state

Finally, we can use our custom camera just like the other cameras

animation = animate(roadway, scenes, TargetRotateCamera(3, zoom=5.))

custom camera

Also, we can combine the camera with other cameras to our liking

animation = animate(roadway, scenes, ComposedCamera([
    ZoomingCamera(zoom_target=25., dz=0.4, zoom=1.),
write("stadium_cam_composed_custom.gif", animation) # hide

composed camera

This page was generated using Literate.jl.