【问题标题】:rgl: drawing a cube with colored faces, vertex points and linesrgl:绘制一个带有彩色面、顶点和线的立方体
【发布时间】:2017-02-05 10:52:22
【问题描述】:

为了演示线性变换在 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)

这给出了:

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

【问题讨论】:

    标签: r linear-algebra rgl


    【解决方案1】:

    rgl 中,绘制原始形状时,您将颜色应用于顶点,而不是面。通过在顶点处插入颜色来对面进行着色。

    但是,cube3d() 不是原始形状,它是一个“网格”。它被绘制为 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)
    

    当然,如果你可以旋转它看起来会更好。

    【讨论】:

    • 如果能记录下这种颜色行为就好了。如何绘制点和线也不明显。也许我的例子可以用来说明这些事情。
    • 为什么不向文档提交补丁?
    【解决方案2】:

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

    在创建类mesh3d 对象时提供颜色信息不是一个好主意,因为shade3d()wire3d()dot3d() 以不同的方式使用它。绘制对象时最好给绘图函数一个颜色信息。

    例如;
    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],Index3 的颜色信息同时用于 1-3 和 3-4。当线条已经被绘制时,略过。用wire3d()画不同颜色的线太难了(有些图案是不可能的)。如果你想做,最好用lines3d()或@987654346 @

    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 = 2red)。
    所以,col = c("col1", "col2", ..., "col8")[unique(c(object$ib))]意味着index1是col1,index2是col2

    【讨论】:

      【解决方案3】:

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

      # 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],])
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-14
        • 2011-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-18
        相关资源
        最近更新 更多