---
title: "rgl Overview"
author: "Duncan Murdoch"
date: "`r format(Sys.time(), '%B %d, %Y')`"
output:
  rmarkdown::html_vignette:
    toc: yes
    fig_width: 5
    fig_height: 5
vignette: >
  %\VignetteIndexEntry{rgl Overview} 
  %\VignetteEngine{knitr::rmarkdown}
---

```{r setup, echo=FALSE, results="asis"}
source("setup.R")
set.seed(123)
```



## 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 the `grid` package.

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

### About this document

This document was written in R Markdown, using the `knitr` package
for production.  It corresponds to rgl version 
`r packageVersion("rgl")`.

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 http://get.webgl.org for tests
and links to a discussion.


## Basics and High Level Functions

The `r indexfns("plot3d")` function
plots points within an rgl window.  It is similar to the classic 
`r linkfn("plot", pkg="graphics")` function,
but works in 3 dimensions.

For example
```{r plot3d, rgl=TRUE}
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 
`r linkfn("xyz.coords", pkg = "grDevices")` 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 `r linkfn("plot3d")` again, it will overwrite the current plot.
To open a new graphics window, use `r linkfn("open3d")`.
 
The other high level function is `r indexfns("persp3d")` to draw surfaces.
It is
similar to the classic `r linkfn("persp", pkg = "graphics")`
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 
`r linkfn("persp3d.function", text="?persp3d.function", pkg="rgl")`
for details.  For example, the `MASS` package estimates
Gamma parameters using maximum likelihood in a 
`r linkfn("fitdistr", text="?MASS::fitdistr", pkg="MASS")` example.
Here we show the log likelihood surface. 
```{r persp3d, rgl=TRUE, fig.height=3, fig.width=6}
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.

## Adding Graphical Elements

### Primitive shapes

Just as we have `r linkfn("points", pkg="graphics")` and 
`r linkfn("lines", pkg="graphics")` 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:

----------------------------- | -----------
`r indexfns("points3d")`:     | adds points
`r indexfns("lines3d")`:      | adds lines
`r indexfns("segments3d")`:   | adds line segments
`r indexfns("triangles3d")`:  | adds triangles
`r indexfns("quads3d")`:      | adds quadrilaterals

Each of the above functions takes arguments `x`, `y` and `z`, again
using `r linkfn("xyz.coords", pkg="grDevices")` for flexibility.
They group successive entries
as necessary.  For example, the `r linkfn("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.

----------------------------- | -----------
`r indexfns(c("text3d", "texts3d"))`: | adds text
`r indexfns("abclines3d")`:   | adds straight lines to plot (like `abline`)
`r indexfns("planes3d")`:     | adds planes to plot
`r indexfns("clipplanes3d")`: | add clipping planes to plot
`r indexfns(c("sprites3d", "particles3d"))`: | add sprites (fixed shapes or images) to plot
`r indexfns("spheres3d")`:    | adds spheres
`r indexfns(c("surface3d", "terrain3d"))`:    | a surface (as used in `r linkfn("persp3d")`)

### Axes and other "decorations"

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

------------------------------------ | -----------
`r indexfns(c("axes3d", "axis3d"))`: | add axes to plot
`r indexfns(c("box3d", "bbox3d"))`:               | add box around plot
`r indexfns("title3d")`:             | add title to plot
`r indexfns("mtext3d")`:             | add marginal text to plot
`r indexfns("decorate3d")`:          | add multiple "decorations" (scales, etc.) to plot
`r indexfns("aspect3d")`:            | set the aspect ratios for the plot
`r indexfns(c("bg3d", "bgplot3d"))`: | set the background of the scene
`r indexfns("legend3d")`:            | set a legend for the scene
`r indexfns("grid3d")`:              | add a reference grid to a graph

For example, to plot three random triangles, one could use
```{r rgl=TRUE, fig.width=3, fig.height=3}
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 even lower-level
functions 
`r indexfns(c("rgl.primitive", "rgl.points", "rgl.linestrips", "rgl.lines", "rgl.triangles",
"rgl.quads", "rgl.texts", "rgl.abclines", "rgl.planes", "rgl.bg",
"rgl.clipplanes", "rgl.bbox", "rgl.spheres", "rgl.sprites", "rgl.surface"))`.  
You should avoid using these functions, which do not
work well with the higher level `*3d` functions.  See the 
`r linkfn("r3d", text="?r3d", pkg="rgl")` help
topic for details.

## Controlling the Look of the Scene

### 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 `r indexfns("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 `r indexfns("rgl.light")` function is a lower-level
function with different defaults; users should normally
use `r linkfn("light3d")`.

### 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 `r indexfns("material3d")` function,
or by arguments to other functions that are passed to it.

The material properties that can be set by calls to `material3d` are
described in detail in the 
`r linkfn("material3d", text="?material3d", pkg="rgl")` help page.
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", and "depth\_test"; 
see the help page for details.

There is also an `r indexfns("rgl.material")` function that works
at a lower level; users should normally avoid it.

