Introduction

The rgl package is used to produce interactive 3-D plots. It contains high-level graphics commands modelled loosely after classic R graphics, but working in three dimensions. It also contains low level structure inspired by (but incompatible with) the grid package.

This document gives an overview. See the help pages for details.

For installation instructions, see the README file in the top level directory of the source tarball rgl_1.3.14.tar.gz (or a later version).

About this document

This document was written in R Markdown, using the knitr package for production. It corresponds to rgl version 1.3.14.

Most of the highlighted function names are HTML links. The internal links should work in any browser; the links to help topics should work if you view the vignette from within the R help system.

The document includes WebGL figures. To view these, you must have Javascript and WebGL enabled in your browser. Some older browsers may not support this – see https://get.webgl.org for tests and links to a discussion.

Basics and High Level Functions

The plot3d function plots points within an RGL window. It is similar to the classic plot function, but works in 3 dimensions.

For example

with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  type="s", col=as.numeric(Species)))

can be used to plot three columns of the iris data. Allowed plot types include "p", "l", "h", "s", meaning points, lines, segments from z=0, and spheres. There’s a lot of flexibility in specifying the coordinates; the xyz.coords function from the grDevices package is used for this.

You can use your mouse to manipulate the plot. The default is that if you click and hold with the left mouse button, you can rotate the plot by dragging it. The right mouse button is used to resize it, and the middle button changes the perspective in the point of view.

If you call plot3d again, it will overwrite the current plot. To open a new graphics window, use open3d.

The other high level function is persp3d to draw surfaces. It is similar to the classic persp function, but with greater flexibility. First, any of x, y or z can be specified using matrices, not just z. This allows parametric surfaces to be plotted. An even simpler specification is possible: x may be a function, in which case persp3d will work out the grid itself. See ?persp3d.function for details. For example, the MASS package estimates Gamma parameters using maximum likelihood in a ?MASS::fitdistr example. Here we show the log likelihood surface.

# This example requires the MASS package
library(MASS)
# from the fitdistr example
set.seed(123)
x <- rgamma(100, shape = 5, rate = 0.1)
fit <- fitdistr(x, dgamma, list(shape = 1, rate = 0.1), lower = 0.001)
loglik <- function(shape, rate) sum(dgamma(x, shape=shape, rate=rate, 
                                           log=TRUE))
loglik <- Vectorize(loglik)
xlim <- fit$estimate[1]+4*fit$sd[1]*c(-1,1)
ylim <- fit$estimate[2]+4*fit$sd[2]*c(-1,1)

mfrow3d(1, 2, sharedMouse = TRUE)
persp3d(loglik, 
        xlim = xlim, ylim = ylim,
        n = 30)
zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0)
next3d()
persp3d(loglik, 
        xlim = xlim, ylim = ylim, zlim = zlim,
        n = 30)

On the left, the whole surface over a range of the parameters; on the right, only the parts of the surface with log likelihood values near the maximum.

Note: this example used the knitr hook functions (see setupKnitr) to insert the scene into this vignette; the previous example used the rglwidget function. We generally recommend the newer rglwidget approach.

Note that both plot3d and persp3d are generic functions, with the following methods defined:

methods(plot3d)
##  [1] plot3d.ashape3d*      plot3d.default*       plot3d.deldir*       
##  [4] plot3d.formula*       plot3d.function*      plot3d.lm*           
##  [7] plot3d.mesh3d*        plot3d.rglbackground* plot3d.rglbboxdeco*  
## [10] plot3d.rglobject*     plot3d.rglscene*      plot3d.rglsubscene*  
## [13] plot3d.rglWebGL*      plot3d.tri*           plot3d.triSht*       
## see '?methods' for accessing help and source code
methods(persp3d)
## [1] persp3d.ashape3d* persp3d.default*  persp3d.deldir*   persp3d.formula* 
## [5] persp3d.function* persp3d.tri*      persp3d.triSht*  
## see '?methods' for accessing help and source code

Adding Graphical Elements

Primitive shapes

Just as we have points and lines in classic graphics, there are a number of low level functions in rgl to add graphical elements to the currently active plot. The “primitive” shapes are those that are native to OpenGL:

Function Description
points3d: adds points
lines3d: adds lines
segments3d: adds line segments
triangles3d: adds triangles
quads3d: adds quadrilaterals

Each of the above functions takes arguments x, y and z, again using xyz.coords for flexibility. They group successive entries as necessary. For example, the triangles3d function takes each successive triple of points as the vertices of a triangle.

You can use these functions to annotate the current graph, or to construct a figure from scratch.

Constructed shapes

rgl also has a number of objects which it constructs from the primitives.

