Read a Wavefront OBJ 3D scene file into an R list

read.obj(f, materialspath = NULL, convert.rgl = FALSE, triangulate = TRUE)

Arguments

f

Path to an OBJ file

materialspath

Path to a folder containing materials files. This is optional and only required if materials files are in a different folder from the OBJ file defined by f.

convert.rgl

Whether to convert the returned list to a rgl::shapelist3d object containing rgl::mesh3d objects.

triangulate

(default TRUE) Whether to convert all mesh faces to triangles. Note that only meshes with triangular or quad faces are supported, so setting triangulate=FALSE will throw an error for more complex files.

Value

When convert.rgl=FALSE, the default, a named list with items shapes and materials, each containing sublists with one entry per object (shapes) or material (materials). Objects in the shapes list have the following structure

  • positions 3 x N matrix of 3D vertices

  • indices 3/4 x M matrix of indices into vertex array (trimesh/quadmesh) 0-indexed

  • normals 3 x N matrix of normal directions for each vertex (missing when there are no normals)

  • normindices 3/4 x M matrix of indices into normals array (trimesh/quadmesh) 0-indexed (missing when there are no normals)

  • texcoords 2 x N matrix of texture coordinates (missing when there are no texture coordinates)

  • texindices 3/4 x M matrix of indices into texcoords array (trimesh/quadmesh) 0-indexed (missing when there are no texture coordinates)

  • nvfaces Raw vector specifying the number of vertices per face (missing unless triangulate=FALSE and there are a mixture of different numbers of vertices per face.)

  • material_ids 0-indexed, -1 when not set (missing when no materials)

When convert.rgl=TRUE a list of class shapelist3d containing a mesh3d for each object or group element in the original OBJ file. See tinyobj2shapelist3d for details of rgl conversion.

Details

tinyobjloader made some substantial changes to its data structures after the first code snapshot was taken for the this package in 2015. In order to benefit from bug fixes, we updated the code in 2020 but we note that tinyobjloader now de-duplicates vertices more aggressively e.g. in the situation where there are normals or texture coordinates. We were forced when converting to rgl::shapelist3d objects to revert these de-duplications on the R side in order for display in rgl; note that this only happens when there are texture coordinates and/or normals in the obj file.

Note that some fields in the tinyobjloader return structure will be omitted when they are not relevant for a given obj file. In this case, as with any R list, the list element will have the value NULL when tested. See examples.

Sample files

Note that at the request of the CRAN maintainers the sample files have the file extension .wavefront instead of the standard .obj because this triggers a false positive R CMD check NOTE.

See also

tinyobj2shapelist3d, rgl::readOBJ for simpler, pure R implementation.

Examples

cube=read.obj(system.file("obj/cube.wavefront", package = "readobj")) str(cube)
#> List of 2 #> $ shapes :List of 6 #> ..$ front cube :List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 0 1 2 0 2 3 #> .. ..$ material_ids: int [1:2] 0 0 #> ..$ back cube :List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 7 6 5 7 5 4 #> .. ..$ material_ids: int [1:2] 0 0 #> ..$ right cube :List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 3 2 6 3 6 7 #> .. ..$ material_ids: int [1:2] 1 1 #> ..$ top cube :List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 4 0 3 4 3 7 #> .. ..$ material_ids: int [1:2] 0 0 #> ..$ left cube :List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 4 5 1 4 1 0 #> .. ..$ material_ids: int [1:2] 2 2 #> ..$ bottom cube:List of 3 #> .. ..$ positions : num [1:3, 1:8] 0 2 2 0 0 2 2 0 2 2 ... #> .. ..$ indices : int [1:3, 1:2] 1 5 6 1 6 2 #> .. ..$ material_ids: int [1:2] 0 0 #> $ materials:List of 5 #> ..$ white:List of 13 #> .. ..$ ambient : num [1:3] 0 0 0 #> .. ..$ diffuse : num [1:3] 1 1 1 #> .. ..$ specular : num [1:3] 0 0 0 #> .. ..$ transmittance : num [1:3] 0 0 0 #> .. ..$ emission : num [1:3] 0 0 0 #> .. ..$ shininess : num 1 #> .. ..$ ior : num 1 #> .. ..$ dissolve : num 1 #> .. ..$ illum : int 0 #> .. ..$ ambient_texname : chr "" #> .. ..$ diffuse_texname : chr "" #> .. ..$ specular_texname: chr "" #> .. ..$ normal_texname : chr "" #> ..$ red :List of 13 #> .. ..$ ambient : num [1:3] 0 0 0 #> .. ..$ diffuse : num [1:3] 1 0 0 #> .. ..$ specular : num [1:3] 0 0 0 #> .. ..$ transmittance : num [1:3] 0 0 0 #> .. ..$ emission : num [1:3] 0 0 0 #> .. ..$ shininess : num 1 #> .. ..$ ior : num 1 #> .. ..$ dissolve : num 1 #> .. ..$ illum : int 0 #> .. ..$ ambient_texname : chr "" #> .. ..$ diffuse_texname : chr "" #> .. ..$ specular_texname: chr "" #> .. ..$ normal_texname : chr "" #> ..$ green:List of 13 #> .. ..$ ambient : num [1:3] 0 0 0 #> .. ..$ diffuse : num [1:3] 0 1 0 #> .. ..$ specular : num [1:3] 0 0 0 #> .. ..$ transmittance : num [1:3] 0 0 0 #> .. ..$ emission : num [1:3] 0 0 0 #> .. ..$ shininess : num 1 #> .. ..$ ior : num 1 #> .. ..$ dissolve : num 1 #> .. ..$ illum : int 0 #> .. ..$ ambient_texname : chr "" #> .. ..$ diffuse_texname : chr "" #> .. ..$ specular_texname: chr "" #> .. ..$ normal_texname : chr "" #> ..$ blue :List of 13 #> .. ..$ ambient : num [1:3] 0 0 0 #> .. ..$ diffuse : num [1:3] 0 0 1 #> .. ..$ specular : num [1:3] 0 0 0 #> .. ..$ transmittance : num [1:3] 0 0 0 #> .. ..$ emission : num [1:3] 0 0 0 #> .. ..$ shininess : num 1 #> .. ..$ ior : num 1 #> .. ..$ dissolve : num 1 #> .. ..$ illum : int 0 #> .. ..$ ambient_texname : chr "" #> .. ..$ diffuse_texname : chr "" #> .. ..$ specular_texname: chr "" #> .. ..$ normal_texname : chr "" #> ..$ light:List of 13 #> .. ..$ ambient : num [1:3] 1 1 1 #> .. ..$ diffuse : num [1:3] 1 1 1 #> .. ..$ specular : num [1:3] 0 0 0 #> .. ..$ transmittance : num [1:3] 0 0 0 #> .. ..$ emission : num [1:3] 0 0 0 #> .. ..$ shininess : num 1 #> .. ..$ ior : num 1 #> .. ..$ dissolve : num 1 #> .. ..$ illum : int 0 #> .. ..$ ambient_texname : chr "" #> .. ..$ diffuse_texname : chr "" #> .. ..$ specular_texname: chr "" #> .. ..$ normal_texname : chr ""
# elements will be NULL when not present in the obj file e.g. normals is.null(cube$shapes[[1]]$texcoords)
#> [1] TRUE
# demonstrate direct conversion of result to rgl format if(require('rgl')) { cuber=read.obj(system.file("obj/cube.wavefront", package = "readobj"), convert.rgl=TRUE) shade3d(cuber) }
#> Loading required package: rgl