rgl.*
interfacevignettes/deprecation.Rmd
deprecation.Rmd
Since at least 2004, rgl
has had two interfaces for many of the primitive functions: rgl.*
and *3d
. For example, to draw points you could use rgl.points()
or points3d()
. With the upcoming version 1.0.0 release of rgl
, most of the duplication will be removed. The first step will be to deprecate a large number of rgl.*
functions so they give warnings when they are called, and a few months later they will be removed from the package exports.
This document describes the differences and changes needed by users of the rgl.*
interface.
The rgl.open()
function has a single argument, useNULL
. If set to TRUE
, the NULL rgl
device will be used. The par3d()
settings will be set to their defaults.
The open3d()
function has arguments
function(...,
params = getr3dDefaults(),
useNULL = rgl.useNULL(),
silent = FALSE )
and allows par3d()
values to be specified, and uses the r3dDefaults
variable to set default values for par3d()
, material3d()
, and bg3d()
. Initially r3dDefaults
is defined as
list(userMatrix = rotationMatrix(290*pi/180, 1, 0, 0),
mouseMode = c("none", "trackball", "zoom", "fov", "pull"),
FOV = 30,
family = "sans",
bg = list(color="white",
fogtype = "none"),
material = list(color="black", fog = TRUE)
)
Users can create their own default lists; e.g. to get the same result as rgl.open()
would give, use
or
The rgl.material()
function has a large number of parameters. The pre-deprecation arguments were:
function(
color = "white",
alpha = 1.0,
lit = TRUE,
ambient = "black",
specular = "white",
emission = "black",
shininess = 50.0,
smooth = TRUE,
texture = NULL,
textype = "rgb",
texmipmap = FALSE,
texminfilter = "linear",
texmagfilter = "linear",
texenvmap = FALSE,
front = "filled",
back = "filled",
size = 3.0,
lwd = 1.0,
fog = TRUE,
point_antialias = FALSE,
line_antialias = FALSE,
depth_mask = TRUE,
depth_test = "less",
polygon_offset = c(0.0, 0.0),
margin = "",
floating = FALSE,
tag = "",
blend = c("src_alpha", "one_minus_src_alpha"),
col,
... )
Thus a call like rgl.material(color = "black")
will set the color to black, and will also set all of the other parameters to the default values listed above.
On the other hand, the arguments to material3d()
are
function (..., id = NULL)
Calling material3d(color = "black")
will set the color to black and leave all other parameters unchanged.
The primitive shapes (points etc.) can be set using calls like rgl.points(x, y, z, color = "black")
or points3d(x, y, z, color = "black")
.
The first difference is that rgl.*
primitives will call rgl.material()
to set the material properties: in this example color
will be set to black
, and all other parameters will be set to their defaults. The *3d
versions of the primitives use material3d()
to set material properties, so only those that were specified will be changed, and the original values will be restored afterwards.
The second difference is what happens if there is no window already open. The rgl.*
functions will call rgl.open()
(ignoring r3dDefaults
), whereas the *3d
functions will call open3d()
.
rgl.*
?
Both of the systems worked, but they do not work together. For example, calling rgl.points()
will have carry-on effects on later points3d()
calls, whereas each points3d()
call will just draw the points, it won’t affect future calls.
Users have found this confusing, and it makes their code hard to debug, and the rgl
package hard to maintain. The *3d
interface is more flexible, and more similar to the base graphics interface in R, so I’ve decided it will be the only one available going forward.
rgl.*
functions are not deprecated
There will still be some rgl.*
functions in the package. These are functions that are mainly intended for programming, such as rgl.attrib()
and rgl.user2window()
, and a few legacy functions like rgl.Sweave()
supporting older approaches of using rgl
.
In a few cases both function versions are identical (rgl.cur
, rgl.ids
, and rgl.pop
are identical to cur3d
, ids3d
and pop3d
respectively), and for those the rgl.*
versions will be kept, but the documentation will concentrate on the *3d
functions.
rgl.*
. What do I need to do?
If your package is using rgl.*
functions, the first step is to just make the substitutions suggested by the deprecation warning message. For example, if you use rgl.points(rnorm(10), rnorm(10), rnorm(10))
try using points3d(rnorm(10), rnorm(10), rnorm(10))
instead. In most cases this will give you what you want. In some cases more changes will be needed.
The default color after rgl.open()
was white, whereas with open3d()
the default color is black, with a white background. Textures multiplicatively modify the color of the object, so after open3d()
, a texture on an object will still appear black. Explicitly specifying color = "white"
when a texture is used will fix this.
rgl.surface()
The arguments to rgl.surface()
and surface3d()
functions are different. The argument lists are
rgl.surface( x, z, y,
coords = 1:3, ...,
normal_x = NULL, normal_y = NULL, normal_z = NULL,
texture_s = NULL, texture_t = NULL)
surface3d(x, y = NULL, z = NULL,
...,
normal_x = NULL, normal_y = NULL,
normal_z = NULL,
texture_s = NULL, texture_t=NULL)
Notice that the arguments are in a different order. Another difference is that rgl.surface()
expects the surface to be defined in the y
coordinate and viewed in the orientation produced by rgl.open()
, not the one produced by open3d()
. Up until very recently, surface3d()
didn’t allow both x
and z
to be vectors.
The excellent rayshader
package used the convention that the y
argument held the surface, so the y
direction should point up. Using view3d(theta = 45, phi = 45)
(which it was already doing) gives a reasonable view.
Many functions in rgl
and other packages use ...
to set material or par3d
properties in a call, and for some, ...
will contain other optional arguments. Some packages used the argument list of rgl.material()
to identify the material property names. Going forward, packages should use the variables
rgl.material.names
rgl.material.readonly
These are character variables holding all the material property names. (rgl.material.names
contains all names; rgl.material.readonly
is the read-only subset of that list.) There are also variables
rgl.par3d.names
rgl.par3d.readonly
which give the same information for par3d
.
Since these variables are recently added, you will need to add a dependence on rgl (>= 0.111.5)
if you use them.
If you have particular problems adapting other rgl.*
to the *3d
interface, please post them as issues on https://github.com/dmurdoch/rgl/issues . I’ll explain how to get what you want or fix things in rgl
so you can do it.