rgl:绘制一个带有彩色面、顶点和线的立方体

rgl: drawing a cube with colored faces, vertex points and lines

为了演示 3D 中线性变换的效果,x -> A x,我想画一个立方体并在 A 下显示它的变换。为此,我需要分别为每个面着色,并显示顶点和勾勒每个面的线条。

我不知道如何为面部使用不同的颜色,以及如何使它更通用,这样我就不必为转换结果重复所有步骤。

我尝试了什么:

library(rgl)
c3d <- cube3d(color=rainbow(6), alpha=0.5)
open3d()
shade3d(c3d)
points3d(t(c3d$vb), size=5)
for (i in 1:6)
    lines3d(t(c3d$vb)[c3d$ib[,i],])

这给出了下图。但我不明白这些脸是怎么变色的。而且,我似乎必须在 c3d 形状的组件上使用 points3dlines3d,并且没有一个我可以转换的对象。

下面的矩阵 A 给出了一个特定的变换,下面是我如何将其添加到场景中,

A <- matrix(c( 1, 0, 1, 0, 2, 0,  1, 0, 2), 3, 3)
c3d_trans <- transform3d(c3d, A) 
shade3d( c3d_trans )
points3d(t(c3d_trans$vb), size=5)

这给出:

有什么方法可以简化它并使其更普遍有用吗?

rgl 中,当绘制原始形状时,您将颜色应用于顶点,而不是面。通过在顶点处插值颜色为面着色。

但是,cube3d() 不是原始形状,而是 "mesh"。它被绘制为 6 个独立的四边形。每个顶点被使用3次。

它没有真正的记录,但颜色使用的顺序是前 4 种用于一张脸,然后接下来的 4 种用于下一张脸,依此类推。如果你希望你的颜色是 rainbow(6),每种颜色需要复制4次:

library(rgl)
c3d <- cube3d(color=rep(rainbow(6), each = 4), alpha = 0.5)
open3d()
shade3d(c3d)
points3d(t(c3d$vb), size = 5)
for (i in 1:6)
    lines3d(t(c3d$vb)[c3d$ib[,i],])

我推荐更高的 alpha 值;我发现 alpha = 0.5.

的透明度有点混乱

顺便说一句,出于同样的目的,我一般会使用看起来更像球形的形状作为基线;我认为它提供了关于转换的更好直觉。这是我使用的代码:

sphere <- subdivision3d(cube3d(color=rep(rainbow(6),rep(4*4^4,6)), alpha=0.9),
    depth=4)
sphere$vb[4,] <- apply(sphere$vb[1:3,], 2, function(x) sqrt(sum(x^2)))
open3d()
shade3d(sphere)

这给出了这个形状:

转换为:

A <- matrix(c( 1, 0, 1, 0, 2, 0,  1, 0, 2), 3, 3)
trans <- transform3d(sphere, A)
open3d()
shade3d(trans)

当然,如果能旋转就更好看了

我的问题的第二部分——如何概括这一点——没有得到解答。这是我现在用来使步骤可重用的一个简单函数。

# draw a mesh3d object with vertex points and lines
draw3d <- function(object, ...) {
    shade3d(object, ...)
    vertices <- t(object$vb)
    indices <- object$ib
    points3d(vertices, size=5)
    for (i in 1:ncol(indices))
        lines3d(vertices[indices[,i],])
}

(注:我用的是rgl version 0.96.0,如果我没记错的话,wire3d()dot3d()规则已经改过了)

在制作 class mesh3d 对象时给出颜色信息不是一个好主意,因为 shade3d()wire3d()dot3d() 以不同的方式使用它。最好在绘制对象时给 plot-function 一个颜色信息。

例如;
A <- matrix(c( 1, 0, 1, 0, 2, 0,  1, 0, 2), 3, 3)
c3d2 <- cube3d()
c3d_trans2 <- cube3d(A)
colv <- rep(2:7, each=4)

shade3d(c3d2, col = colv, alpha = 0.8)
wire3d(c3d2); dot3d(c3d2, size = 5)
shade3d(c3d_trans2, col = colv, alpha=0.5)
dot3d(c3d_trans2, size = 5)


[与颜色相关的细节mesh3d.obj]

最重要的规则是一个顶点在使用时消耗一种颜色(但它有点复杂,请看下面的例子)。我在下面调用矩阵 ibmesh3d.obj$vb 的列号 index

cube3d()$ib
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    1    3    2    1    1    5
# [2,]    3    7    4    5    2    6
# [3,]    4    8    8    7    6    8
# [4,]    2    4    6    3    5    7
shade3d() 规则(很简单)
plot3d(cube3d(scaleMatrix(1.2,1.2,1.2)), alpha=0)
text3d(t(cube3d()$vb[1:3,]*1.05), texts=1:8)  # indices
shade3d(cube3d(), col=c(rep(2,4), rep(3,4), rep(4,4), rep(5,4), rep(6,4), rep(7,4)), alpha=0.8)
                #  ib[1:4, 1]  [1:4, 2]  [1:4, 3]  [1:4, 4]  [1:4, 5]  [1:4, 6]
              # index 1,3,4,2  3,7,8,4   2,4,8,6, ...

wire3d 规则(复杂而可怕..;已编辑)
text3d(t(cube3d()$vb[1:3,]*1.05), texts=1:8, font=2)  # indices
wire3d(cube3d(), col=c(rep(2,6), rep(3,6), rep(4,6), rep(5,6), rep(6,6), rep(7,6)))
# I gave each color 6 times.

index  1       3       4       2       1
ib$[1,1] - [2,1] - [3,1] - [4,1] - [1,1] - NA
 col   2       2       2       2       2    2  # Why NA uses a color!!??

index  3       7      8    4 (skipped) 3       # the line already has been drawn, skipped.
ib$[1,2] - [2,2] - [3,2] - [4,2] - [1,2] - NA; 
 col   3       3      3    3 (skipped) 3    3

index 2 (sk)   4 (sk)  8       6      2
ib$[1,3] - [2,3] - [3,3] - [4,3] - [1,3] - NA; 
 col 4  (sk)   4 (sk)  4       4       4    4,   and so on.

在一个ibcol中,一个顶点只有一种颜色(例如,在ib[,1]处,1-3和3-4都使用了Index3的颜色信息。当线已经被绘制时,它被跳过。使用 wire3d() 绘制不同颜色的线是 太难了(有些图案是不可能的)。如果你想做,最好使用 lines3d()segments3d()

dot3d 规则
plot3d(cube3d(scaleMatrix(1.2,1.2,1.2)), alpha=0)
text3d(t(cube3d()$vb[1:3,]*1.05), texts=1:8)  # indices
dot3d(cube3d(), col=1:8, size=8)

unique(c(cube3d()$ib))
# [1] 1 3 4 2 7 8 6 5

如果你给 col=1:8,不是 index2 但 index3 变成 col = 2 (red)。
所以,col = c("col1", "col2", ..., "col8")[unique(c(object$ib))] 意味着 index1 是 col1, index2 为 col2.