r3drgl

Using rgl's extrude3d() function to make a 3D mesh from polygons in R


I'm trying to make a 3D OBJ file using R. My initial data is a Geopackage with multiple polygons. And I want to 'extrude' each polygon to make them 3d. The extrude amount should be determined by the value of an attribute of these polygons.

I have a geopackage with multiple polygons: Screenshot of data list. I am able to plot this data in 2d. 2d plot of data

Each of these polygons has an attribute called 'POINT...50'. I want to use the value of this attribute to determine the height ( z axis) of each polygon by extruding each polygon, but I can't get it to work. So far I have tried to do it with the extrude3d function.

Here is my initial data . Here is my code so far :

library(sf)
library(ggplot2)
library(rgl)
library(dplyr)

data <- st_read("data/métropole_de_lyon_LGT_LCI_500m.gpkg")

data|>
  ggplot() +
  geom_sf()

data |>
  extrude3d()

writeOBJ(data3D, '3d model')

I have also used the rayshader package to create a 3d visualization but the problem it that it rasterizes the data so the OBJ file it outputs is not satisfactory. So i want the same result but only using vector to have a clean 3D mesh. 3D visualisation made with rayshader The goal is to have a clean mesh like this one: Clean mesh


Solution

  • Here's an example of how to do this. It's probably not the neatest way to use sf, but it seems to work.

    library(sf)
    library(rgl)
    data <- st_read("~/temp/métropole_de_lyon_LGT_LCI_500m.gpkg")
    
    open3d(useNULL = TRUE) # don't need to draw on screen yet
    
    for (i in 1:nrow(data)) {
      thickness <- data[i,]$POINT...50
      if (!is.na(thickness))
        st_geometry(data)[[i]] |>
        as.matrix() |>
        extrude3d(thickness = thickness) |>
        shade3d()
    }
    
    writeOBJ("~/temp/test.obj", separateObjects = FALSE)
    
    open3d(useNULL = FALSE) # Now draw the file we saved
    readOBJ("~/temp/test.obj") |>
      shade3d(col = "red", alpha = 0.2)
    

    This produces an image like this:

    enter image description here