R/tree_mesh.R

Defines functions tree_mesh

Documented in tree_mesh

#'@title Generate a Tree Mesh
#'
#'@description This function generates a tree model and transforms it into a `ray_mesh` object or an OBJ file.
#' The tree model consists of two main parts: the crown (leafy part) and the trunk. Both parts can be customized according
#' to a range of preset types, as well as full control over the tree's colors and dimensions.
#' The tree model can be positioned, scaled, and rotated in 3D space.
#'
#' @param crown_type Default `"oval"`. Crown type (the leafy part of the tree). Full list of options:
#'| **3D/Flat**  | **Name**           | **Crown Color**                            | **Trunk Ratio** |
#'| :----------: | :----------------: | :----------------------------------------: | :-------------: |
#'| Both         | `"columnar"`       | `"#A2C683"` \figure{columnarsquare.png}   | 1/3             |
#'| Both         | `"pyramidal1"`     | `"#066038"` \figure{pyramidal1square.png} | 1/6             |
#'| Both         | `"pyramidal2"`     | `"#447765"` \figure{pyramidal2square.png} | 1/6             |
#'| Both         | `"weeping"`        | `"#CBD362"` \figure{weepingsquare.png}    | 1/3             |
#'| Both         | `"spreading1"`     | `"#CCB471"` \figure{spreading1square.png} | 1/3             |
#'| Both         | `"oval"`           | `"#7CB262"` \figure{ovalsquare.png}       | 1/3             |
#'| Flat-only    | `"palm"`           | `"#DB8952"` \figure{palmsquare.png}       | 1/2             |
#'| Flat-only    | `"rounded"`        | `"#E0A854"` \figure{roundedsquare.png}    | 1/3             |
#'| Flat-only    | `"spreading2"`     | `"#75C165"` \figure{spreading2square.png} | 1/3             |
#'| Flat-only    | `"vase"`           | `"#AECCB1"` \figure{vasesquare.png}       | 1/3             |
#' @param solid Default `FALSE`. Whether the crown should be a solid mesh (`TRUE`), or a collection of flat
#' 2D planes (`FALSE`).
#' @param position Default `c(0,0,0)`. A length-3 numeric vector specifying the X, Y, and Z coordinates of the tree mesh in 3D space.
#' @param angle Default `0`. Amount of rotation around the y-axis for the tree.
#' @param resolution Default `"medium"`. String indicating the level of detail of the tree mesh. All options:
#'`"low"`
#'`"medium"`
#'`"high`
#' @param filename Default `NULL`. File name of the OBJ file, if saving the mesh to a local file.
#' @param tree_height Default `1`. A numeric value setting the total height of the tree.
#' @param trunk_height_ratio Default `NULL`. A numeric value specifying the ratio of the trunk height to the total height of the tree. If not provided, default values for each tree type will be used.
#' @param crown_width_ratio Default `1`. A numeric value specifying the ratio of the crown width to the crown height.
#' @param crown_height Default `NULL`. A numeric value setting the height of the crown. If not provided, it is calculated based on the tree height and trunk height ratio.
#' @param crown_width Default `NULL`. A numeric value setting the diameter of the crown. If not provided, it is calculated based on the crown height and crown width ratio.
#' @param trunk_height Default `NULL`. A numeric value setting the height of the trunk. If not provided, it is calculated based on the tree height and trunk height ratio.
#' @param trunk_width Default `NULL`. A numeric value setting the diameter of the trunk. If not provided, this is set to 1/10th the crown width.
#' @param crown_color Default `NA`, use default for crown type. A string specifying the hex code of the crown color.
#' @param trunk_color Default `"#8C6F5B"`. A string specifying the hex code of the trunk color.
#' @param diffuse_intensity Default `1.0`. A numeric value controlling the amount of diffuse (shaded) color included in the model.
#' @param ambient_intensity Default `0.2`. A numeric value controlling the amount of ambient (constant) color included in the model.
#'@export
#'
#'@return `ray_mesh` list object
#'@examples
#'#Load a tree and render it
#'library(rayvertex)
#'render_tree_example = function(example_tree_mesh) {
#'  example_tree_mesh |>
#'    add_shape(xz_rect_mesh(c(0,0,-9),
#'                           material = material_list(diffuse="tan",
#'                           ambient = "grey", diffuse_intensity = 0.7,
#'                           ambient_intensity = 0.6),
#'                           scale=25)) |>
#'    rasterize_scene(lookat=c(0,0.5,0),
#'                    light_info = directional_light(c(0.3,1,1), intensity = 0.7),
#'                    lookfrom=c(0,3,10),
#'                    fov=8,
#'                    shadow_map_dims = 2, shadow_map_bias = 0.0005,
#'                    width = 800, height = 800,
#'                    #fsaa = 4, ssao = TRUE, ssao_intensity = 1,
#'                    background = "lightblue")
#'}
#'if(run_documentation()) {
#'#Render a basic 3D crown
#'tree_mesh("columnar",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'#Render the 2D planar version
#'tree_mesh("columnar",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'#Adjust the trunk/crown proportions of the overall tree using ratios
#'tree_mesh("columnar",
#'          tree_height = 1,
#'          trunk_height_ratio = 1/5,
#'          crown_width_ratio = 1.25,
#'          trunk_width = 0.125,
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'
#'}
#'
#'if(run_documentation()) {
#'#The crown width is set proportional to the crown height (not the overall tree)
#'tree_mesh("columnar",
#'          tree_height = 1,
#'          trunk_height_ratio = 2/3,
#'          crown_width_ratio = 1,
#'          trunk_width = 0.075,
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'
#'if(run_documentation()) {
#'#Set the trunk and crown dimensions directly
#'tree_mesh("columnar",
#'          trunk_height = 0.25,
#'          trunk_width = 0.05,
#'          crown_height = 0.75,
#'          crown_width = 0.33,
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'#Change the crown and trunk color
#'tree_mesh("columnar",
#'          solid = TRUE,
#'          crown_color = "orange",
#'          trunk_color = "tan",
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'#Render different tree types, both 2D and 3D versions
#'tree_mesh("columnar",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("columnar",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("pyramidal1",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("pyramidal1",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("pyramidal2",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("pyramidal2",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("weeping",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("weeping",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("spreading1",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("spreading1",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("oval",
#'          solid = TRUE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("oval",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("palm",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("rounded",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("spreading2",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
#'if(run_documentation()) {
#'tree_mesh("vase",
#'          solid = FALSE,
#'          ambient_intensity = 0.3) |>
#'  render_tree_example()
#'}
tree_mesh = function(crown_type = "oval",
                     position = c(0,0,0),
                     angle = 0,
                     solid = FALSE,
                     resolution = "medium",
                     filename = NULL,
                     tree_height  = 1,
                     trunk_height_ratio = NULL,
                     crown_width_ratio = 1,
                     crown_height = NULL,
                     crown_width = NULL,
                     trunk_height = NULL,
                     trunk_width = NULL,
                     crown_color = NA,
                     trunk_color = "#8C6F5B",
                     diffuse_intensity = 1.0,
                     ambient_intensity = 0.2) {
  if(solid) {
    crown_file = get_solid_crown_file(crown_type, resolution, offset_origin = TRUE)
  } else {
    crown_file = get_flat_crown_file(crown_type, resolution, offset_origin = TRUE)
  }

  if(is.na(crown_color)) {
    crown_color = get_default_tree_color(crown_type)
  }
  tree_data = get_tree_data()
  if(is.null(trunk_height_ratio)) {
    default_ratio = tree_data$trunk_crown_ratio[which(tree_data$name == crown_type)]
    trunk_height_ratio = default_ratio
  }

  #Define crown dimensions
  if(is.null(crown_height)) {
    stopifnot(trunk_height_ratio < 1 && trunk_height_ratio >= 0)
    crown_height = (1 - trunk_height_ratio) * tree_height
  }
  if(is.null(crown_width)) {
    crown_width = crown_height * crown_width_ratio
  }

  #Define trunk dimensions
  if(is.null(trunk_height)) {
    trunk_height = trunk_height_ratio * tree_height
  }
  if(is.null(trunk_width)) {
    trunk_width = crown_width / 10
  }

  crown_mesh = rayvertex::obj_mesh(crown_file,
                                   material = rayvertex::material_list(diffuse = crown_color,
                                                                       ambient = crown_color,
                                                                       diffuse_intensity = diffuse_intensity,
                                                                       ambient_intensity = ambient_intensity,
                                                                       culling = "none", two_sided = TRUE)) |>
    rayvertex::scale_mesh(scale = c(crown_width,crown_height,crown_width)) |>
    rayvertex::translate_mesh(position = c(0,trunk_height,0))

  trunk_mesh = rayvertex::obj_mesh(get_trunk_file(offset = TRUE),
                                   material = rayvertex::material_list(diffuse = trunk_color,
                                                                       diffuse_intensity = diffuse_intensity,
                                                                       ambient_intensity = ambient_intensity,
                                                                       ambient = trunk_color)) |>
    rayvertex::scale_mesh(scale = c(trunk_width,
                                    trunk_height,
                                    trunk_width))
  tree_full = rayvertex::add_shape(crown_mesh, trunk_mesh) |>
    rayvertex::rotate_mesh(angle = c(0,angle,0)) |>
    rayvertex::translate_mesh(position)
  if(!is.null(filename)) {
    rayvertex::write_scene_to_obj(tree_full, filename)
  }
  return(tree_full)
}

Try the tree3d package in your browser

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

tree3d documentation built on July 9, 2023, 5:18 p.m.