写在前面
本文为 R 语言 rgl 包的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。软件可能随时更新,建议配合官方文档一起阅读。
::: block-1
目录
- 1 介绍
- 2 关于本文档
- 3 基础和高级函数
- 4 添加图形元素
- 5 控制场景的外观
- 6 网格:构建形状
- 7 多图布局
- 8 带有 rgl 场景的文档
- 9 实用功能
- 10 警告:工作正在进行中!
:::
官网教程:https://dmurdoch.github.io/rgl/articles/rgl.html
1 介绍
rgl
包用于生成交互式 3-D 绘图。它包含按照经典 R 图形松散建模的高级图形命令,但在三维上工作。它还包含受grid
包启发(但不兼容)的低级结构。
本文档提供了概述。有关详细信息,请参阅帮助页面。
有关安装说明,请参阅源 tarball rgl_1.3.12.tar.gz(或更高版本)顶级目录中的README
文件。
2 关于本文档
本文档是用 R Markdown 编写的,使用knit
包进行生产。它对应于rgl
版本1.3.12。
大多数突出显示的函数名称都是 HTML 链接。内部链接应该在任何浏览器中都有效;如果您从 R 帮助系统中查看小插图,则帮助主题的链接应该有效。
该文档包含 WebGL 图形。要查看这些,您必须在浏览器中启用 Javascript 和 WebGL。一些较旧的浏览器可能不支持此功能 - 请参阅https://get.webgl.org
以获取测试和讨论链接。
3 基础和高级函数
plot3d
函数在 RGL 窗口内绘制点(points)。它类似于经典的plot
函数,但适用于 3 维。
例如
with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length,
type="s", col=as.numeric(Species)))
可用于绘制三列iris
数据。允许的绘图类型包括"p", "l", "h", "s"
,表示点(points)、线(lines)、从 z=0 开始的线段(segments)、球体(spheres)。指定坐标有很大的灵活性;grDevices
包中的 xyz.coords
函数用于此目的。
您可以使用鼠标来操纵绘图。默认情况下,如果单击并按住鼠标左键,则可以通过拖动来旋转绘图。鼠标右键用于调整其大小,中键用于更改视点的视角。
如果再次调用plot3d
,它将覆盖当前绘图。要打开新的图形窗口,请使用open3d
。
另一个高级函数是persp3d
,用于绘制曲面(surfaces)。它与经典的persp
函数类似,但具有更大的灵活性。首先,x
、y
、z
中的任何一个都可以使用矩阵来指定,而不仅仅是 z
。这允许绘制参数化曲面。甚至可以有更简单的规范:x
可能是一个函数,在这种情况下persp3d
将计算出网格本身。有关详细信息,请参阅?persp3d.function
。例如,MASS
包在?MASS::fitdistr
示例中使用最大似然估计 Gamma 参数。这里我们展示了对数似然曲面。
# 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)
左边是整个表面的一系列参数;右侧仅显示对数似然值接近最大值的表面部分。
注意:此示例使用knit
钩子函数(请参阅setupKnit
)将场景插入到此小插图中;前面的示例使用了rglwidget
函数。我们通常推荐较新的rglwidget
方法。
请注意,plot3d
和persp3d
都是通用函数,定义了以下方法:
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
4 添加图形元素
4.1 原始形状
正如经典图形中的points
和lines
一样,rgl
中有许多低级函数可以将图形元素添加到当前活动的绘图中。"primitive" 形状是 OpenGL 原生的形状:
Function | Description |
---|---|
points3d | 添加点 |
lines3d | 添加线 |
segments3d | 添加线段 |
triangles3d | 添加三角形 |
quads3d | 添加四边形 |
上述每个函数都接受参数 x
、y
和 z
,为了灵活性再次使用 xyz.coords
。他们根据需要对连续的条目进行分组。例如,triangles3d
函数将每个连续的三重点作为三角形的顶点。
您可以使用这些函数来注释当前图形,或从头开始构建图形。
4.2 构造形状
rgl
还有许多从原始形状构造的对象。
Function | Description |
---|---|
text3d, texts3d | 添加文本 |
abclines3d | 添加直线来绘图(如 abline) |
arc3d | 添加球弧或螺旋线来绘图 |
planes3d | 添加平面到绘图中 |
clipplanes3d | 添加剪裁平面来绘图 |
sprites3d, particles3d | 添加精灵(固定形状或图像)来绘图 |
spheres3d | 添加球体 |
surface3d, terrain3d | 表面(如 persp3d 中使用的) |
drape3d | 在表面或物体上覆盖线条 |
shadow3d | 将网格(mesh)投影到表面(surface)上 |
arrow3d | 向场景添加箭头 |
pch3d | 绘制基本样式的绘图符号 |
plotmath3d | 由 text3d 用于数学文本 |
4.3 轴和其它装饰
以下低级函数控制图形的外观:
Function | Description |
---|---|
axes3d, axis3d | 添加坐标轴到绘图 |
box3d, bbox3d | 在图周围添加框 |
title3d | 添加标题到绘图 |
mtext3d | 添加边际文本到绘图 |
decorate3d | 添加多个“装饰”(scales 等)到绘图 |
aspect3d | 设置绘图的纵横比 |
bg3d, bgplot3d | 设置场景的背景 |
show2d | 在 3D 场景中显示 2D 绘图或图像 |
legend3d | 为场景设定一个图例 |
grid3d | 向图表添加参考网格 |
thigmophobe3d | 选择标签位置以避免重叠 |
setAxisCallbacks | 设置用户定义的轴注释 |
例如,要绘制三个随机三角形,可以使用
triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green")
decorate3d()
bg3d("lightgray")
aspect3d(1,1,1)
除了上面提到的 *3d
函数之外,还有已弃用的函数 rgl.abclines
、rgl.bbox
、rgl.bg
、rgl.clipplanes
、rgl.lines
、rgl.linestrips
、rgl.planes
、rgl.points
、rgl.primitive
、rgl.Qquads
,rgl.setAxisCallback
,rgl.spheres
,rgl.sprites
,rgl.surface
,rgl.texts
,rgl.triangles
。您应该避免使用所有这些函数,它们不能与 *3d
函数一起正常工作,并且很快就会从 rgl
中删除。有关详细信息,请参阅 ?r3d
帮助主题。
函数 rgl.getAxisCallback
为 setAxisCallbacks
提供低级支持。
5 控制场景的外观
5.1 拍摄角度
默认情况下,当您使用 open3d
打开新绘图时:
- x 轴从左到右。
- y 轴从靠近相机到远处。
- z 轴从下到上。
您只需用鼠标拖动图片即可更改相机角度。
要以编程方式设置相机角度,请使用 view3d
。这使用极坐标:
theta
设置绕垂直轴的旋转(以度为单位)。phi
设置绕水平轴的“垂直”旋转,范围为 -90 到 90 度。
默认角度大致为 theta = 0,phi = -70
。从这个位置开始:
- 当您增加
theta
时,从您的角度来看,图表将逆时针旋转。 - 当您将
phi
增加到 0 时,您开始从顶部向下看场景。如果将phi
增加到 0 以上,您将继续并开始从“背面”(并且颠倒)查看图表。
您还可以使用 observer3d
使用 x、y、z
坐标更改相机位置。特别是,增加 z
坐标可以缩小,减少 z
坐标可以放大。
一种有用的方法是使用鼠标找到一个合适的视角。然后您可以使用 par3d("userMatrix")
保存它并稍后恢复相同的视图:
myview <- par3d("userMatrix")
# ... later ...
par3d(userMatrix = myview)
5.2 灯光
在大多数场景中,对象都是“被照亮”的,这意味着它们的外观取决于它们相对于场景中灯光的位置和方向。灯光本身通常不会出现,但它们对物体的影响却会出现。
使用 light3d
函数指定灯光的位置和特征。灯光可能无限远,也可能嵌入场景中。它们的特征包括 ambient
, diffuse
, specular
成分,全部默认为白色。ambient
成分从任何方向看都是一样的。diffuse
分量取决于表面和光线之间的角度,而 specular
分量还考虑了观看者的位置。
不应再使用已弃用的 rgl.light
函数;使用 light3d
代替。
5.3 材质
rgl
中使用的心理模型是场景中显示的对象是空间中的物理对象,其材质属性会影响光从它们反射(或由它们发出)的方式。这些主要由 material3d
函数或传递给它的其他函数的参数控制。
在调用 material3d
时识别的材料属性在 ?material3d
帮助页面中有详细描述,并在 rgl.material.names
变量中列出。除了 rgl.material.readonly
中的之外,所有这些都可以设置。这里我们给出一个概述。
Property | Default | Meaning |
---|---|---|
color | white | 应用于 diffuse 光的连续顶点的表面颜色向量 |
alpha | 1 | 透明度:0 为不可见,1 为不透明 |
lit | TRUE | 是否应该进行光照计算 |
ambient | black | 环境光下的颜色 |
specular | white | 镜面光下的颜色 |
emission | black | 表面发出的颜色 |
shininess | 50 | 控制镜面照明:高值看起来有光泽 |
smooth | TRUE | 是否应在顶点之间插入阴影 |
texture | NULL | 要显示在表面上的“纹理”位图的可选路径 |
front, back | fill | 多边形应该被填充还是轮廓? |
size | 3 | size of points in pixels |
lwd | 1 | width of lines in pixels |
其他属性包括 “texmipmap”、“texmagfilter”、“texminfilter”、“texenvmap”、“fog”、“point_antialias”、“line_antialias”、“depth_mask”、“depth_test”、“polygon_offset”、“margin”、“floating” 、“tag” 和 “blend”;有关详细信息,请参阅帮助页面。
还有一个已弃用的 rgl.material
函数,它在较低级别上工作;用户应该避免它。
5.4 纹理
如上一节所述,材质属性之一是 texture
,即包含要在表面上显示的图像的位图文件(.png
格式)的名称。本节提供有关 textures 的更多详细信息。
在 OpenGL
中,多边形中的每个顶点都可以与位图中的特定位置相关联。多边形的内部在位图中进行插值。rgl
函数中有两种约定用于指定这些坐标。
指定基元(triangles3d
等)的函数接受可选的矩阵参数 texcoords
,它给出位图中的 s
(水平)和 t
(垂直)位置,以列为单位,每个顶点一行。左下角坐标为 (0,0)
,右上角坐标为 (1,1)
。如果给出的值超出此范围,则图像会重复,即 (1.1, 1.2)
将图像中的同一点指定为 (0.1, 0.2)
。
其他函数(例如为每个顶点坐标采用矩阵的 surface3d
)也接受纹理坐标作为矩阵,在参数 texture_s
和 texture_t
中。
例如,以下代码在四边形上显示 2D 图的四个副本,因为 s
和 t
中的纹理坐标都从 0 到 2:
filename <- tempfile(fileext = ".png")
png(filename = filename)
plot(rnorm(1000), rnorm(1000))
safe.dev.off()
open3d()
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")
其他一些注意事项:
- 上面的
quads3d()
中的颜色被指定为白色。默认情况下,位图中的颜色将修改表面的颜色。如果col
是黑色(常见的默认值),您将看不到任何内容,因此可能会发出警告。 - 您通常不希望出现镜面反射(表现为眩光)。将
specular
设置为黑色可以防止这些情况发生。 - 材质属性
"texmode"
允许以不同方式使用纹理颜色。默认值为"modulate"
,其中纹理值与基础值乘法组合。 - 位图处理方式的另一个方面是由材质属性
"textype"
控制的。默认值为"rgb"
,它从位图中获取红-绿-蓝颜色,并使用它们来修改多边形中相应的颜色。 - Material3d 帮助页面中描述了
"textype"
和"texmode"
的其他可能性。 - 其他
"tex*"
材质属性控制图像内插值的完成方式。 - 现代
OpenGL
支持 1 维和 3 维纹理;rgl
目前不支持这些。
5.5 字体
rgl
使用与绘制文本的基本图形相同的想法:有名为"sans"
、"serif"
和"mono"
的字体系列用于绘制这些类型的文本。在 rgl
中,不支持"symbol"
系列。
新的字体系列可以使用低级函数 rglFonts
定义,或者更简单地使用高级函数 rglExtrafonts
定义。后一个功能需要安装 extrafont
软件包。
5.6 par3d:其他图形参数
par3d
函数以经典图形 par
函数为模型,设置或读取 rgl.par3d.names
变量中列出的各种不同的 rgl
内部参数。除了 rgl.par3d.readonly
中的之外,所有这些都可以设置。有些参数是完全只读的;其他的在窗口打开时是固定的,其他的可能随时更改。
Name | Changeable? | Description |
---|---|---|
antialias | fixed | 硬件抗锯齿量 |
cex | 文本的默认大小 | |
family | 与设备无关的字体系列名称;参见 ?text3d | |
font | 整数字体编号 | |
useFreeType | 如果有的话应该使用 FreeType 字体吗? | |
fontname | read-only | rglFonts 设置的系统相关字体名称 |
FOV | 视野,以度为单位。零表示等距透视 | |
ignoreExtent | rgl 在计算边界框时是否应该忽略新对象的大小? | |
skipRedraw | rgl 应该抑制显示更新吗? | |
maxClipPlanes | read-only | 可以定义多少个裁剪平面? |
modelMatrix | read-only | OpenGL 模型视图矩阵;部分由 view3d 设置 |
projMatrix | read-only | OpenGL 投影矩阵 |
bbox | read-only | 场景的当前边界框 |
viewport | 窗口内场景的尺寸(以像素为单位) | |
windowRect | 整个屏幕上窗口的尺寸(以像素为单位) | |
listeners | 哪些子场景响应当前场景中的鼠标操作 | |
mouseMode | 鼠标按钮的作用。请参阅 "mouseMode" | |
observer | read-only | 观察者的位置;由 observer3d 设置 |
scale | 对每个坐标重新缩放;参见 aspect3d | |
zoom | 场景放大 |
不应使用已弃用的 rgl.viewpoint
函数。
5.7 默认设置
r3dDefaults
列表和 getr3dDefaults
函数控制 open3d
打开的新窗口中的默认值。
该函数在用户的全局环境中查找该变量,如果没有找到,则在 rgl
命名空间中查找该变量。这允许用户覆盖新窗口的默认设置。
找到后,r3dDefaults
列表将提供 par3d
参数的初始值,以及组件 "material"
和 "bg"
中的 material3d
和 bg3d
的默认值。
6 网格:构建形状
rgl
包含许多用于构造和显示各种实体形状的函数。它们生成"shape3d"
、"mesh3d"
或"shapelist3d"
类的对象。类的详细信息如下所述。我们从生成它们的函数开始。
6.1 特定固体
这些函数生成特定的形状。可选参数允许指定颜色或变换等属性。
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]))
Rpolyhedra
包中包含非常多的多面体集合。
6.2 生成新形状
这些函数生成新的形状:
Function | Description |
---|---|
cylinder3d | 生成管子或圆柱体 |
polygon3d | 通过三角测量生成平面多边形 |
extrude3d | 生成多边形的“挤压” |
turn3d | 生成旋转固体 |
ellipse3d | 以各种方式生成椭球体 |
mesh3d | 从索引顶点生成形状 |
shapelist3d | 通过组合其他形状生成一个形状 |
as.mesh3d | 通用函数;见下文 |
一个相关的函数是 triangulate
,它采用二维多边形并使用“ear-clipping”算法将其分成三角形。
提供通用函数 as.mesh3d
来允许将其他代码生成的数据结构转换为网格结构。目前支持以下类:
Class | Package | Description |
---|---|---|
deldir | deldir | 不规则点云的 Delaunay 三角剖分 |
triSht | interp | 也是 Delaunay 三角剖分 |
tri | tripack | 广义 Delaunay 三角剖分 |
ashape3d | alphashape3d | Alpha-shapes |
rglId | rgl | rgl 对象标识符 |
checkDeldir
函数检查是否安装了 deldir
软件包的兼容版本。
默认的 as.mesh3d.default
方法是一种从顶点矩阵构造网格的简单方法;它可以使用 mergeVertices
(也可以单独使用)来合并矩阵内的重复顶点,从而允许使用 addNormals
来提供平滑的外观。
as.tmesh3d
泛型是一种变体,可保证生成的对象不会有四边形条目。
函数 tmesh3d
、qmesh3d
现已过时;使用 mesh3d
代替。
6.3 形状的底层类结构
"shape3d"
是基本的抽象类型。此类的对象可以通过 shade3d
(对面进行着色)、wire3d
(绘制边)、或 dot3d
(在每个顶点绘制点)来显示。
"mesh3d"
是后代类型。该类型的对象包含以下字段:
Field | Meaning |
---|---|
vb | 齐次坐标中的 4 x n 顶点矩阵。每列都是一个点 |
ip | (可选)点的顶点索引向量 |
is | (可选)顶点索引的 2 x s 矩阵。每列都是一条线段 |
it | (可选)顶点索引的 3 x t 矩阵。每列都是一个三角形 |
ib | (可选)顶点索引的 4 x q 矩阵。每列都是一个四边形 |
material | (可选)材质属性列表 |
normals | (可选)与 vb 形状相同的矩阵,包含每个顶点的法向量 |
texcoords | (可选)与每个顶点对应的纹理坐标的 2 x n 矩阵 |
values | (可选)长度为 n 的向量,在每个顶点保存值 |
meshColor | (可选)一个文本值指示如何解释颜色和纹理坐标 |
tags | (可选)由某些函数(例如 clipMesh3d)添加的向量,用于将输出部分与输入部分相关联 |
6.4 轮廓和剪裁形状
这些函数计算并绘制曲面上函数的轮廓,或沿函数的轮廓剪切对象。
Function | Description |
---|---|
contourLines3d | 在曲面上绘制轮廓线 |
filledContour3d | 填充曲面轮廓之间 |
clipMesh3d | 使用弯曲边界裁剪网格对象 |
clipObj3d | 使用弯曲边界裁剪一般对象 |
6.5 操纵形状
这些函数操作和修改网格对象:
Function | Description |
---|---|
addNormals | 添加法线向量以使形状看起来平滑 |
subdivision3d | 添加额外的顶点使其看起来更平滑 |
merge | 合并网格对象 |
facing3d | 面向“向上”的网格子集 |
getBoundary3d | 获取网格对象的边界 |
subdivision3d
中的各个步骤也可用:deform.mesh3d
、divide.mesh3d
、normalize.mesh3d
。这些主要供内部使用。
7 多图布局
rgl
有几个函数支持在同一窗口中显示多个不同的“子场景”。高级功能是
Function | Description |
---|---|
mfrow3d | 多图(如 par("mfrow")) |
layout3d | 多图(如 layout) |
next3d | 移至下一个图(如 plot.new 或 frame) |
subsceneList | 列出当前布局中的所有子场景 |
clearSubsceneList | 清除当前列表并恢复到上一个列表 |
还有一些较低级别的功能。
Function | Description |
---|---|
newSubscene3d | 创建一个新的子场景,对从父场景继承的内容进行精细控制 |
currentSubscene3d | 报告活动的子场景 |
subsceneInfo | 获取当前子场景的信息 |
useSubscene3d | 激活不同的子场景 |
addToSubscene3d, delFromSubscene3d | 将对象添加到子场景,或删除它们 |
gc3d | 进行“垃圾收集”:删除未在任何子场景中显示的对象 |
8 带有 rgl 场景的文档
rgl
包可以生成可嵌入其他文档中的输出。多年来,推荐的执行此操作的方法已多次更改。我们将从当前的建议开始,然后列出旧的方法。
8.1 推荐方法
目前,在文档中嵌入 rgl
场景的最佳方法是使用 R Markdown 生成 HTML 文档。在文档的前面,您应该在其中一个设置代码块中包含如下代码:
```{r echo=FALSE, include=FALSE}
library(rgl)
setupKnitr(autoprint = TRUE)
```
对 setupKnit()
的调用将在 knit
中安装许多钩子并设置选项,以便正确处理 rgl
代码。autoprint = TRUE
参数使 rgl
在文档中的行为几乎与在控制台中的行为相同,或者与 knit
处理基本图形的方式相同:如果打印高级 rgl
函数的值,则绘图将插入到输出,但可能只有在对其进行低级修改完成之后。例如,此代码块在最后的单个图中打印三角形和球体:
xyz <- matrix(rnorm(27), ncol = 3)
triangles3d(xyz, col = rainbow(9))
spheres3d(xyz, col = rainbow(9), radius = 0.1)
如果情况复杂,则存在一些差异:
- 该机制取决于自动打印
rgl
函数调用的结果。如果调用位于循环或其他不会发生自动打印的代码块中,则您将需要一些技巧来打印内容。例如,这将打印三个图:
foreignHigh() # Produces a high level plot, but doesn't return
# an appropriate value
highlevel()
foreignLow() # Modifies the previous plot
lowlevel()
当假设修改完成时,这应该在代码块的末尾显示输出。
8.2 生成 PDF 输出
虽然某些 PDF 预览器支持交互式 3D 图形,但大多数不支持。要在具有 PDF 输出的 R Markdown 文档中生成 rgl
场景的屏幕截图,只需按照上面给出的说明进行操作即可。自动打印将检测 PDF 输出并使用 snapshot3d
生成要插入的 PNG 文件。(如果您想插入不同格式的图形,请参见下文。)
如果您确实需要交互式输出,请参阅 writeASY
函数。
8.3 手动插入图
您可能不想使用上述 setupKnit(autoprint = TRUE)
方法。它非常新,可能仍然存在错误;您可能有一个较旧的文档,但不想对其进行编辑以使其正常工作。
在这种情况下,您可以手动插入绘图。使用设置代码
```{r echo=FALSE, include=FALSE}
library(rgl)
setupKnitr()
```
并在您想要插入绘图时在顶层调用 rglwidget()
。
如果您不使用 autoprint
,默认行为还有一些其他差异:
- 默认情况下,每个代码块都会延续前面代码块的
rgl
场景。您需要显式的open3d
调用才能获得干净的窗口。 - 同样默认情况下,
rgl
窗口在代码块末尾不会关闭。这可能并不重要,但如果场景很大,您可能会发现内存不足。
8.4 较旧的方法
在文档中插入 rgl
场景的原始方法是使用已弃用的 writeWebGL
函数编写 HTML 代码以插入到文档中。后来又添加了 Sweave
和 knitr
hooks。这些不再受支持,您应该更新旧文档以使用较新的方法。如果您正在阅读建议使用这些方法的文档,请让作者知道它们需要更新!
9 实用功能
9.1 用户交互
默认情况下,rgl
检测并处理场景中的鼠标单击,并使用这些来控制其外观。您可以使用以下代码找出当前的处理程序:
par3d("mouseMode")
## none left right middle wheel
## "none" "trackball" "zoom" "fov" "pull"
标签 c("left", "right", "middle")
指的是三键鼠标上的按钮,或其他鼠标上的模拟按钮。"wheel"
是指鼠标滚轮,"none"
是指在不按任何按钮的情况下移动鼠标时发生的操作。
按钮操作通常对应于单击和拖动操作。鼠标指针或滚轮的"mouseMode"
的可能值如下:
Mode | Description |
---|---|
"none" | No action |
"trackball" | 鼠标充当虚拟轨迹球。单击并拖动可旋转场景 |
"xAxis", "yAxis", "zAxis" | 类似于 "trackball",但仅限于绕一个轴旋转 |
"polar" | 鼠标通过直接控制极坐标来影响旋转 |
"selecting" | select3d 函数正在使用鼠标 |
"zoom" | 鼠标缩放显示 |
"fov" | 鼠标通过改变视野来影响视角 |
"pull" | 朝用户方向旋转鼠标滚轮“拉近场景” |
"push" | 同样的旋转“把场景推开” |
"user" | 通过 setUserCallbacks、rgl.setMouseCallbacks、rgl.setWheelCallback 设置的用户操作。使用 rgl.getMouseCallbacks 和 rgl.getWheelCallback 进行检索 |
以下功能使用鼠标在场景内进行选择。
Function | Description |
---|---|
identify3d | 像经典的图形识别功能 |
select3d | 返回一个测试坐标是否被选择的函数 |
selectpoints3d | 从特定对象中选择 |
hover3d | 显示有关点的“悬停”信息 |
SelectionFunction3d
根据有关投影和鼠标选择区域的信息生成选择函数;它在上述函数内部使用。
已弃用的 rgl.select3d
函数是 select3d
的过时版本,rgl.select
是低级支持函数。
9.2 动画
rgl
有几个可用于构造动画的函数。这些基于根据当前现实世界时间更新场景的函数,以及对这些函数的重复调用。其功能是:
Function | Description |
---|---|
play3d | 反复调用更新函数 |
spin3d | 通过以恒定速率旋转来更新显示 |
par3dinterp | 通过随时间的插值计算一些 par3d 参数的新值 |
有关将动画输出到磁盘上文件的方法,请参阅 movie3d
函数。
尽管 playwidget
函数提供了等效的功能,但 rglwidget
编写的 HTML 目前不支持动画。
9.3 与 TCL/TK 集成
rgl
中有三个函数支持使用 TCL/TK 框架控制 rgl
场景。
Function | Description |
---|---|
tkspin3d | 在窗口中设置按钮来控制场景 |
tkspinControl | 将控制按钮嵌入单独的 TCL/TK 框架中 |
tkpar3dsave | 创建一个对话框以交互方式保存鼠标操作 |
这些函数以前包含在 tkrgl
包中(其名称中没有 tk
前缀)。该软件包现已被弃用。
9.4 导出和导入场景
rgl
包含多个将场景写入磁盘以供其他软件使用或将其读入的函数。
按照从最高保真度到最低保真度的顺序,这些函数是:
Function | Description |
---|---|
scene3d | 将场景保存到 R 变量,可以保存和重新加载 |
rglwidget | 以 HTML 和 Javascript 形式打印以在 Web 浏览器中显示场景(另请参阅 WebGL 中的用户交互) |
writeASY | 为 Asymptote 编写文件 |
writePLY | 写入 PLY 文件(常用于 3D 打印) |
readOBJ, writeOBJ | 读取或写入 OBJ 文件(常用于 3D 图形) |
readSTL, writeSTL | 读取或写入 STL 文件(在 3D 打印中也很常见) |
as.rglscene | 通用函数,rgl 中没有方法 |
rgl2gltf
包可以读取或写入 GLTF 和 GLB 文件。它包括一个 as.rglscene
方法,用于将 GLTF 对象转换为 rgl
场景。rgl
的 Buffer
R6 类中的代码基于 GLTF 格式。rglwidget
使用它来使输出网页比以前小一些。
还有一些功能可以保存场景的快照或其他记录,而不保存任何 3D 信息:
Function | Description |
---|---|
snapshot3d | 保存场景的 PNG 文件位图 |
rgl.postscript | 保存场景的 Postscript、LaTeX、PDF、SVG 或 PGF 矢量渲染 |
movie3d | 保存一系列位图以组合成电影 |
rgl.pixels | 在 R 变量中获取有关场景的像素级信息 |
rgl.Sweave | 用于将快照插入 Sweave 文档的驱动程序功能 |
hook_rgl, hook_webgl | knitr 钩子函数用于将图像插入到文档中 |
setupKnitr | 设置 knitr 钩子的功能 |
rgl.snapshot
函数是 snapshot3d()
的低级版本;它要求 rgl
显示在屏幕上并从那里进行复制。snapshot3d()
尝试使用 webshot2
包,因此即使没有显示它也能工作。函数 rgl.Sweave.off
、Sweave.snapshot
涉及 Sweave 处理,通常不被用户调用。
9.5 默认显示
在 R 中,通常有两种方式显示 rgl
场景。较旧的方式是在专用窗口中显示。在类似 Unix 的系统中,这是一个 X11 窗口;在 Microsoft Windows 中,这是一个本机窗口。在 macOS 上,需要安装 XQuartz 系统(请参阅 https://www.xquartz.org
)才能支持此功能。
要禁止显示此内容,请在打开新的 rgl
窗口之前设置 options(rgl.useNULL = TRUE)
。请参阅 rgl.useNULL
函数的帮助页面,了解如何在启动 R 之前设置此选项。
显示场景的较新方式是在浏览器窗口或 RStudio 中的查看器窗格中使用 WebGL。要选择此选项,请设置 options(rgl.printRglwidget = TRUE)
。每个会更改场景的操作都会返回一个值,该值在打印时会触发新的 WebGL 显示。
9.6 使用 WebGL 场景
您应该使用以下方案将场景导出到网页。还有一个旧方案,不再受支持。
推荐的方法适用于 htmlwidgets
框架(请参阅 http://www.htmlwidgets.org/
)。在 knit
中的 R Markdown 文档中,使用 rglwidget
函数。(您还可以使用块选项 webgl=TRUE
;我们建议显式使用 rglwidget
。)此方法还允许在 RStudio 中显示 rgl
场景。除了 rgl
场景之外,还可以显示它们的各种控件,并且有一些有用的实用函数:
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 |
这些函数与 Shiny 应用程序中的上述方案配合使用:
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 |
使用 Shiny 时,selectionFunction3d
函数也可能涉及鼠标交互。
一些函数主要供内部使用:elementId2Prefix
、playwidgetOutput
、renderPlaywidget
、rglwidgetOutput
、renderRglwidget
、registerSceneChange
。更多详细信息请参阅 WebGL 中的用户交互。函数 lowlevel
、highlevel
、rglId
也供内部使用,标记函数结果以便自动打印。最后,函数 setUserShaders
允许您在 WebGL 中使用手写着色器,而 getShaders
允许您查看将使用哪个着色器。
9.7 使用场景
rgl
维护它显示的所有场景的内部结构。以下功能允许用户查找有关它们的信息并对其进行操作。如果同时存在 *3d
和 rgl.*
版本的函数,大多数用户应使用 *3d
版本:rgl.*
函数更原始,主要供内部使用。
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 |
为了向后兼容,其中一些函数具有备用名称:
rgl.cur
、rgl.ids
、rgl.pop
。任一名称都可以,但建议新代码使用 *3d
版本。有些版本已弃用:rgl.clear
、rgl.set
。那些不应该被调用。
这些函数主要用于编程,没有相应的 *3d
对应函数:
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 |
as.triangles3d
通用函数旨在以适合传递给 triangles3d
的形式提取坐标。目前为 rglId
对象提供了一种方法。
除此之外,还有一些不建议调用的函数:rgl.init
、rgl.open
、rgl.close
、rgl.quit
。
9.8 使用 3-D 矢量
大多数 rgl
函数在内部使用“齐次”坐标工作。在该系统中,3D 点用 4 个坐标表示,通常称为 (x, y, z, w)。如果 w 非零,则对应的欧几里德点为 (x/w, y/w, z/w);w 的零值对应于“无穷远点”。该系统的优点是仿射变换(包括平移和透视移位)通过乘以 4 x 4 矩阵而变成线性变换。
rgl
具有以下用于处理齐次坐标的函数:
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 |
还有一个函数 GramSchmidt
,主要供内部使用:它对 3x3 矩阵进行 Gram-Schmidt 正交化,并对其在 cylinder3d
中使用进行了一些专门化。
9.9 与其他包一起使用
有时,以交互方式将场景旋转到特定视图,然后以 lattice
或基础图形显示它可能会很方便。rglToLattice
和 rglToBase
函数支持这一点。
例如,我们首先在 rgl
中显示 volcano 数据:
persp3d(volcano, col = "green")
该显示是交互式的,但我们可以使用 lattice wireframe
或基本图形 persp
函数重现初始视图:
# Only evaluated if the lattice & orientlib packages are installed
lattice::wireframe(volcano, col = "green", screen = rglToLattice())
angles <- rglToBase()
persp(volcano, col = "green", shade = TRUE,
theta = angles$theta, phi = angles$phi)
请注意,orientlib
包必须可用才能使这些功能正常工作。
9.10 创建 pkgdown 网站
“Using RGL in pkgdown web sites” 小节描述了如何在 pkgdown
网站中使用 rgl
。实用程序函数 in_pkgdown_example
可用于检测 pkgdown
是否正在使用。
9.11 使用 testthat
testthat
包广泛用于包中的单元测试。这样的测试很难用 rgl
编写,因为输出是可视化和交互式的,而不是简单的值。expect_known_scene
、compare_proxy.mesh3d
和 all.equal.mesh3d
函数通过删除 rgl
输出的系统相关功能来帮助解决此问题。
9.12 使用 JavaScript
使用 rglwidget
创建的 WebGL 显示依赖于该包中包含的大量 Javascript 代码。为了帮助开发此代码,编写了 makeDependency
函数。它可能在其他包含 Javascript 的包中有用。
9.13 其他函数和对象
本节适用于不属于本文档中任何其他类别的杂项函数和对象。
setGraphicsDelay
函数旨在解决 macOS 上的一个错误:如果在 rgl
窗口之后打开标准绘图窗口太快,R 可能会崩溃。此功能会在需要时插入一秒的延迟。
gltfTypes
向量包含 OpenGL 和 glTF 中使用的常量。
10 警告:工作正在进行中!
这个页面始终是一项正在进行的工作。rgl
包的某些方面没有描述,或者没有示例。如果以下列表不为空,甚至可能会完全错过某些功能:
## [1] "rgl.incrementID" "safe.dev.off" "textureSource"
<center>--------------- 结束 ---------------</center>
<p style="color: gray; font-size: 10px;">注:本文为个人学习笔记,仅供大家参考学习,不得用于任何商业目的。如有侵权,请联系作者删除。</p>
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。