R/render_ao.R

Defines functions render_ao

Documented in render_ao

#' Render Ambient Occlusion
#'
#' Takes the scene description and renders an image using ambient occlusion,
#' either to the device or to a filename.
#'
#' @param scene Tibble of object locations and properties.
#' @param width Default `400`. Width of the render, in pixels.
#' @param height Default `400`. Height of the render, in pixels.
#' @param fov Default `20`. Field of view, in degrees. If this is `0`, the camera will use an orthographic projection. The size of the plane
#' used to create the orthographic projection is given in argument `ortho_dimensions`. From `0` to `180`, this uses a perspective
#' projections. If this value is `360`, a 360 degree environment image will be rendered.
#' @param sample_dist Default `10`. Ambient occlusion sampling distance.
#' @param keep_colors Default `FALSE`. Whether to keep the diffuse material colors.
#' @param background_color Default `"white"`. Background color.
#' @param samples Default `100`. The maximum number of samples for each pixel. If this is a length-2
#' vector and the `sample_method` is `stratified`, this will control the number of strata in each dimension.
#' The total number of samples in this case will be the product of the two numbers.
#' @param camera_description_file Default `NA`. Filename of a camera description file for rendering with
#' a realistic camera. Several camera files are built-in: `"50mm"`,`"wide"`,`"fisheye"`, and `"telephoto"`.
#' @param camera_scale Default `1`. Amount to scale the camera up or down in size. Use this rather than scaling a
#' scene.
#' @param iso Default `100`. Camera exposure.
#' @param film_size Default `22`, in `mm` (scene units in `m`. Size of the film if using a realistic camera, otherwise
#' ignored.
#' @param min_variance Default `0.00005`. Minimum acceptable variance for a block of pixels for the
#' adaptive sampler. Smaller numbers give higher quality images, at the expense of longer rendering times.
#' If this is set to zero, the adaptive sampler will be turned off and the renderer
#' will use the maximum number of samples everywhere.
#' @param min_adaptive_size Default `8`. Width of the minimum block size in the adaptive sampler.
#' @param sample_method Default `sobol`. The type of sampling method used to generate
#' random numbers. The other options are `random` (worst quality but fastest),
#' `stratified` (only implemented for completion), `sobol_blue` (best option for sample counts below 256),
#' and `sobol` (slowest but best quality, better than `sobol_blue` for sample counts greater than 256).
#' @param lookfrom Default `c(0,1,10)`. Location of the camera.
#' @param lookat Default `c(0,0,0)`. Location where the camera is pointed.
#' @param camera_up Default `c(0,1,0)`. Vector indicating the "up" position of the camera.
#' @param aperture Default `0.1`. Aperture of the camera. Smaller numbers will increase depth of field, causing
#' less blurring in areas not in focus.
#' @param clamp_value Default `Inf`. If a bright light or a reflective material is in the scene, occasionally
#' there will be bright spots that will not go away even with a large number of samples. These
#' can be removed (at the cost of slightly darkening the image) by setting this to a small number greater than 1.
#' @param filename Default `NA`. If present, the renderer will write to the filename instead
#' of the current device.
#' @param shutteropen Default `0`. Time at which the shutter is open. Only affects moving objects.
#' @param shutterclose Default `1`. Time at which the shutter is open. Only affects moving objects.
#' @param focal_distance Default `NULL`, automatically set to the `lookfrom-lookat` distance unless
#' otherwise specified.
#' @param ortho_dimensions Default `c(1,1)`. Width and height of the orthographic camera. Will only be used if `fov = 0`.
#' @param parallel Default `FALSE`. If `TRUE`, it will use all available cores to render the image
#'  (or the number specified in `options("cores")` if that option is not `NULL`).
#' @param bvh_type Default `"sah"`, "surface area heuristic". Method of building the bounding volume
#' hierarchy structure used when rendering. Other option is "equal", which splits tree into groups
#' of equal size.
#' @param progress Default `TRUE` if interactive session, `FALSE` otherwise.
#' @param verbose Default `FALSE`. Prints information and timing information about scene
#' construction and raytracing progress.
#' @export
#' @importFrom  grDevices col2rgb
#' @return Raytraced plot to current device, or an image saved to a file. Invisibly returns the
#' array (containing either debug data or the RGB)
#'
#'@examplesIf interactive() || identical(Sys.getenv("IN_PKGDOWN"), "true")
#' #Generate and render a regular scene and an ambient occlusion version of that scene
#'angles = seq(0,360,by=36)
#'xx = rev(c(rep(c(1,0.5),5),1) * sinpi(angles/180))
#'yy = rev(c(rep(c(1,0.5),5),1) * cospi(angles/180))
#'star_polygon = data.frame(x=xx,y=yy)
#'hollow_star = rbind(star_polygon,0.8*star_polygon)
#'
#'generate_ground(material = diffuse(color="grey20", checkercolor = "grey50",sigma=90)) |>
#'  add_object(sphere(material=metal())) |>
#'  add_object(obj_model(r_obj(),y=-0.25,x=-1.8,scale=2,
#'                       angle=c(0,-45,0),material = diffuse(sigma=90))) |>
#'  add_object(pig(x=1.8,y=-1.2,scale=0.5,angle=c(0,90,0),diffuse_sigma = 90)) |>
#'  add_object(extruded_polygon(hollow_star,top=-0.5,bottom=-1, z=-2,
#'                              hole = nrow(star_polygon),
#'                              material=diffuse(color="red",sigma=90))) |>
#'  render_scene(parallel = TRUE,width=800,height=800,
#'               fov=70,clamp_value=10,samples=16, aperture=0.1,
#'               lookfrom=c(-0.9,1.2,-4.5),lookat=c(0,-1,0))
#'
#'#Render the scene with ambient occlusion
#'generate_ground(material = diffuse(color="grey20", checkercolor = "grey50",sigma=90)) |>
#'  add_object(sphere(material=metal())) |>
#'  add_object(obj_model(r_obj(),y=-0.25,x=-1.8,scale=2,
#'                       angle=c(0,-45,0),material = diffuse(sigma=90))) |>
#'  add_object(pig(x=1.8,y=-1.2,scale=0.5,angle=c(0,90,0),diffuse_sigma = 90)) |>
#'  add_object(extruded_polygon(hollow_star,top=-0.5,bottom=-1, z=-2,
#'                              hole = nrow(star_polygon),
#'                              material=diffuse(color="red",sigma=90))) |>
#'  render_ao(parallel = TRUE,width=800,height=800, sample_dist=10,
#'            fov=70,samples=16, aperture=0.1,
#'            lookfrom=c(-0.9,1.2,-4.5),lookat=c(0,-1,0))
#'#Decrease the ray occlusion search distance
#'generate_ground(material = diffuse(color="grey20", checkercolor = "grey50",sigma=90)) |>
#'  add_object(sphere(material=metal())) |>
#'  add_object(obj_model(r_obj(),y=-0.25,x=-1.8,scale=2,
#'                       angle=c(0,-45,0),material = diffuse(sigma=90))) |>
#'  add_object(pig(x=1.8,y=-1.2,scale=0.5,angle=c(0,90,0),diffuse_sigma = 90)) |>
#'  add_object(extruded_polygon(hollow_star,top=-0.5,bottom=-1, z=-2,
#'                              hole = nrow(star_polygon),
#'                              material=diffuse(color="red",sigma=90))) |>
#'  render_ao(parallel = TRUE,width=800,height=800, sample_dist=1,
#'            fov=70,samples=16, aperture=0.1,
#'            lookfrom=c(-0.9,1.2,-4.5),lookat=c(0,-1,0))
#'#Turn on colors
#'generate_ground(material = diffuse(color="grey20", checkercolor = "grey50",sigma=90)) |>
#'  add_object(sphere(material=metal())) |>
#'  add_object(obj_model(r_obj(), y=-0.25,x=-1.8,scale=2,
#'                       angle=c(0,-45,0),material = diffuse(sigma=90))) |>
#'  add_object(pig(x=1.8,y=-1.2,scale=0.5,angle=c(0,90,0),diffuse_sigma = 90)) |>
#'  add_object(extruded_polygon(hollow_star,top=-0.5,bottom=-1, z=-2,
#'                              hole = nrow(star_polygon),
#'                              material=diffuse(color="red",sigma=90))) |>
#'  render_ao(parallel = TRUE,width=800,height=800, sample_dist=1,
#'            fov=70,samples=16, aperture=0.1, keep_colors = TRUE,
#'            lookfrom=c(-0.9,1.2,-4.5),lookat=c(0,-1,0))
#'
render_ao = function(
  scene,
  width = 400,
  height = 400,
  fov = 20,
  sample_dist = 10,
  keep_colors = FALSE,
  samples = 100,
  camera_description_file = NA,
  camera_scale = 1,
  iso = 100,
  film_size = 22,
  min_variance = 0.0000,
  min_adaptive_size = 8,
  sample_method = "sobol",
  background_color = "white",
  lookfrom = c(0, 1, 10),
  lookat = c(0, 0, 0),
  camera_up = c(0, 1, 0),
  aperture = 0.1,
  clamp_value = Inf,
  filename = NA,
  shutteropen = 0.0,
  shutterclose = 1.0,
  focal_distance = NULL,
  ortho_dimensions = c(1, 1),
  parallel = TRUE,
  bvh_type = "sah",
  progress = interactive(),
  verbose = FALSE
) {
  #Check if Cornell Box scene and set camera if user did not:
  if (!is.null(attr(scene, "cornell"))) {
    corn_message = "Setting default values for Cornell box: "
    missing_corn = FALSE
    if (missing(lookfrom)) {
      lookfrom = c(278, 278, -800)
      corn_message = paste0(corn_message, "lookfrom `c(278,278,-800)` ")
      missing_corn = TRUE
    }
    if (missing(lookat)) {
      lookat = c(278, 278, 555 / 2)
      corn_message = paste0(corn_message, "lookat `c(278,278,555/2)` ")
      missing_corn = TRUE
    }
    if (missing(fov) && is.na(camera_description_file)) {
      fov = 40
      corn_message = paste0(corn_message, "fov `40` ")
      missing_corn = TRUE
    }
    if (
      fov == 0 && missing(ortho_dimensions) && is.na(camera_description_file)
    ) {
      ortho_dimensions = c(580, 580)
      corn_message = paste0(corn_message, "ortho_dimensions `c(580, 580)` ")
      missing_corn = TRUE
    }
    corn_message = paste0(corn_message, ".")
    if (missing_corn) {
      message(corn_message)
    }
  }
  debug_channel = "ao"
  tonemap = "raw"
  bloom = FALSE

  background_color = convert_color(background_color)
  scene_list = prepare_scene_list(
    scene = scene,
    width = width,
    height = height,
    fov = fov,
    samples = samples,
    camera_description_file = camera_description_file,
    camera_scale = camera_scale,
    iso = iso,
    film_size = film_size,
    min_variance = min_variance,
    min_adaptive_size = min_adaptive_size,
    sample_method = sample_method,
    max_depth = 1000,
    roulette_active_depth = 1000,
    ambient_light = FALSE,
    lookfrom = lookfrom,
    lookat = lookat,
    camera_up = camera_up,
    aperture = aperture,
    clamp_value = clamp_value,
    filename = filename,
    backgroundhigh = background_color,
    backgroundlow = background_color,
    shutteropen = shutteropen,
    shutterclose = shutterclose,
    focal_distance = focal_distance,
    ortho_dimensions = ortho_dimensions,
    tonemap = "raw",
    bloom = FALSE,
    parallel = parallel,
    bvh_type = bvh_type,
    environment_light = NULL,
    rotate_env = 0,
    intensity_env = 1,
    debug_channel = debug_channel,
    plot_scene = TRUE,
    progress = progress,
    verbose = verbose,
    sample_dist = sample_dist,
    keep_colors = keep_colors,
    deferred_render = FALSE
  )

  camera_info = scene_list$camera_info
  scene_info = scene_list$scene_info
  render_info = scene_list$render_info
  processed_scene = scene_info$scene

  camera_info$preview = FALSE
  camera_info$interactive = FALSE
  debug_channel = 18 # converted to numeric

  #Pathtrace Scene
  rgb_mat = render_scene_rcpp(
    scene = processed_scene,
    camera_info = camera_info,
    scene_info = scene_info,
    render_info = render_info
  )

  return_array = post_process_scene(
    rgb_mat,
    iso,
    FALSE, #use_iso
    tonemap,
    debug_channel,
    filename,
    FALSE,
    bloom
  )
  return(invisible(return_array))
}

Try the rayrender package in your browser

Any scripts or data that you put into this service are public.

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