Function Description
text3d, texts3d: adds text
abclines3d: adds straight lines to plot (like abline)
arc3d: adds spherical arcs or spirals to plot
planes3d: adds planes to plot
clipplanes3d: add clipping planes to plot
sprites3d, particles3d: add sprites (fixed shapes or images) to plot
spheres3d: adds spheres
surface3d, terrain3d: a surface (as used in persp3d)
drape3d: drapes lines on a surface or object(s)
shadow3d: projects mesh onto a surface
arrow3d: add an arrow to a scene
pch3d: draw base-style plotting symbols
plotmath3d: used by text3d for math text

Axes and other “decorations”

The following low-level functions control the look of the graph:

Function Description
axes3d, axis3d: add axes to plot
box3d, bbox3d: add box around plot
title3d: add title to plot
mtext3d: add marginal text to plot
decorate3d: add multiple “decorations” (scales, etc.) to plot
aspect3d: set the aspect ratios for the plot
bg3d, bgplot3d: set the background of the scene
show2d: show a 2D plot or image in a 3D scene
legend3d: set a legend for the scene
grid3d: add a reference grid to a graph
thigmophobe3d: choose label positions to avoid overlap
setAxisCallbacks: set user-defined axis annotations

For example, to plot three random triangles, one could use

triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green")
decorate3d()
bg3d("lightgray")
aspect3d(1,1,1)

Besides the *3d functions mentioned above, there are deprecated functions rgl.abclines, rgl.bbox, rgl.bg, rgl.clipplanes, rgl.lines, rgl.linestrips, rgl.planes, rgl.points, rgl.primitive, rgl.quads, rgl.setAxisCallback, rgl.spheres, rgl.sprites, rgl.surface, rgl.texts, rgl.triangles. You should avoid using all of these functions, which do not work properly with the *3d functions and will soon be removed from rgl. See the ?r3d help topic for details.

The function rgl.getAxisCallback provides low-level support for setAxisCallbacks.

Controlling the Look of the Scene

Camera angle

By default when you open a new plot with open3d:

  • The x axis goes from left to right.
  • The y axis goes from near the camera to far away.
  • The z axis goes from down to up.

You can change the camera angle simply by dragging the picture with the mouse.

To set the camera angle programmatically, use view3d. This uses polar coordinates:

  • theta sets the rotation around the vertical axis, in degrees.
  • phi sets the “vertical” rotation around the horizontal axis, from -90 to 90 degrees.

The default angle is roughly theta = 0, phi = -70. Starting from this position:

  • As you increase theta, the graph will spin anticlockwise from your point of view.
  • As you increase phi to 0, you start to look down at the scene from the top. If you increase phi above 0, you continue over and start to see the graph from the “back” (and upside down).

You can also use observer3d to change the camera location using x,y,z coordinates. In particular, increasing the z coordinate lets you zoom out, and decreasing it zooms you in.

One useful approach is to use the mouse to find a nice viewing angle. You can then save it using par3d("userMatrix") and restore the same view later:

myview <- par3d("userMatrix")
# ... later ...
par3d(userMatrix = myview)

Lighting

In most scenes, objects are “lit”, meaning that their appearance depends on their position and orientation relative to lights in the scene. The lights themselves don’t normally show up, but their effect on the objects does.

Use the light3d function to specify the position and characteristics of a light. Lights may be infinitely distant, or may be embedded within the scene. Their characteristics include ambient, diffuse, and specular components, all defaulting to white. The ambient component appears the same from any direction. The diffuse component depends on the angle between the surface and the light, while the specular component also takes the viewer’s position into account.

The deprecated rgl.light function should no longer be used; use light3d instead.

Materials

The mental model used in rgl is that the objects being shown in scenes are physical objects in space, with material properties that affect how light reflects from them (or is emitted by them). These are mainly controlled by the material3d function, or by arguments to other functions that are passed to it.

The material properties that are recognized in calls to material3d are described in detail in the ?material3d help page, and listed in the rgl.material.names variable. All of them can be set except the ones in rgl.material.readonly. Here we give an overview.

Property Default Meaning
color white vector of surface colors to apply to successive vertices for diffuse light
alpha 1 transparency: 0 is invisible, 1 is opaque
lit TRUE whether lighting calculations should be done
ambient black color in ambient light
specular white color in specular light
emission black color emitted by the surface
shininess 50 controls the specular lighting: high values look shiny
smooth TRUE whether shading should be interpolated between vertices
texture NULL optional path to a “texture” bitmap to be displayed on the surface
front, back fill should polygons be filled, or outlined?
size 3 size of points in pixels
lwd 1 width of lines in pixels

Other properties include “texmipmap”, “texmagfilter”, “texminfilter”, “texenvmap”, “fog”, “point_antialias”, “line_antialias”, “depth_mask”, “depth_test”, “polygon_offset”, “margin”, “floating”, “tag” and “blend”; see the help page for details.

