9  3D Visualisation

Numbers are useful; actually seeing the mesh is better. This chapter covers two routes: rgl (Adler, Murdoch, et al. 2024) for interactive exploration in RStudio (spin it with the mouse, zoom in, inspect details), and rayshader (Morgan-Wall 2024) for rendering publication-quality static images.

Both work on mesh_vcg from Reading OBJ and STL Meshes.

9.1 Interactive 3D with rgl

shade3d() opens an OpenGL window where you can rotate and zoom with the mouse. Takes one line:

library(rgl)
open3d()
shade3d(mesh_vcg, col = "#C0C0C0", alpha = 0.9)
bg3d("white")
axes3d()
title3d("Aerial DWG — Translated Mesh")

9.1.1 Embedding in HTML Output

rgl windows are interactive in RStudio but don’t embed in HTML documents on their own. rglwidget() wraps the scene in a self-contained WebGL widget that works in any browser:

# Add this once at the top of your document (setup chunk)
knitr::knit_hooks$set(webgl = rgl::hook_webgl)

open3d()
shade3d(mesh_vcg, col = "#4A90D9", alpha = 0.85)
rglwidget()
Note

The WebGL widget is fully self-contained in the rendered HTML. Readers can rotate and zoom without a running R server. It does require a modern browser (Chrome, Firefox, Safari, Edge all work fine).

9.2 Colouring by Height

Map vertex Z-values to a colour ramp to reveal the model’s vertical structure instantly. Blues for low, reds for high:

z_vals <- mesh_vcg$vb[3, ]
z_norm <- (z_vals - min(z_vals)) / diff(range(z_vals))   # 0–1

cols      <- colorRampPalette(c("#2166ac", "#92c5de", "#f7f7f7",
                                 "#f4a582", "#d6604d"))(100)
vert_cols <- cols[ceiling(z_norm * 99) + 1]

open3d()
shade3d(mesh_vcg, col = vert_cols)
rglwidget()

9.3 Rendered Images with rayshader

rayshader renders the active rgl scene with ray-traced lighting and ambient occlusion, great for reports and presentations. The output is a PNG file.

library(rayshader)

vertices  <- t(mesh_vcg$vb[1:3, ])
triangles <- t(mesh_vcg$it)

open3d()
triangles3d(vertices[triangles[, 1], ],
            vertices[triangles[, 2], ],
            vertices[triangles[, 3], ],
            col = "steelblue")

render_snapshot(filename    = "aerial_render.png",
                width       = 1200,
                height      = 900,
                title_text  = "Aerial DWG — Rayshader Render",
                title_color = "white",
                title_size  = 24,
                clear       = TRUE)

Include the render in your Quarto document with a standard image link:

![Aerial DWG rendered with rayshader](aerial_render.png)

9.4 Depth of Field

Add a depth-of-field effect to emphasise the model’s 3D structure in the output image, works especially well for tall structures:

render_depth(focus       = 0.7,
             focallength = 200,
             filename    = "aerial_dof.png")

9.5 Quick Comparison: rgl vs. rayshader

rgl rayshader
Output Interactive HTML widget Static PNG
Use for Exploration, dashboards Reports, presentations
Render time Instant Seconds–minutes
WebGL support Yes (via rglwidget()) No