Search code examples
rplotlymeshrgl

Is it possible to create mesh3d objects without indices information?


I have a matrix of landmarks that denotes a nose. I wish to convert this matrix to mesh3d so that I could use shade3d function to visualize the surface.

Here is the dput of my data. I have to deposit it in GitHub because it is too large to be directly put here.

The three columns are x, y, and z coordinates. I would like to ask how can I convert this matrix to mesh3d. I tried as.mesh3d, however, I was returned error because the number of vertices is not a multiple of 3 or 4.

mesh.d <- as.mesh3d(deformed, triangles = T)

Error in as.mesh3d.default(deformed, triangles = T) : length(x)%%3 == 0 is not TRUE

I also tried to remove the last two rows so that my data has 621 rows, which is a multiple of 3. I then used shade3d to plot. However, the resultant plot does not give surface mesh of a nose. The function mesh3d requires input of not just vertices, but also indices which I do not have. I therefore ask if it is possible to convert my coordinate matrix to an object of mesh3d in R?


Solution

  • The indices describe the triangles formed from triplets of vertices. If you don't have them given to you, you will need to construct them somehow.

    There are a few options. You can use the alphashape3d::ashape3d function to approximate the outline of the points. You need to choose the alpha parameter; for example, with alpha = 20 I get

    ash <- ashape3d(as.matrix(nose), alpha=20)
    shade3d(as.mesh3d(ash))
    

    screenshot

    This would work even if the points were randomly rearranged, but in fact, if you plot

    plot3d(nose, type = "l")
    

    you can see that the points are very regularly organized:

    screenshot2

    If you can work out how they are organized, you might be able to rearrange the x, y and z coordinates into matrices and use surface3d() to plot them. For example, this plots all but the first 23 points:

    m1x <- matrix(nose[24:323,1], nrow=20)
    m1y <- matrix(nose[24:323,2], nrow=20)
    m1z <- matrix(nose[24:323,3], nrow=20)
    m2x <- matrix(nose[324:623,1], nrow=20)
    m2y <- matrix(nose[324:623,2], nrow=20)
    m2z <- matrix(nose[324:623,3], nrow=20)
    mx <- cbind(m1x[,15:1], m2x)
    my <- cbind(m1y[,15:1], m2y)
    mz <- cbind(m1z[,15:1], m2z)
    library(rgl)
    open3d()
    surface3d(mx, my, mz, col = "gray")
    

    screenshot3

    You can see that the alpha3d plot fills out the side of the nose too much. However, this one ignores 23 points; I can't really see how they should be incorporated.