diff --git a/DESCRIPTION b/DESCRIPTION index 538564c0..49fd2764 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: rayshader Type: Package Title: Create Maps and Visualize Data in 2D and 3D -Version: 0.36.0 -Date: 2023-07-30 +Version: 0.36.1 +Date: 2023-08-01 Author: Tyler Morgan-Wall Maintainer: Tyler Morgan-Wall Description: Uses a combination of raytracing and multiple hill shading methods to produce 2D and 3D data visualizations and maps. Includes water detection and layering functions, programmable color palette generation, several built-in textures for hill shading, 2D and 3D plotting options, a built-in path tracer, 'Wavefront' OBJ file export, and the ability to save 3D visualizations to a 3D printable format. diff --git a/R/convert_rgl_to_raymesh.R b/R/convert_rgl_to_raymesh.R index e3168698..7d3cdeab 100644 --- a/R/convert_rgl_to_raymesh.R +++ b/R/convert_rgl_to_raymesh.R @@ -1,9 +1,9 @@ -#'@title Convert RGL to ray_mesh +#'@title Convert rayshader RGL scene to ray_mesh object #' -#'@description Converts the current RGL scene to a ray_mesh object +#'@description Converts the current RGL rayshader scene to a `ray_mesh` object (see `rayvertex` package for more information) #' -#'@param filename String with the filename. If `.obj` is not at the end of the string, it will be appended automatically. #'@param save_shadow Default `FALSE`. If `TRUE`, this saves a plane with the shadow texture below the model. +#'@return A `ray_mesh` object #'@export #'@examples #'if(interactive()) { @@ -17,8 +17,7 @@ #' #'rm_obj = convert_rgl_to_raymesh() #'} -convert_rgl_to_raymesh = function(water_index_refraction = 1, - save_shadow = TRUE) { +convert_rgl_to_raymesh = function(save_shadow = TRUE) { if(rgl::cur3d() == 0) { stop("No rgl window currently open.") } @@ -26,14 +25,20 @@ convert_rgl_to_raymesh = function(water_index_refraction = 1, num_elems = 1 vertex_info = get_ids_with_labels() - basic_load_mesh = function(row, texture_loc, color = "white", alpha=1, obj = FALSE, specular = "white") { + basic_load_mesh = function(row, texture_loc, + color = "white", alpha=1, obj = FALSE, specular = "white", + lit = FALSE, quads = FALSE) { id = as.character(vertex_info$id[row]) indices = matrix(rgl::rgl.attrib(vertex_info$id[row], "indices"), ncol = 3L, byrow = TRUE) - 1 vertices = rgl.attrib(vertex_info$id[row], "vertices") - if(nrow(indices) == 0) { + if(nrow(indices) == 0 && !quads) { indices = matrix(seq_len(nrow(vertices))-1, ncol = 3, nrow = nrow(vertices)/3, byrow = TRUE) + } else if (quads) { + quads = matrix(seq_len(nrow(vertices))-1,nrow=4) + indices = t(matrix(rbind(quads[c(1L, 2L, 4L),], + quads[c(2L, 3L, 4L),]), 3L)) } textures = rgl.attrib(vertex_info$id[row], "texcoords") normals = rgl.attrib(vertex_info$id[row], "normals") @@ -76,11 +81,16 @@ convert_rgl_to_raymesh = function(water_index_refraction = 1, norm_indices = norm_indices, material = rayvertex::material_list(texture_location = texture_loc, diffuse = color, - type = "color", + type = ifelse(lit, "diffuse", "color"), dissolve = alpha, specular = specular))) } for(row in 1:nrow(vertex_info)) { + if(!is.na(vertex_info$lit[row])) { + lit_val = vertex_info$lit[row] + } else { + lit_val = FALSE + } if(vertex_info$tag[row] == "surface") { dims = rgl::rgl.attrib(vertex_info$id[row], "dim") vertices = rgl.attrib(vertex_info$id[row], "vertices") @@ -159,6 +169,7 @@ convert_rgl_to_raymesh = function(water_index_refraction = 1, type = "color")) } else if (vertex_info$tag[row] == "base") { final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, texture_loc = NA, color = vertex_info$base_color[[row]]) } else if (vertex_info$tag[row] == "water") { @@ -169,33 +180,53 @@ convert_rgl_to_raymesh = function(water_index_refraction = 1, specular = vertex_info$water_color[[row]]) } else if (vertex_info$tag[row] == "north_symbol") { final_scene[[num_elems]] = basic_load_mesh(row, - texture_loc = vertex_info$north_color[[row]]) + lit = lit_val, + texture_loc = NA, + color = vertex_info$north_color[[row]]) } else if (vertex_info$tag[row] == "arrow_symbol") { final_scene[[num_elems]] = basic_load_mesh(row, - texture_loc = vertex_info$arrow_color[[row]]) + lit = lit_val, + texture_loc = NA, + color = vertex_info$arrow_color[[row]]) } else if (vertex_info$tag[row] == "bevel_symbol") { final_scene[[num_elems]] = basic_load_mesh(row, - texture_loc = vertex_info$bevel_color[[row]]) + lit = lit_val, + texture_loc = NA, + color = vertex_info$bevel_color[[row]]) } else if (vertex_info$tag[row] == "background_symbol") { final_scene[[num_elems]] = basic_load_mesh(row, - texture_loc = vertex_info$background_color[[row]]) + lit = lit_val, + texture_loc = NA, + color = vertex_info$background_color[[row]]) } else if (vertex_info$tag[row] == "scalebar_col1") { if(vertex_info$type[row] == "quads") { - #Need to handle quads - baseindices = matrix(vertex_info$startindex[row]:vertex_info$endindex[row], ncol=4, byrow=TRUE) + final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, + texture_loc = NA, + quads = TRUE, + color = vertex_info$scalebar1_color[[row]]) } else { - final_scene[[num_elems]] = basic_load_mesh(row, texture_loc = NA) + final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, + color = vertex_info$scalebar1_color[[row]], + texture_loc = NA) } } else if (vertex_info$tag[row] == "scalebar_col2") { if(vertex_info$type[row] == "quads") { - #Need to handle quads - - baseindices = matrix(vertex_info$startindex[row]:vertex_info$endindex[row], ncol=4, byrow=TRUE) + final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, + texture_loc = NA, + quads = TRUE, + color = vertex_info$scalebar2_color[[row]]) } else { - final_scene[[num_elems]] = basic_load_mesh(row, texture_loc = NA) + final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, + color = vertex_info$scalebar2_color[[row]], + texture_loc = NA) } } else if (vertex_info$tag[row] == "polygon3d") { final_scene[[num_elems]] = basic_load_mesh(row, texture_loc = NA, + lit = lit_val, color = vertex_info$tricolor[[row]]) } else if(vertex_info$tag[row] == "shadow" && save_shadow) { final_scene[[num_elems]] = basic_load_mesh(row, @@ -205,9 +236,11 @@ convert_rgl_to_raymesh = function(water_index_refraction = 1, texture_loc = vertex_info$layer_texture_file[[row]]) } else if (vertex_info$tag[row] %in% c("base_soil1","base_soil2")) { final_scene[[num_elems]] = basic_load_mesh(row, + lit = lit_val, texture_loc = vertex_info$soil_texture[[row]]) } else if (grepl("obj", vertex_info$tag[row], fixed=TRUE)) { tmp_obj = basic_load_mesh(row, texture_loc = vertex_info$texture_file[[row]], + lit = lit_val, obj = TRUE) obj_color = vertex_info$obj_color[[row]] obj_alpha = vertex_info$obj_alpha[[row]] diff --git a/R/render_highquality.R b/R/render_highquality.R index ff63d582..265597fd 100644 --- a/R/render_highquality.R +++ b/R/render_highquality.R @@ -27,7 +27,8 @@ #'@param lightsize Default `NULL`. Radius of the light(s). Automatically chosen, but can be set here by the user. #'@param lightintensity Default `500`. Intensity of the light. #'@param lightcolor Default `white`. The color of the light. -#'@param obj_material Default `rayrender::diffuse()`. The material properties of the object file. +#'@param material Default `rayrender::diffuse()`. The material properties of the object file. Only used if `override_material = TRUE` +#'@param override_material Default `FALSE`. Whether to override the default diffuse material with that in argument `material`. #'@param cache_scene Default `FALSE`. Whether to cache the current scene to memory so it does not have to be converted to a `raymesh` object #'each time `render_snapshot()` is called. If `TRUE` and a scene has been cached, it will be used when rendering. #'@param reset_scene_cache Default `FALSE`. Resets the scene cache before rendering. @@ -157,11 +158,11 @@ #' material=rayrender::light(color="red",intensity=10)), #' min_variance = 0, sample_method = "sobol_blue") #'} -render_highquality = function(filename = NULL, samples = 128, +render_highquality = function(filename = NA, samples = 128, sample_method = "sobol_blue", min_variance=1e-7, light = TRUE, lightdirection = 315, lightaltitude = 45, lightsize=NULL, - lightintensity = 500, lightcolor = "white", obj_material = rayrender::diffuse(), + lightintensity = 500, lightcolor = "white", material = rayrender::diffuse(), override_material = FALSE, cache_scene = FALSE, reset_scene_cache = FALSE, width = NULL, height = NULL, @@ -193,7 +194,7 @@ render_highquality = function(filename = NULL, samples = 128, if(reset_scene_cache) { assign("scene_cache", NULL, envir = ray_cache_scene_envir) } - if(!is.null(filename)) { + if(!is.na(filename)) { if(dirname(filename) != ".") { if(!dir.exists(dirname(filename))) { stop(sprintf("Error: directory '%s' does not exist.", dirname(filename))) @@ -365,11 +366,11 @@ render_highquality = function(filename = NULL, samples = 128, if(cache_scene) { ray_scene = get("scene_cache", envir = ray_cache_scene_envir) if(is.null(ray_scene)) { - ray_scene = convert_rgl_to_raymesh() + ray_scene = convert_rgl_to_raymesh(save_shadow = FALSE) assign("scene_cache", ray_scene, envir = ray_cache_scene_envir) } } else { - ray_scene = convert_rgl_to_raymesh() + ray_scene = convert_rgl_to_raymesh(save_shadow = FALSE) } if(!override_material) { @@ -384,7 +385,7 @@ render_highquality = function(filename = NULL, samples = 128, x = -bbox_center[1], y = -bbox_center[2], z = -bbox_center[3], - material = obj_material, + material = material, override_material = TRUE, calculate_consistent_normals = calculate_consistent_normals) } @@ -604,9 +605,6 @@ render_highquality = function(filename = NULL, samples = 128, if(!is.null(animation_camera_coords)) { stopifnot(ncol(animation_camera_coords) == 14) - if(is.null(filename)) { - filename = NA - } rayrender::render_animation(scene, camera_motion = animation_camera_coords, width = width, height = height, min_variance = min_variance, samples = samples, sample_method = sample_method, filename = filename, clamp_value = clamp_value, ...) @@ -633,10 +631,17 @@ render_highquality = function(filename = NULL, samples = 128, } } } else { - debug_return = rayrender::render_scene(scene, lookfrom = lookfrom, lookat = camera_lookat, fov = fov, filename=filename, - min_variance = min_variance, samples = samples, sample_method = sample_method, - ortho_dimensions = ortho_dimensions, width = width, height = height, #camera_up = camera_up, - clamp_value = clamp_value, ...) + if(!is.na(filename)) { + debug_return = rayrender::render_scene(scene, lookfrom = lookfrom, lookat = camera_lookat, fov = fov, filename=filename, + min_variance = min_variance, samples = samples, sample_method = sample_method, + ortho_dimensions = ortho_dimensions, width = width, height = height, #camera_up = camera_up, + clamp_value = clamp_value, ...) + } else { + debug_return = rayrender::render_scene(scene, lookfrom = lookfrom, lookat = camera_lookat, fov = fov, + min_variance = min_variance, samples = samples, sample_method = sample_method, + ortho_dimensions = ortho_dimensions, width = width, height = height, #camera_up = camera_up, + clamp_value = clamp_value, ...) + } } if(clear) { rgl::clear3d() diff --git a/R/render_snapshot_software.R b/R/render_snapshot_software.R index 51ac7aa8..7c48aa00 100644 --- a/R/render_snapshot_software.R +++ b/R/render_snapshot_software.R @@ -221,11 +221,13 @@ render_snapshot_software = function(filename, cache_scene = FALSE, camera_locati if(thick_lines) { for(j in seq_len(nrow(temp_verts)-1)) { line_mat = rayvertex::material_list(diffuse = temp_color[j,1:3], type = "color") - line_scene[[line_counter]] = rayvertex::segment_mesh(start = temp_verts[j,] - bbox_center, - end = temp_verts[j+1,] - bbox_center, - radius = line_radius, - material = line_mat) - line_counter = line_counter + 1 + if(!all(temp_verts[j+1,] == temp_verts[j,])) { + line_scene[[line_counter]] = rayvertex::segment_mesh(start = temp_verts[j,] - bbox_center, + end = temp_verts[j+1,] - bbox_center, + radius = line_radius, + material = line_mat) + line_counter = line_counter + 1 + } } } else { for(j in seq_len(nrow(temp_verts)-1)) { diff --git a/R/save_multipolygonz_to_obj.R b/R/save_multipolygonz_to_obj.R index eb50f520..7658a6e3 100644 --- a/R/save_multipolygonz_to_obj.R +++ b/R/save_multipolygonz_to_obj.R @@ -21,17 +21,16 @@ save_multipolygonz_to_obj = function(sfobj, filename, swap_yz = FALSE) { total_verts = 0 cat_list = list() counter = 1 - geometry_list = sf::st_geometry(sfobj) - num_polygons = length(sfobj) - - for(j in seq_len(num_polygons)) { - single_geom = geometry_list - number = length(single_geom) - for(i in seq_len(number)) { + + for(j in seq_len(nrow(sfobj))) { + mat_coords = sf::st_coordinates(sf::st_geometry(sfobj[j,])) + geometry_list = lapply(split(mat_coords[,1:3],mat_coords[,5]),matrix,ncol=3) + for(i in seq_len(length(geometry_list))) { + single_geom = geometry_list[[i]] if(swap_yz) { - mat = as.matrix(single_geom[[i]])[-1,c(1,3,2)] + mat = as.matrix(single_geom)[-1,c(1,3,2)] } else { - mat = as.matrix(single_geom[[i]])[-1,] + mat = as.matrix(single_geom)[-1,] } text_mat = matrix(sprintf("%0.4f", mat),ncol=ncol(mat), nrow=nrow(mat)) indices = sprintf("%d", seq_len(nrow(mat))+total_verts) diff --git a/man/convert_rgl_to_raymesh.Rd b/man/convert_rgl_to_raymesh.Rd index a1c8d9dc..429fa23b 100644 --- a/man/convert_rgl_to_raymesh.Rd +++ b/man/convert_rgl_to_raymesh.Rd @@ -2,15 +2,16 @@ % Please edit documentation in R/convert_rgl_to_raymesh.R \name{convert_rgl_to_raymesh} \alias{convert_rgl_to_raymesh} -\title{Convert RGL to ray_mesh} +\title{Convert rayshader RGL scene to ray_mesh object} \usage{ -convert_rgl_to_raymesh(water_index_refraction = 1, save_shadow = TRUE) +convert_rgl_to_raymesh(save_shadow = TRUE) } \arguments{ \item{save_shadow}{Default `FALSE`. If `TRUE`, this saves a plane with the shadow texture below the model.} - -\item{filename}{String with the filename. If `.obj` is not at the end of the string, it will be appended automatically.} +} +\value{ +A `ray_mesh` object } \description{ -Converts the current RGL scene to a ray_mesh object +Converts the current RGL rayshader scene to a `ray_mesh` object (see `rayvertex` package for more information) } diff --git a/man/render_highquality.Rd b/man/render_highquality.Rd index 1b8a87a9..7eae6a6c 100644 --- a/man/render_highquality.Rd +++ b/man/render_highquality.Rd @@ -15,7 +15,7 @@ render_highquality( lightsize = NULL, lightintensity = 500, lightcolor = "white", - obj_material = rayrender::diffuse(), + material = rayrender::diffuse(), override_material = FALSE, cache_scene = FALSE, reset_scene_cache = FALSE, @@ -89,7 +89,9 @@ If this is a vector longer than one, multiple lights will be generated (using va \item{lightcolor}{Default `white`. The color of the light.} -\item{obj_material}{Default `rayrender::diffuse()`. The material properties of the object file.} +\item{material}{Default `rayrender::diffuse()`. The material properties of the object file. Only used if `override_material = TRUE`} + +\item{override_material}{Default `FALSE`. Whether to override the default diffuse material with that in argument `material`.} \item{cache_scene}{Default `FALSE`. Whether to cache the current scene to memory so it does not have to be converted to a `raymesh` object each time `render_snapshot()` is called. If `TRUE` and a scene has been cached, it will be used when rendering.}