Skip to content

Commit

Permalink
rayshader v0.36.1: Fix raymesh conversion bugs + render_multipolygonz…
Browse files Browse the repository at this point in the history
…() fixes

-Fix several bugs in rgl-to-raymesh conversion
-Fix multipolygonz meshing
-`render_highquality()` Change argument `obj_material` to `material`
-Fix NA filename bugs in `render_highquality()`
-Fix docs
-Fix  degenerate normals when specifying zero length path segment with render_path()
  • Loading branch information
tylermorganwall committed Aug 1, 2023
1 parent 3127db9 commit c46288d
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 56 deletions.
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
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.
Expand Down
71 changes: 52 additions & 19 deletions R/convert_rgl_to_raymesh.R
Original file line number Diff line number Diff line change
@@ -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()) {
Expand All @@ -17,23 +17,28 @@
#'
#'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.")
}
final_scene = list()
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")
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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") {
Expand All @@ -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,
Expand All @@ -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]]
Expand Down
33 changes: 19 additions & 14 deletions R/render_highquality.R
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)))
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
}
Expand Down Expand Up @@ -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, ...)
Expand All @@ -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()
Expand Down
12 changes: 7 additions & 5 deletions R/render_snapshot_software.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
17 changes: 8 additions & 9 deletions R/save_multipolygonz_to_obj.R
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 6 additions & 5 deletions man/convert_rgl_to_raymesh.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions man/render_highquality.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c46288d

Please sign in to comment.