There is also a deprecated rgl.material function that works at a lower level; users should avoid it.

Textures

As described in the previous section, one of the material properties is texture, the name of a bitmap file (in .png format) containing an image to be displayed on the surface. This section gives more details about textures.

In OpenGL, each vertex in a polygon may be associated with a particular location in the bitmap. The interior of the polygon interpolates within the bitmap. There are two conventions in rgl functions for specifying these coordinates.

Functions which specify primitives (triangles3d, etc.) accept an optional matrix argument texcoords which gives s (horizontal) and t (vertical) locations within the bitmap in columns with one row per vertex. The coordinates are (0,0) for the lower left, and (1,1) for the upper right. If values outside this range are given, the image repeats, i.e. (1.1, 1.2) would specify the same point in the image as (0.1, 0.2).

Other functions such as surface3d that take matrices for each vertex coordinate accept texture coordinates as matrices as well, in arguments texture_s and texture_t.

For example, the following code displays four copies of a 2D plot on a quad, because the texture coordinates run from 0 to 2 in both s and t:

filename <- tempfile(fileext = ".png")
png(filename = filename)
plot(rnorm(1000), rnorm(1000))
safe.dev.off()
## agg_png 
##       2
## null 
##   11
xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1))
quads3d(xyz, texture = filename, texcoords = xyz[,c(1, 3)]*2, 
        col = "white", specular = "black")

Some other notes:

  • The color in quads3d() above was specified to be white. By default, the colors in the bitmap will modify the color of the surface. If col is black (a common default), you won’t see anything, so a warning may be issued.
  • You usually don’t want specular reflections (which show up as glare). Setting specular to black prevents those.
  • The material property "texmode" allows texture colors to be used differently. The default is "modulate", where the texture values combine multiplicatively with the underlying values.
  • Another aspect of how the bitmap is handled is controlled by the material property "textype". The default is "rgb", which takes the red-green-blue colors from the bitmap and uses them to modify the corresponding colors in the polygon.
  • Other possibilities for "textype" and "texmode" are described in the material3d help page.
  • The other "tex*" material properties control how the interpolation within the image is done.
  • Modern OpenGL supports 1- and 3-dimensional textures; these are not currently supported in rgl.

Fonts

rgl uses the same ideas as base graphics for drawing text: there are font families named "sans", "serif", and "mono" for drawing text of those types. In rgl, the "symbol" family is not supported.

New font families can be defined using the low-level function rglFonts, or more simply using the higher level function rglExtrafonts. The latter function requires the extrafont package to be installed.

par3d: Miscellaneous graphical parameters

The par3d function, modelled after the classic graphics par function, sets or reads a variety of different rgl internal parameters, listed in the rgl.par3d.names variable. All of them can be set except the ones in rgl.par3d.readonly. Some parameters are completely read-only; others are fixed at the time the window is opened, and others may be changed at any time.

Name Changeable? Description
antialias fixed Amount of hardware antialiasing
cex Default size for text
family Device-independent font family name; see ?text3d
font Integer font number
useFreeType Should FreeType fonts be used if available?
fontname read-only System-dependent font name set by rglFonts
FOV Field of view, in degrees. Zero means isometric perspective
ignoreExtent Should rgl ignore the size of new objects when computing the bounding box?
skipRedraw Should rgl suppress updates to the display?
maxClipPlanes read-only How many clip planes can be defined?
modelMatrix read-only The OpenGL ModelView matrix; partly set by view3d
projMatrix read-only The OpenGL Projection matrix
bbox read-only Current bounding-box of the scene
viewport Dimensions in pixels of the scene within the window
windowRect Dimensions in pixels of the window on the whole screen
listeners Which subscenes respond to mouse actions in the current one
mouseMode What the mouse buttons do. See “mouseMode”
observer read-only The position of the observer; set by observer3d
scale Rescaling for each coordinate; see aspect3d
zoom Magnification of the scene

The deprecated rgl.viewpoint function should not be used.

Default settings

The r3dDefaults list and the getr3dDefaults function control defaults in new windows opened by open3d.
The function looks for the variable in the user’s global environment, and if not found there, finds the one in the rgl namespace. This allows the user to override the default settings for new windows.

Once found, the r3dDefaults list provides initial values for par3d parameters, as well as defaults for material3d and bg3d in components "material" and "bg" respectively.

Meshes: Constructing Shapes

rgl includes a number of functions to construct and display various solid shapes. These generate objects of class "shape3d", "mesh3d" or "shapelist3d". The details of the classes are described below. We start with functions to generate them.

Specific solids

These functions generate specific shapes. Optional arguments allow attributes such as color or transformations to be specified.

