screen_line: Screen-space Lines

View source: R/screen_line.R

screen_lineR Documentation

Screen-space Lines

Description

Creates line annotations for 'render_scene()' that are anchored to 3D world-space endpoints but drawn in 2D screen space after rendering.

Usage

screen_line(
  x = 0,
  y = 0,
  z = 0,
  xend = 0,
  yend = 0,
  zend = 0,
  start = NULL,
  end = NULL,
  offset = c(0, 0),
  end_offset = offset,
  width = 2,
  color = "black",
  alpha = 1,
  lineend = "round",
  clip = TRUE,
  occlusion = FALSE,
  occlusion_mode = "anchor",
  occlusion_tolerance = 0.001
)

Arguments

x, y, z

Default '0'. World-space coordinates of the line start point.

xend, yend, zend

Default '0'. World-space coordinates of the line end point.

start, end

Default 'NULL'. Optional 3-column matrix/data frame of world-space start and end points. If supplied, overrides 'x', 'y', 'z' and 'xend', 'yend', 'zend'.

offset

Default 'c(0,0)'. Pixel offset for the start point, as 'c(x,y)', with positive y moving down the image.

end_offset

Default 'offset'. Pixel offset for the end point.

width

Default '2'. Line width in pixels.

color

Default '"black"'. Line color.

alpha

Default '1'. Line alpha.

lineend

Default '"round"'. Line end style. Options are '"round"', '"butt"', and '"square"'.

clip

Default 'TRUE'. If 'TRUE', lines whose endpoints are both behind the camera are skipped.

occlusion

Default 'FALSE'. If 'TRUE', use scene geometry to hide the line.

occlusion_mode

Default '"anchor"'. If '"anchor"', occlusion skips the entire line when its midpoint is blocked. If '"line"' or '"partial"', each line pixel is hidden only when the scene depth at that pixel is closer than the interpolated screen-space line depth.

occlusion_tolerance

Default '0.001'. Endpoint tolerance for occlusion.

Value

A data frame describing screen-space line annotations.

Examples


# Build the scene first, then add independent screen-space line layers.
scene = generate_cornell(lightwidth = 250, lightdepth = 250) |>
  add_object(sphere(
    x = 180, y = 90, z = 260, radius = 90,
    material = diffuse(color = "#f2c14e")
  )) |>
  add_object(cube(
    x = 385, y = 90, z = 330, xwidth = 120, ywidth = 180, zwidth = 120,
    angle = c(0, 25, 0), material = diffuse(color = "#243846")
  ))

# A round-ended measurement across the sphere uses matrix start/end points.
sphere_measure = screen_line(
  start = matrix(c(90, 6, 260), ncol = 3),
  end = matrix(c(270, 6, 260), ncol = 3),
  offset = c(0, 0),
  end_offset = c(0, 0),
  width = 5,
  color = "#f2c14e",
  alpha = 1,
  lineend = "round",
  clip = TRUE,
  occlusion = FALSE,
  occlusion_mode = "anchor",
  occlusion_tolerance = 0.001
)

# A vertical guide on the rotated box exercises line-level occlusion.
box_measure = screen_line(
  start = matrix(c(385, 0, 330), ncol = 3),
  end = matrix(c(385, 180, 330), ncol = 3),
  offset = c(-12, 0),
  end_offset = c(-12, 0),
  width = 7,
  color = "#4d9de0",
  alpha = 0.8,
  lineend = "butt",
  clip = TRUE,
  occlusion = TRUE,
  occlusion_mode = "line",
  occlusion_tolerance = 0.004
)

# A back-wall rule uses square caps, no clipping, and the "partial" alias.
wall_rule = screen_line(
  start = matrix(c(85, 18, 545), ncol = 3),
  end = matrix(c(505, 18, 545), ncol = 3),
  offset = c(0, -8),
  end_offset = c(0, -8),
  width = 4,
  color = "white",
  alpha = 0.6,
  lineend = "square",
  clip = FALSE,
  occlusion = TRUE,
  occlusion_mode = "partial",
  occlusion_tolerance = 0.01
)

# Scalar coordinates work too, which is handy for one-off callout lines.
callout_line = screen_line(
  x = 180, y = 190, z = 260,
  xend = 245, yend = 255, zend = 230,
  offset = c(0, -4),
  end_offset = c(30, -24),
  width = 3,
  color = "black",
  alpha = 0.9,
  lineend = "round",
  clip = TRUE,
  occlusion = TRUE,
  occlusion_mode = "anchor",
  occlusion_tolerance = 0.002
)

# Build a 3D spiral from many short screen-space line segments.
spiral_theta = seq(0, 5 * pi, length.out = 120)
spiral_radius = seq(6, 65, length.out = length(spiral_theta))
spiral_points = cbind(
  445 + spiral_radius * cos(spiral_theta),
  390 + spiral_radius * sin(spiral_theta),
  seq(245, 390, length.out = length(spiral_theta))
)
spiral_count = nrow(spiral_points) - 1
spiral_lines = screen_line(
  start = spiral_points[-nrow(spiral_points), ],
  end = spiral_points[-1, ],
  width = seq(1, 4, length.out = spiral_count),
  color = grDevices::hcl(seq(250, 360, length.out = spiral_count), 80, 65),
  alpha = seq(0.35, 0.95, length.out = spiral_count),
  lineend = "round",
  clip = TRUE
)

line_layers = list(
  sphere_measure,
  box_measure,
  wall_rule,
  callout_line,
  spiral_lines
)

render_scene(
  scene,
  samples = 32,
  clamp_value = 5,
  aperture = 0,
  ambient_light = FALSE,
  screen_line = line_layers
)


rayrender documentation built on Sept. 16, 2026, 9:08 a.m.