user101089 user101089 - 2 months ago 23
R Question

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

To demonstrate the effect of linear transformations in 3D,

x -> A x
, I want to draw a cube and show its transformation under
A
. For this, I need to color each face separately, and also show the vertex points and the lines that outline each face.

I can't figure out how to use distinct colors for the faces, and how to make this more general so I don't have to repeat all the steps for the result under the transformation.

what I tried:

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


This gives the image below. But I don't understand how the faces are colored. And, I seem to have to use
points3d
and
lines3d
on the components of the
c3d
shape, and don't have a single object I can transform.

enter image description here

A particular transformation is given by the matrix
A
below, and here is how I add that to the scene,

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)


This gives:

enter image description here

Is there some way to simplify this and make it more generally useful?

Answer

In rgl, when drawing primitive shapes, you apply colours to vertices, not faces. The faces are coloured by interpolating the colors at the vertices.

However, cube3d() is not a primitive shape, it's a "mesh". It is drawn as 6 separate quadrilaterals. Each vertex is used 3 times.

It's not really documented, but the order the colours are used is that the first 4 are used for one face, then the next 4 for the next face, etc. If you want your colours to be rainbow(6), you need to replicate each colour 4 times:

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

Screenshot of rendered cube

I'd recommend a higher alpha value; I find the transparency a little confusing at alpha = 0.5.

By the way, for the same purpose, I generally use a shape that looks more spherical as the baseline; I think it gives better intuition about the transformation. Here's code I have used:

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)

and this gives this shape:

sphere

which transforms to this:

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

transformed sphere

Of course, it all looks better if you can rotate it.