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
形状的组件上使用 points3d
和 lines3d
,并且没有一个我可以转换的对象。
下面的矩阵 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]
最重要的规则是一个顶点在使用时消耗一种颜色(但它有点复杂,请看下面的例子)。我在下面调用矩阵 ib 和 mesh3d.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.
在一个ib
的col
中,一个顶点只有一种颜色(例如,在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
.
为了演示 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
形状的组件上使用 points3d
和 lines3d
,并且没有一个我可以转换的对象。
下面的矩阵 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]
最重要的规则是一个顶点在使用时消耗一种颜色(但它有点复杂,请看下面的例子)。我在下面调用矩阵 ib 和 mesh3d.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, ...
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.
在一个ib
的col
中,一个顶点只有一种颜色(例如,在ib[,1]
处,1-3和3-4都使用了Index3的颜色信息。当线已经被绘制时,它被跳过。使用 wire3d()
绘制不同颜色的线是 太难了(有些图案是不可能的)。如果你想做,最好使用 lines3d()
或 segments3d()
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
.