Function Description
tetrahedron3d, cube3d, octahedron3d, dodecahedron3d, icosahedron3d: Platonic solids
cuboctahedron3d, oh3d: other solids
cols <- rainbow(7)
layout3d(matrix(1:16, 4,4), heights=c(1,3,1,3))
text3d(0,0,0,"tetrahedron3d"); next3d()
shade3d(tetrahedron3d(col=cols[1])); next3d()
text3d(0,0,0,"cube3d"); next3d()
shade3d(cube3d(col=cols[2])); next3d()
text3d(0,0,0,"octahedron3d"); next3d()
shade3d(octahedron3d(col=cols[3])); next3d()
text3d(0,0,0,"dodecahedron3d"); next3d()
shade3d(dodecahedron3d(col=cols[4])); next3d()
text3d(0,0,0,"icosahedron3d"); next3d()
shade3d(icosahedron3d(col=cols[5])); next3d()
text3d(0,0,0,"cuboctahedron3d"); next3d()
shade3d(cuboctahedron3d(col=cols[6])); next3d()
text3d(0,0,0,"oh3d"); next3d()
shade3d(oh3d(col=cols[7]))

A very large collection of polyhedra is contained in the Rpolyhedra package.

Generating new shapes

These functions generate new shapes:

Function Description
cylinder3d: generate a tube or cylinder
polygon3d: generate a flat polygon by triangulation
extrude3d: generate an “extrusion” of a polygon
turn3d: generate a solid of rotation
ellipse3d: generate an ellipsoid in various ways
mesh3d: generate a shape from indexed vertices
shapelist3d: generate a shape by combining other shapes
as.mesh3d: a generic function; see below

A related function is triangulate, which takes a two dimensional polygon and divides it up into triangles using the “ear-clipping” algorithm.

The generic function as.mesh3d is provided to allow data structures produced by other code to be converted to mesh structures. Currently the following classes are supported:

Class Package Description
deldir deldir Delaunay triangulations of irregular point clouds
triSht interp Also Delaunay triangulations
tri tripack Generalized Delaunay triangulations
ashape3d alphashape3d Alpha-shapes
rglId rgl rgl object identifiers

The checkDeldir function checks that a compatible version of the deldir package is installed.

The default as.mesh3d.default method is a simple way to construct a mesh from a matrix of vertices; it can use mergeVertices (which can also be used on its own) to merge repeated vertices within the matrix, allowing addNormals to be used to give a smooth appearance.

The as.tmesh3d generic is a variation that guarantees the resulting object will have no quad entries.

Functions tmesh3d, qmesh3d are now obsolete; use mesh3d instead.

The underlying class structure for shapes

"shape3d" is the basic abstract type. Objects of this class can be displayed by shade3d (which shades faces), wire3d (which draws edges), or dot3d (which draws points at each vertex.)

"mesh3d" is a descendant type. Objects of this type contain the following fields:

Field Meaning
vb A 4 by n matrix of vertices in homogeneous coordinates. Each column is a point.
ip (optional) A vector of vertex indices for points.
is (optional) A 2 by s matrix of vertex indices. Each column is a line segment.
it (optional) A 3 by t matrix of vertex indices. Each column is a triangle.
ib (optional) A 4 by q matrix of vertex indices. Each column is a quadrilateral.
material (optional) A list of material properties.
normals (optional) A matrix of the same shape as vb, containing normal vectors at each vertex.
texcoords (optional) A 2 by n matrix of texture coordinates corresponding to each vertex.
values (optional) A vector of length n holding values at each vertex
meshColor (optional) A text value indicating how colors and texture coordinates should be interpreted.
tags (optional) A vector added by some functions (e.g. clipMesh3d) to relate output parts to input parts.

Contouring and clipping shapes

These functions compute and plot contours of functions on surfaces, or clip objects along a contour of a function.

Function Description
contourLines3d: draw contour lines on surface
filledContour3d: fill between contours on surface
clipMesh3d: clip mesh object using curved boundary
clipObj3d: clip general object using curved boundary

Manipulating shapes

These functions manipulate and modify mesh objects:

Function Description
addNormals: add normal vectors to make a shape look smooth
subdivision3d: add extra vertices to make it look even smoother
merge: merge mesh objects
facing3d: subset of mesh facing “up”
getBoundary3d: get the boundary of a mesh object

The individual steps in subdivision3d are also available: deform.mesh3d, divide.mesh3d, normalize.mesh3d. These are mainly intended for internal use.

Multi-figure Layouts

rgl has several functions to support displaying multiple different “subscenes” in the same window. The high level functions are

