dmurdoch / rgl

rgl is a 3D visualization system based on OpenGL. It provides a medium to high level interface for use in R, currently modelled on classic R graphics, with extensions to allow for interaction.
https://dmurdoch.github.io/rgl/
GNU General Public License v2.0
85 stars 20 forks source link

writePLY() exports vertex colors as float instead of uchar #425

Closed aidanmorales closed 3 months ago

aidanmorales commented 3 months ago

Hi. I am using your excellent rgl library in my package rTwig to efficiently export and visualize cylinder meshes of tree. I found an issue with the writePLY() function on both the latest CRAN and development versions.

The issue is that custom colors applied to vertices display correctly in the plotting window, but are not correctly applied when using writePLY(), and do not display properly when opening the file in third party applications. I believe the issue is that the header of the .ply file assigns the RGBA colors as float, instead of uchar.

If I manually edit the header of the exported .ply file:

property float red property float green property float blue property float alpha

to

property uchar red property uchar green property uchar blue property uchar alpha

the colors are now displayed properly in third party applications, such as CloudCompare, for example. Is it possible to modify writePLY() to export RGBA colors as unsigned char instead of floating point?

Here is a reproducible example:

# Import rgl 
library(rgl)

 # Function to generate n random colors
generate_random_colors<- function(n) {
  colors <- replicate(n, {
    r <- sprintf("%02X", sample(0:255, 1))
    g <- sprintf("%02X", sample(0:255, 1))
    b <- sprintf("%02X", sample(0:255, 1))
    paste0("#", r, g, b)
  })
  return(colors)
}

# Temp file 
filename <- tempfile(pattern = "mesh",  fileext = ".ply")

# Generate mesh
mesh <- icosahedron3d()

# Assign colors to vertices
colors <- generate_random_colors(length(mesh$vb))
mesh$material$color <- colors

# Plot mesh
open3d()
shade3d(mesh)

# Export mesh
writePLY(filename, withColors = TRUE, format = "ascii")

The issue was also documented in this stackoverflow thread a few years ago: https://stackoverflow.com/questions/39239298/

dmurdoch commented 3 months ago

I think an argument could be made that those other applications should support float, but uchar is indeed the recommended type. The trouble is that the current code puts together a big matrix of values and writes them all using the float format. Mixing some float and some uchar will make writing more complicated and probably slower. Still, I suspect the speed difference doesn't matter, so I'll look into it.

dmurdoch commented 3 months ago

@aidanmorales : Okay, I have made some changes, but I don't use PLY format much, so I don't know if they are correct. In particular, the colors aren't being displayed the way they look in R, but that might be the fault of the viewer (which is F3D 2.4.0). Could you build rgl from the writePLY branch and see if things work with your viewer? If not, can you take a look at the output file or source and suggest what needs changing?

aidanmorales commented 3 months ago

@dmurdoch Thanks for looking into this! I tested your new patch in my package and everything works flawlessly. In terms of the speed difference, withColors = TRUE has a very slight performance hit, but it is still very fast and can export >100,000 vertices in a few seconds. I will mark this issue as closed, since this solved all of the issues I had with the function.