### par3d:  Miscellaneous graphical parameters

The `r indexfns("par3d")` function, modelled after the classic
graphics `r linkfn("par", pkg="graphics")` function, sets or reads 
a variety of different `rgl` internal
parameters.  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 `r linkfn("text3d", text="?text3d", pkg="rgl")`
font        |       | Integer font number
useFreeType |       | Should FreeType fonts be used if available?
fontname    | read-only | System-dependent font name set by `r indexfns("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 `r indexfns("view3d")` or the obsolete `r indexfns("rgl.viewpoint")`
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 `r linkfn("mouseMode", '<code>"mouseMode"</code>')`
observer    | read-only | The position of the observer; set by `r indexfns("observer3d")`
scale       |           | Rescaling for each coordinate; see `r linkfn("aspect3d")`
zoom        |           | Magnification of the scene

### Default settings

The `r indexfns("r3dDefaults")` list and the `r indexfns("getr3dDefaults")` 
function control defaults in new windows opened by `r linkfn("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 `r linkfn("par3d")` parameters, as well as defaults for `r linkfn("material3d")` and `r linkfn("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 colour or transformations to be specified.

------------------------------------ | -----------
`r indexfns(c("tetrahedron3d", "cube3d", "octahedron3d", "dodecahedron3d", "icosahedron3d"))`: | Platonic solids
`r indexfns(c("cuboctahedron3d", "oh3d"))`:             | other solids

```{r results="hide",rgl=TRUE}
open3d()
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]))
```

### Generating new shapes 

These functions generate new shapes:

------------------------------------ | -----------
`r indexfns("cylinder3d")`: | generate a tube or cylinder
`r indexfns("polygon3d")`:  | generate a flat polygon by triangulation
`r indexfns("extrude3d")`:  | generate an "extrusion" of a polygon
`r indexfns("turn3d")`:     | generate a solid of rotation
`r indexfns("ellipse3d")`:  | generate an ellipsoid in various ways
`r indexfns(c("tmesh3d", "qmesh3d"))`:  | generate a shape from vertices and faces
`r indexfns("shapelist3d")`: | generate a shape by combining other shapes

A related function is `r indexfns("triangulate")`, which takes a
two dimensional polygon and divides it up into triangles using the 
"ear-clipping" algorithm.

### The underlying class structure for shapes

`"shape3d"` is the basic abstract type.  Objects of this class can be
displayed by `r indexfns("shade3d")` (which shades faces), 
`r indexfns("wire3d")` (which draws edges), or `r indexfns("dot3d")`
(which draws points at each vertex.)  Note that `wire3d` and `dot3d`
only work within R; in HTML output from `r linkfn("writeWebGL")` only
`shade3d` is supported.

`"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.
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.

### Manipulating shapes

The final set of functions manipulate and modify mesh objects:

------------------------------------ | -----------
`r indexfns("addNormals")`: | add normal vectors to make a shape look smooth
`r indexfns("subdivision3d")`: | add extra vertices to make it look even smoother

## Multi-figure Layouts

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

------------------------------------ | -----------
`r indexfns("mfrow3d")`:  | Multiple figures (like `r linkfn("par", text = 'par("mfrow")', pkg="graphics")`
`r indexfns("layout3d")`: | Multiple figures (like `r linkfn("layout", pkg="graphics")`)
`r indexfns("next3d")`:   | Move to the next figure (like `r linkfn("plot.new", pkg="graphics")` or `r linkfn("frame", pkg="graphics")`)
`r indexfns("subsceneList")`: | List all the subscenes in the current layout
`r indexfns("clearSubsceneList")` | Clear the current list and revert to the previous one

There are also lower level functions.

------------------------------------ | -----------
`r indexfns("newSubscene3d")`:     | Create a new subscene, with fine control over what is inherited from the parent
`r indexfns("currentSubscene3d")`: | Report on the active subscene
`r indexfns("subsceneInfo")`:      | Get information on current subscene
`r indexfns("useSubscene3d")`:     | Make a different subscene active
`r indexfns(c("addToSubscene3d", "delFromSubscene3d"))`: | Add objects to a subscene, or delete them
`r indexfns("gc3d")`:              | Do "garbage collection":  delete objects that are not displayed in any subscene


## 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:
```{r}
par3d("mouseMode")
```
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.

The button actions generally correspond to click and drag operations.
Possible values for `r indexfns("mouseMode", '<code>"mouseMode"</code>')` for buttons or the wheel are as follows:

--------       | ---------
`"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 `r linkfn("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 `r indexfns(c("rgl.setMouseCallbacks", "rgl.setWheelCallback"))`.  Use `r indexfns("rgl.getMouseCallbacks")` and `r indexfns("rgl.getWheelCallback")` to retrieve

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

---------------------------- | -----------
`r indexfns("identify3d")`   | like the classic graphics `r linkfn("identify", pkg="graphics")` function
`r indexfns("select3d")`     | returns a function that tests whether a coordinate was selected
`r indexfns("selectpoints3d")` | selects from specific objects

The `r indexfns("rgl.select3d")` function is an obsolete version of
`select3d`, and `r indexfns("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:

---------------------- | -------------
`r indexfns("play3d")` | Repeatedly call the update function 
`r indexfns("spin3d")` | Update the display by rotating at a constant rate
`r indexfns("par3dinterp")` | Compute new values of some `r linkfn("par3d")` parameters by interpolation over time

See the `r linkfn("movie3d")` function for a way to output an animation
to a file on disk.  
Animations are not currently supported 
in the HTML written by `r linkfn("writeWebGL")`. 

### 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:

----------- | -------------
`r indexfns("scene3d")`    | Save a scene to an R variable, which can be saved and reloaded
`r indexfns("writeWebGL")` | Write HTML and Javascript to display a scene in a web browser.  (This vignette uses `writeWebGL`; see also [User Interaction in WebGL](WebGL.html).)
`r indexfns("writePLY")`   | Write PLY files (commonly used in 3D printing)
`r indexfns(c("readOBJ", "writeOBJ"))`   | Read or write OBJ files (commonly used in 3D graphics)
`r indexfns(c("readSTL", "writeSTL"))`   | Read or write STL files (also common in 3D printing)
`r indexfns("rgl.useNULL")`  | A helper function for setting a NULL device

See the help page `r linkfn("rgl.useNULL", pkg="rgl")` for instructions on how
to use `rgl` on a "headless" system.

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

------------ | -------------
`r indexfns("snapshot3d")` | Save a PNG file bitmap of the scene
`r indexfns("rgl.postscript")` | Save a Postscript, LaTeX, PDF, SVG or PGF vector rendering of the scene
`r indexfns("movie3d")`    | Save a series of bitmaps to be assembled into a movie
`r indexfns("rgl.pixels")` | Obtain pixel-level information about the scene in an R variable
`r indexfns("rgl.Sweave")` | Driver function for inserting a snapshot into a Sweave document.
`r indexfns(c("hook_rgl", "hook_webgl"))` | `knitr` hook functions 
for inserting snapshots or WebGL code into a document.

The `r indexfns("rgl.snapshot")` function is identical to `snapshot3d`.
The functions `r indexfns(c("rgl.Sweave.off", "Sweave.snapshot"))` are 
involved in Sweave processing and not normally called by users.

### Working with WebGL scenes

The `writeWebGL` function exports a scene to HTML and Javascript code.  
The functions below write HTML and Javascript for working with the 
exported scene.  More details are given in the vignette 
[User Interaction in WebGL](WebGL.html).

------------------------------------ | -------------
`r indexfns("propertySlider")`       | insert a slider to make changes to a scene
`r indexfns("clipplaneSlider")`      | insert a slider to control a clipping plane
`r indexfns("subsetSlider")`         | insert a slider to control which objects are displayed
`r indexfns("toggleButton")`         | insert a button to toggle some items
`r indexfns("propertySetter")`       | function to modify properties
`r indexfns("subsetSetter")`         | function to choose subsets
`r indexfns("ageSetter")`            | function to "age" vertices
`r indexfns("par3dinterpSetter")`    | function like `r linkfn("par3dinterp")`

### 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.

------------------------------------ | -----------
`r indexfns("open3d")`               | open a new window
`r indexfns("rgl.close")`            | close the current window
`r indexfns("rgl.bringtotop")`       | bring the current window to the top
`r indexfns("rgl.cur")`              | id of the active device
`r indexfns("rgl.dev.list")`         | ids of all active devices
`r indexfns("rgl.set")`              | set a particular device to be active
`r indexfns("rgl.ids")`              | ids and types of all current objects
`r indexfns(c("rgl.attrib", "rgl.attrib.count"))`: | attributes of objects in the scene
`r indexfns(c("pop3d", "rgl.pop"))`     | delete an object from the scene
`r indexfns(c("clear3d", "rgl.clear"))`            | delete all objects of certain classes
`r indexfns("rgl.projection")`        | return information about the current projection
`r indexfns(c("rgl.user2window", "rgl.window2user"))` | convert between coordinates in the current projection

In addition to these, there are some other related functions which
should rarely be called by users: `r indexfns(c("rgl.init", "rgl.open", "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:

------------------------------------ | -----------
`r indexfns(c("asEuclidean", "asHomogeneous"))`: | convert between homogeneous and Euclidean coordinates
`r indexfns(c("rotate3d", "scale3d", "translate3d"))`:  | apply a transformation
`r indexfns("transform3d")`:  | apply a general transformation
`r indexfns(c("rotationMatrix", "scaleMatrix", "translationMatrix"))`:  | compute the transformation matrix
`r indexfns("identityMatrix")` | return a 4 x 4 identity matrix

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

## Warning:  Work in Progress!

This vignette is in a preliminary form.  Many 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:
```{r echo=FALSE}
setdiff(ls("package:rgl"), documentedfns)
```

## Index of Functions

The following functions and constants are described in this document:<br>

```{r echo=FALSE, results="asis"}
writeIndex(cols = 5)
```