Function Description
mfrow3d: Multiple figures (like par(“mfrow”)
layout3d: Multiple figures (like layout)
next3d: Move to the next figure (like plot.new or frame)
subsceneList: List all the subscenes in the current layout
clearSubsceneList: Clear the current list and revert to the previous one

There are also lower level functions.

Function Description
newSubscene3d: Create a new subscene, with fine control over what is inherited from the parent
currentSubscene3d: Report on the active subscene
subsceneInfo: Get information on current subscene
useSubscene3d: Make a different subscene active
addToSubscene3d, delFromSubscene3d: Add objects to a subscene, or delete them
gc3d: Do “garbage collection”: delete objects that are not displayed in any subscene

Documents with rgl Scenes

The rgl package can produce output that can be embedded in other documents. The recommended way to do this has changed several times over the years. We will start with the current recommendation, then list older methods.

Currently the best way to embed an rgl scene in a document is to produce the document in HTML using R Markdown. Early in the document, you should have code like this in one of the setup code chunks:

```{r echo=FALSE, include=FALSE}
library(rgl)
setupKnitr(autoprint = TRUE)
```

The call to setupKnitr() will install a number of hooks and set options in knitr so that rgl code is handled properly. The autoprint = TRUE argument makes rgl act in the document almost the same way it would act in the console, or the way base graphics are handled by knitr: If you print the value of high level rgl functions, a plot will be inserted into the output, but maybe only after low level modifications to it are complete. For example, this code block prints both triangles and spheres in a single plot at the end:

xyz <- matrix(rnorm(27), ncol = 3)
triangles3d(xyz, col = rainbow(9))
spheres3d(xyz, col = rainbow(9), radius = 0.1)

There are a few differences if you have a complicated situation:

  • The mechanism depends on the result of the rgl function calls being automatically printed. If the calls are in a loop or other code block where automatic printing doesn’t happen, you’ll need some trickery to get things to print. For example, this will print three plots:
plots <- NULL
for (i in 1:3) {
  plot3d(rnorm(10), rnorm(10), rnorm(10))
  plots <- htmltools::tagList(plots, rglwidget())
  close3d()
}
plots
  • It also depends on the fact that rgl functions return results using lowlevel() or highlevel() to mark which kind of plot they are. If you are using a function from another package to produce the plot, you may need to insert an explicit call to one of those to get it to print. Use lowlevel() if the function just modifies an existing plot, highlevel() if it starts a new one. For example,
foreignHigh()   # Produces a high level plot, but doesn't return
                # an appropriate value
highlevel()
foreignLow()    # Modifies the previous plot
lowlevel()

This should display the output at the end of the code chunk, when modifications are assumed complete.

Producing PDF output

While some PDF previewers support interactive 3D graphics, most don’t. To produce a screenshot of an rgl scene in an R Markdown document with PDF output, simply follow the directions given above. The auto-printing will detect PDF output and use snapshot3d to produce a PNG file to insert. (See below if you want to insert a different format of graphic.)

If you really need interactive output, see the writeASY function.

Manual insertion of plots

You may not want to use the setupKnitr(autoprint = TRUE) method described above. It is very new, and may still have bugs; you may have an older document and not want to edit it to work that way.

In this case, you can insert plots manually. Use setup code

```{r echo=FALSE, include=FALSE}
library(rgl)
setupKnitr()
```

and call rglwidget() at top level whenever you want to insert a plot.

There are a couple of other differences in default behaviour if you are not using autoprint:

  • By default, each code chunk continues the rgl scene from earlier chunks. You’ll need an explicit open3d call to get a clean window.

  • Also by default, the rgl window is not closed at the end of the chunk. This probably doesn’t matter, but you may find you run out of memory if your scenes are really big.

Older methods

The original way to insert an rgl scene in a document was to use the deprecated writeWebGL function to write HTML code to insert in a document. Later, Sweave and knitr hooks were added. These are no longer supported, and you should update old documents to use the newer methods. If you are reading documents that suggest using those methods, let the author know they need updating!

Utility Functions

User interaction

By default, rgl detects and handles mouse clicks within your scene, and uses these to control its appearance. You can find out the current handlers using the following code:

par3d("mouseMode")
##        none        left       right      middle       wheel 
##      "none" "trackball"      "zoom"       "fov"      "pull"

The labels c("left", "right", "middle") refer to the buttons on a three button mouse, or simulations of them on other mice. "wheel" refers to the mouse wheel, and "none" refers to actions that take place when the mouse is moved without pressing any button.

The button actions generally correspond to click and drag operations. Possible values for “mouseMode” for the mouse pointer or wheel are as follows:

Mode Description
"none" No action
"trackball" The mouse acts as a virtual trackball. Clicking and dragging rotates the scene
"xAxis", "yAxis", "zAxis" Like "trackball", but restricted to rotation about one axis
"polar" The mouse affects rotations by controlling polar coordinates directly
"selecting" The mouse is being used by the select3d function
"zoom" The mouse zooms the display
"fov" The mouse affects perspective by changing the field of view
"pull" Rotating the mouse wheel towards the user “pulls the scene closer”
"push" The same rotation “pushes the scene away”
"user" A user action set by setUserCallbacks, rgl.setMouseCallbacks, rgl.setWheelCallback. Use rgl.getMouseCallbacks and rgl.getWheelCallback to retrieve.

The following functions make use of the mouse for selection within a scene.

Function Description
identify3d: like the classic graphics identify function
select3d: returns a function that tests whether a coordinate was selected
selectpoints3d: selects from specific objects
hover3d: displays “hover” info about points

selectionFunction3d produces the selection function from information about the projection and mouse selection region; it is used internally in the functions above.

The deprecated rgl.select3d function is an obsolete version of select3d, and rgl.select is a low-level support function.

Animations

rgl has several functions that can be used to construct animations. These are based on functions that update the scene according to the current real-world time, and repeated calls to those. The functions are:

Function Description
play3d: Repeatedly call the update function
spin3d: Update the display by rotating at a constant rate
par3dinterp: Compute new values of some par3d parameters by interpolation over time

See the movie3d function for a way to output an animation to a file on disk.
Animations are not currently supported in the HTML written by rglwidget, though the playwidget function provides equivalent functionality.

Integration with TCL/TK

There are three functions in rgl that support control of an rgl scene using the TCL/TK framework.

Function Description
tkspin3d: Set up buttons in a window to control a scene
tkspinControl: Embed the control buttons in a separate TCL/TK frame
tkpar3dsave: Create a dialog to interactively save mouse actions

These functions were formerly contained (without the tk prefixes on their names) in the tkrgl package. That package is now deprecated.

Exporting and importing scenes

rgl contains several functions to write scenes to disk for use by other software, or to read them in.

In order from highest fidelity to lowest, the functions are:

Function Description
scene3d: Save a scene to an R variable, which can be saved and reloaded
rglwidget: Prints as HTML and Javascript to display a scene in a web browser. (See also User Interaction in WebGL.)
writeASY: Write files for Asymptote
writePLY: Write PLY files (commonly used in 3D printing)
readOBJ, writeOBJ: Read or write OBJ files (commonly used in 3D graphics)
readSTL, writeSTL: Read or write STL files (also common in 3D printing)
as.rglscene: Generic function, no methods in rgl

The rgl2gltf package can read or write GLTF and GLB files. It includes an as.rglscene method to convert GLTF objects to rgl scenes. The code in rgl’s Buffer R6 class is based on the GLTF format. It is used by rglwidget to make output webpages somewhat smaller than they were previously.

There are also functions to save snapshots or other recordings of a scene, without any 3D information being saved:

Function Description
snapshot3d: Save a PNG file bitmap of the scene
rgl.postscript: Save a Postscript, LaTeX, PDF, SVG or PGF vector rendering of the scene
movie3d: Save a series of bitmaps to be assembled into a movie
rgl.pixels: Obtain pixel-level information about the scene in an R variable
rgl.Sweave: Driver function for inserting a snapshot into a Sweave document.
hook_rgl, hook_webgl: knitr hook functions for inserting images into a document.
setupKnitr: Function to set up knitr hooks

The rgl.snapshot function is a low level version of snapshot3d(); it requires that the rgl display be onscreen and copies from there. snapshot3d() tries to use the webshot2 package so it will work even with no display. The functions rgl.Sweave.off, Sweave.snapshot are involved in Sweave processing and not normally called by users.

Default display

There are two ways in which rgl scenes are normally displayed within R. The older one is in a dedicated window. In Unix-alikes this is an X11 window; it is a native window in Microsoft Windows. On macOS, the XQuartz system (see https://www.xquartz.org) needs to be installed to support this.

To suppress this display, set options(rgl.useNULL = TRUE) before opening a new rgl window. See the help page for the rgl.useNULL function for how to set this before starting R.

The newer way to display a scene is by using WebGL in a browser window or in the Viewer pane in RStudio. To select this, set options(rgl.printRglwidget = TRUE). Each operation that would change the scene will return a value which triggers a new WebGL display when printed.

Working with WebGL scenes

You should use the following scheme for exporting a scene to a web page. There’s also an older scheme, which is no longer supported.

The recommended approach works with the htmlwidgets framework (see http://www.htmlwidgets.org/). In an R Markdown document in knitr, use the rglwidget function. (You can also use chunk option webgl=TRUE; we recommend the explicit use of rglwidget.) This approach also allows display of rgl scenes in RStudio. Besides rgl scenes, various controls for them can be displayed, and there are a few utility functions that can be useful:

Function Description
propertyControl: set individual properties
clipplaneControl: control a clipping plane
subsetControl: control which objects are displayed
ageControl: “age” vertices of an object
vertexControl: control properties of vertices
par3dinterpControl: WebGL control like par3dinterp
playwidget: display and automate controls
toggleWidget: display a button to toggle some items
%>%: magrittr pipe
figHeight, figWidth: Dimensions of figures in R Markdown document
rglShared: share data using crosstalk package
rglMouse: change mouse mode in RGL scene
asRow: arrange multiple objects in an HTML display
getWidgetId: get the elementId from a widget

These functions work with the above scheme in Shiny apps:

Function Description
sceneChange: used in Shiny for large scene changes
shinyGetPar3d, shinySetPar3d: get or set par3d values from Shiny
shinyResetBrush: reset the mouse brush in Shiny

The selectionFunction3d function is also likely to be involved in mouse interactions when using Shiny.

Some functions are mainly for internal use: elementId2Prefix, playwidgetOutput, renderPlaywidget, rglwidgetOutput, renderRglwidget, registerSceneChange. More details are given in the vignette User Interaction in WebGL. The functions lowlevel, highlevel, rglId are also for internal use, marking function results for automatic printing. Finally, the function setUserShaders allows you to use hand-written shaders in WebGL, and getShaders allows you to see what shader would be used.

Working with the scene

rgl maintains internal structures for all the scenes it displays. The following functions allow users to find information about them and manipulate them. In cases where there are both *3d and rgl.* versions of functions, most users should use the *3d version: the rgl.* functions are more primitive and are mainly intended for internal use.

Function Description
open3d: open a new window
close3d: close the current window
cur3d: id of the active device
set3d: set a particular device to be active
pop3d: delete objects from the scene
clear3d: delete all objects of certain classes
ids3d: ids, types and tags of current objects
tagged3d: find tags or objects with tags

Some of these functions have alternate names for back compatibility:
rgl.cur, rgl.ids, rgl.pop. Either name will work, but the *3d version is recommended for new code. Some have deprecated versions: rgl.clear, rgl.set. Those should not be called.

These functions are mainly intended for programming, and have no corresponding *3d counterparts:

Function Description
rgl.bringtotop: bring the current window to the top
rgl.dev.list: ids of all active devices
rgl.attrib, rgl.attrib.info, rgl.attrib.count: attributes of objects in the scene
rgl.projection: return information about the current projection
rgl.user2window, rgl.window2user: convert between coordinates in the current projection

The as.triangles3d generic function is intended to extract coordinates in a form suitable for passing to triangles3d. Currently a method is provided for rglId objects.

In addition to these, there are some deprecated functions which should not be called: rgl.init, rgl.open, rgl.close, rgl.quit.

Working with 3-D vectors

Most rgl functions work internally with “homogeneous” coordinates. In this system, 3-D points are represented with 4 coordinates, generally called (x, y, z, w). The corresponding Euclidean point is (x/w, y/w, z/w), if w is nonzero; zero values of w correspond to “points at infinity”. The advantage of this system is that affine transformations including translations and perspective shifts become linear transformations, with multiplication by a 4 by 4 matrix.

rgl has the following functions to work with homogeneous coordinates:

Function Description
asEuclidean, asHomogeneous: convert between homogeneous and Euclidean coordinates when x, y and z are columns
asEuclidean2, asHomogeneous2: convert when x, y and z are rows
rotate3d, scale3d, translate3d: apply a transformation
transform3d: apply a general transformation
rotationMatrix, scaleMatrix, translationMatrix: compute the transformation matrix
identityMatrix: return a 4 x 4 identity matrix
projectDown: a 3D to 2D projection down a vector

There is also a function GramSchmidt, mainly for internal use: it does a Gram-Schmidt orthogonalization of a 3x3 matrix, with some specializations for its use in cylinder3d.

Working with other packages

Sometimes it may be convenient to interactively rotate a scene to a particular view, then display it in lattice or base graphics. The rglToLattice and rglToBase functions support this.

For example, we first display the volcano data in rgl:

persp3d(volcano, col = "green")

This display is interactive, but we can reproduce the initial view using the lattice wireframe or base graphics persp functions:

# Only evaluated if the lattice & orientlib packages are installed
lattice::wireframe(volcano, col = "green", 
           screen = rglToLattice())

Volcano in latticegraphics.

angles <- rglToBase()
persp(volcano, col = "green", shade = TRUE,
      theta = angles$theta, phi = angles$phi)

Volcano in basegraphics.

Note that the orientlib package must be available for these functions to work.

Creating pkgdown websites

The “Using RGL in pkgdown web sites” vignette describes how to use rgl in a pkgdown web site. The utility function in_pkgdown_example can be used to detect that pkgdown is being used.

Working with testthat

The testthat package is widely used for unit tests in packages. Such tests are hard to write with rgl, because the output is visual and interactive rather than a simple value. The expect_known_scene, compare_proxy.mesh3d and all.equal.mesh3d functions help with this by removing system-dependent features of rgl output.

Working with Javascript

The WebGL displays created using rglwidget rely on a large body of Javascript code included in this package. To help in development of this code, the makeDependency function was written. It may be useful in other packages that include Javascript.

Other functions and objects

This section is for miscellaneous functions and objects that don’t fall in any of the other categories in this document.

The setGraphicsDelay function is designed to work around what appears to be a bug on macOS: if a standard plot window is opened too quickly after an rgl window, R can crash. This function inserts a one second delay when it appears to be needed.

The gltfTypes vector contains constants used in OpenGL and glTF.

Warning: Work in Progress!

This vignette is always a work in progress. Some aspects of the rgl package are not described, or do not have examples. There may even be functions that are missed completely, if the following list is not empty:

## [1] "rgl.incrementID" "safe.dev.off"    "textureSource"

Index of Functions

The following functions and constants are described in this document:

%>%   deldir   mtext3d   rgl.material.readonly   shinyResetBrush  
abclines3d   delFromSubscene3d   newSubscene3d   rgl.par3d.names   shinySetPar3d  
addNormals   divide.mesh3d   next3d   rgl.par3d.readonly   show2d  
addToSubscene3d   dodecahedron3d   normalize.mesh3d   rgl.pixels   snapshot3d  
ageControl   dot3d   observer3d   rgl.postscript   spheres3d  
all.equal.mesh3d   drape3d   observer3d   rgl.projection   spin3d  
arc3d   elementId2Prefix   octahedron3d   rgl.select   sprites3d  
arrow3d   ellipse3d   oh3d   rgl.setMouseCallbacks   subdivision3d  
as.mesh3d   expect_known_scene   open3d   rgl.setWheelCallback   subsceneInfo  
as.mesh3d.default   extrude3d   par3d   rgl.snapshot   subsceneList  
as.rglscene   facing3d   par3dinterp   rgl.Sweave   subsetControl  
as.tmesh3d   figHeight   par3dinterpControl   rgl.Sweave.off   surface3d  
as.triangles3d   figWidth   particles3d   rgl.useNULL   Sweave.snapshot  
asEuclidean   filledContour3d   pch3d   rgl.user2window   tagged3d  
asEuclidean2   gc3d   persp3d   rgl.window2user   terrain3d  
ashape3d   getBoundary3d   pipe   rglExtrafonts   tetrahedron3d  
asHomogeneous   getr3dDefaults   planes3d   rglFonts   text3d  
asHomogeneous2   getShaders   play3d   rglId   texts3d  
aspect3d   getWidgetId   playwidget   rglMouse   thigmophobe3d  
asRow   gltfTypes   playwidgetOutput   rglShared   title3d  
axes3d   GramSchmidt   plot3d   rglToBase   tkpar3dsave  
axis3d   grid3d   plotmath3d   rglToLattice   tkspin3d  
bbox3d   highlevel   points3d   rglwidget   tkspinControl  
bg3d   hook_rgl   polygon3d   rglwidgetOutput   tmesh3d  
bgplot3d   hook_webgl   pop3d   rotate3d   toggleWidget  
box3d   hover3d   projectDown   rotationMatrix   transform3d  
Buffer   icosahedron3d   propertyControl   scale3d   translate3d  
checkDeldir   identify3d   qmesh3d   scaleMatrix   translationMatrix  
clear3d   identityMatrix   quads3d   scene3d   tri  
clearSubsceneList   ids3d   r3dDefaults   sceneChange   triangles3d  
clipMesh3d   in_pkgdown_example   readOBJ   segments3d   triangulate  
clipObj3d   layout3d   readSTL   select3d   triSht  
clipplaneControl   legend3d   registerSceneChange   selectionFunction3d   turn3d  
clipplanes3d   light3d   renderPlaywidget   selectpoints3d   useSubscene3d  
close3d   lines3d   renderRglwidget   set3d   vertexControl  
compare_proxy.mesh3d   lowlevel   rgl.attrib   setAxisCallbacks   view3d  
contourLines3d   makeDependency   rgl.attrib.count   setGraphicsDelay   view3d  
cube3d   material3d   rgl.attrib.info   setupKnitr   wire3d  
cuboctahedron3d   merge.mesh3d   rgl.bringtotop   setUserCallbacks   writeASY  
cur3d   mergeVertices   rgl.dev.list   setUserShaders   writeOBJ  
currentSubscene3d   mesh3d   rgl.getAxisCallback   shade3d   writePLY  
cylinder3d   mfrow3d   rgl.getMouseCallbacks   shadow3d   writeSTL  
decorate3d   mouseMode   rgl.getWheelCallback   shapelist3d  
deform.mesh3d   movie3d   rgl.material.names   shinyGetPar3d