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.
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:
Is there some way to simplify this and make it more generally useful?
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:I'd recommend a higher
alpha
value; I find the transparency a little confusing atalpha = 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:
and this gives this shape:
which transforms to this:
Of course, it all looks better if you can rotate it.
The second part of my question-- how to generalize this a bit -- was unanswered. Here is a simple function I'm now using to make the steps reusable.
(Note: I use
rgl version 0.96.0
. If my memory is correct,wire3d()
anddot3d()
rules have been changed)It isn't a good idea to give a color informatin when you make a class
for example;mesh3d
object, becauseshade3d()
,wire3d()
anddot3d()
use it in the different ways. It would be better to give plot-function a color information when you draw a object.[ the details related to colors and mesh3d.obj ]
Most important rule is that a vertex consumes a color whenever it is used (but it is a bit complex, please see below exampe). I call below matrix ib and
shade3d() rule (it's easy)mesh3d.obj$vb
's col number index .wire3d rule (complex and terrible..; edited)
In one
ib
'scol
, one vertex have only one color (e.g., atib[,1]
, Index3's color information is used both 1-3 and 3-4. When the line already has been drawn, it is skipped. It is too difficult (some patterns is impossible) to draw lines in different colors usingwire3d()
. If you want to do, it would be better to uselines3d()
orsegments3d()
dot3d rule
if you give
col=1:8
, NOT index2 but index3 becomescol = 2
(red
).So,
col = c("col1", "col2", ..., "col8")[unique(c(object$ib))]
means index1 iscol1
, index2 iscol2
.