Title: | Read and Write '.gltf' and '.glb' Files |
---|---|
Description: | The 'glTF' file format is used to describe 3D models. This package provides read and write functions to work with it. |
Authors: | Duncan Murdoch [aut, cre], Morten S. Mikkelsen [cph] |
Maintainer: | Duncan Murdoch <[email protected]> |
License: | GPL-2 |
Version: | 1.0.7 |
Built: | 2024-11-25 16:29:46 UTC |
Source: | CRAN |
The glTF file is the JSON part of a glTF representation of a 3D scene. This function creates the R structure corresponding to one, and writes the binary buffer file for it.
as.gltf(x, ...) ## Default S3 method: as.gltf(x, y = NULL, z = NULL, vertices, material = NULL, normals = NULL, texcoords = NULL, points = NULL, segments = NULL, triangles = NULL, quads = NULL, transform = diag(4), extras = NULL, ..., rglscene = list(), previous = Gltf$new(), newScene = FALSE, parentNode = NULL, dir = tempdir(), scale = c(1,1,1)) ## S3 method for class 'rglscene' as.gltf(x, ..., previous = Gltf$new(), newScene = FALSE) ## S3 method for class 'mesh3d' as.gltf(x, ...)
as.gltf(x, ...) ## Default S3 method: as.gltf(x, y = NULL, z = NULL, vertices, material = NULL, normals = NULL, texcoords = NULL, points = NULL, segments = NULL, triangles = NULL, quads = NULL, transform = diag(4), extras = NULL, ..., rglscene = list(), previous = Gltf$new(), newScene = FALSE, parentNode = NULL, dir = tempdir(), scale = c(1,1,1)) ## S3 method for class 'rglscene' as.gltf(x, ..., previous = Gltf$new(), newScene = FALSE) ## S3 method for class 'mesh3d' as.gltf(x, ...)
x |
An object to convert to a |
y , z
|
In the default method, combined with |
vertices |
A 3 or 4 row matrix of Euclidean or homogeneous coordinates; takes
precedence over |
material |
material properties for rendering |
normals |
normals at each vertex as a 3 or 4 column matrix |
texcoords |
texture coordinates at each vertex as a 2 column matrix |
points |
vector of indices of vertices to draw as points |
segments |
2 x n matrix of indices of vertices to draw as segments |
triangles |
3 x n matrix of indices of vertices to draw as triangles |
quads |
4 x n matrix of indices of vertices to draw as quads |
transform |
4 x 4 matrix associated with this object (e.g. a subscene) |
extras |
A list to attach as |
... |
Other parameters passed to the default method. |
rglscene |
The RGL scene this came from, e.g. to look up defaults |
previous |
Optionally a previously produced |
newScene |
logical; if |
parentNode |
If not |
dir |
Where to write the binary buffer file. |
scale |
Rescaling in the enclosing subscene. |
as.gltf
is a generic function.
The method for "rglscene"
objects can handle most
objects produced by scene3d
, but not all
objects will be handled. In particular:
Lights, text, bounding box decorations and backgrounds are saved in “extra” fields, so they can be read by rgl2gltf, but most other software will ignore them or only display some parts.
Most material properties are also stored in “extra” fields.
There are methods for many individual types of "rglobject"
, but these are intended for internal
use.
A "gltf"
object.
Duncan Murdoch
The specification of the glTF format: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
cube <- rgl::rotate3d(rgl::cube3d(col = "red"), -pi/10, 1,0,0) gltf <- as.gltf(cube) rgl::plot3d(gltf) gltf$closeBuffers()
cube <- rgl::rotate3d(rgl::cube3d(col = "red"), -pi/10, 1,0,0) gltf <- as.gltf(cube) rgl::plot3d(gltf) gltf$closeBuffers()
These methods convert a "gltf"
object to
a "rglscene"
object, similar to what scene3d
would produce, or a "mesh3d"
object.
## S3 method for class 'gltf' as.rglscene(x, scene = x$scene, nodes = NULL, useRGLinfo = TRUE, time = NULL, ani = 0, clone = TRUE, quick = FALSE, add = FALSE, ...) ## S3 method for class 'gltf' as.mesh3d(x, ...)
## S3 method for class 'gltf' as.rglscene(x, scene = x$scene, nodes = NULL, useRGLinfo = TRUE, time = NULL, ani = 0, clone = TRUE, quick = FALSE, add = FALSE, ...) ## S3 method for class 'gltf' as.mesh3d(x, ...)
x |
The |
scene |
Which scene to convert? If |
nodes |
Which nodes to convert? If |
useRGLinfo |
|
time |
Set the "time" within an animation. |
ani |
Animation number to use. |
clone |
Whether to clone the |
quick |
If |
add |
If |
... |
|
These functions need to modify the glTF object, caching
some information to help with the conversion. By default
they do this on a cloned copy of it, and the original is
left unchanged. If the object has already been cloned
this can be skipped by setting clone = FALSE
.
An "rglscene"
object.
Extracts a texture from a glTF object, and writes it to a file.
extractTexture(gltf, index = 0, outfile = tempfile(), verbose = TRUE)
extractTexture(gltf, index = 0, outfile = tempfile(), verbose = TRUE)
gltf |
The glTF object. |
index |
The texture number (starting from 0). |
outfile |
The filename to write to. If |
verbose |
Whether to report on success. |
Since rgl doesn't support any texture format except PNG, this function will attempt to convert JPEG textures to PNG. To do that it needs to have the jpeg and png packages available.
Returns the filename that was written, or NULL
if the request failed.
If closeConnections = FALSE
, the filename will have
attribute "gltf"
containing the gltf
object which might now contain a new open connection.
If the texture has a recorded MIME type in gltf
,
that will be returned in attribute "mimeType"
.
findEntry
searches recursive objects for components
matching a condition. namePattern
creates a test of
whether the component name matches a pattern. hasClass
creates a test of whether the component has a class.
findEntry(x, test, ..., path = c()) namePattern(pattern) hasClass(class)
findEntry(x, test, ..., path = c()) namePattern(pattern) hasClass(class)
x |
The recursive object to search. |
test |
A test function. See Details below. |
pattern |
A regexp pattern to match the desired name(s). |
class |
A class name to search for. |
... |
Optional additional arguments to pass to the test function. |
path |
For internal use: names to prepend to the path. |
Utility/debugging functions to search a large recursive object for a particular component name or class.
The test
function should have header function(name, value)
, and may include other arguments which will
be taken from ...
.
findEntry
returns
a list with one entry per hit. Each entry in the list is a named vector
giving the path to the hit, numerically in the values, and as an R expression
by concatenating the names. The test functions will be passed
single names and values, and should return a single logical result.
x <- list( a = list( b = list(c(d="A", e="B"), 1L, 1:3))) locations <- findEntry(x, namePattern("e")) locations #This shows how the result can be used: x[[locations[[1]]]] expr <- paste0(c("x", names(locations[[1]])), collapse = "") expr eval(parse(text=expr)) findEntry(x, hasClass("integer"))
x <- list( a = list( b = list(c(d="A", e="B"), 1L, 1:3))) locations <- findEntry(x, namePattern("e")) locations #This shows how the result can be used: x[[locations[[1]]]] expr <- paste0(c("x", names(locations[[1]])), collapse = "") expr eval(parse(text=expr)) findEntry(x, hasClass("integer"))
This function generates tangent vectors using the MikkTSpace code by Morten S. Mikkelsen.
getTangents(obj)
getTangents(obj)
obj |
A triangles or quads object as returned by |
glTF files include normal textures, which require the tangent space to be specified: the normals at each vertex are supplemented with a tangent vector and a bitangent vector that is their cross product. The standard recommends that if the glTF file doesn't specify tangents, they should be generated using the MikkTSpace code.
Note that a comment in ‘mikktspace.h’ indicates that indexing needs to be recalculated after computing the tangents, so this function works on unindexed inputs, and reapplies indexing at the end.
A modified copy of the original object, adding a 4 column
tangents
entry. The order and number of indices
may have changed.
Morten S. Mikkelsen, Johannes Kuehnel and Duncan Murdoch.
The MikkTSpace code was obtained from https://github.com/mmikk/MikkTSpace. The interface code is based on code from https://www.turais.de/using-mikktspace-in-your-project/ by Johannes Kuehnel.
The glTF file spec is described here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html. This object encapsulates most of the data from those files.
rgl::Buffer
-> gltf
scene
The default scene number
rgl::Buffer$addBufferView()
rgl::Buffer$as.list()
rgl::Buffer$closeBuffer()
rgl::Buffer$closeBuffers()
rgl::Buffer$dataURI()
rgl::Buffer$getAccessor()
rgl::Buffer$getBuffer()
rgl::Buffer$getBufferview()
rgl::Buffer$load()
rgl::Buffer$openBuffer()
rgl::Buffer$openBufferview()
rgl::Buffer$readAccessor()
rgl::Buffer$readAccessor0()
rgl::Buffer$saveOpenBuffer()
rgl::Buffer$setAccessor()
rgl::Buffer$setBuffer()
rgl::Buffer$setBufferview()
rgl::Buffer$writeBuffer()
new()
Gltf$new(json = NULL, defaultbin = NULL)
json
List read from glTF file.
defaultbin
Optional external binary file.
addAccessor()
Write values to accessor, including min
and max
.
The glTF standard requires min
and max
values in
accessors, whereas other uses of buffers may not.
This function stores in the usual way using the
Buffer$addAccessor()
method, and then adds
min
and max
values.
The standard also doesn't support signed 4 byte integers or double precision values, so we test for those here.
Gltf$addAccessor(values, target = NULL, types = "anyGLTF", normalized = FALSE)
values
Values to write.
target
Optional target use for values.
types
Allowed types (from names of rgl::gltfTypes
), or c("any", "anyGLTF")
).
normalized
Are these normalized integer values?
New accessor number.
getScene()
Get scene object.
Gltf$getScene(sc)
sc
Scene number.
Scene object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-scene.
setScene()
Update scene record.
Gltf$setScene(sc, scene)
sc
Which scene to update.
scene
New scene record.
addScene()
Add a scene object.
Gltf$addScene()
Scene number.
addToScene()
Add node to scene.
Gltf$addToScene(scene, node)
scene
Scene number to modify.
node
Node number(s) to add.
defaultScene()
Get default scene, creating it if necessary.
Gltf$defaultScene()
Scene number.
getNode()
Get node object.
Gltf$getNode(n)
n
Node number.
Node object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-node.
setNode()
Set node object.
Gltf$setNode(n, node)
n
Node number.
node
New node object.
addNode()
Add a node object.
Gltf$addNode(mesh = NULL, matrix = NULL, extras = NULL)
mesh
A mesh number.
matrix
A matrix transformation for the node.
extras
A list of extras, typically rgl
objects.
Node number.
addChild()
Add node as child of another.
Gltf$addChild(parent, node)
parent
Node number to modify.
node
Node number(s) to add as children.
setParents()
Set parent member for all nodes
Gltf$setParents()
getSkin()
Get skin object.
Gltf$getSkin(skin)
skin
Skin number.
Skin object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-skin.
setSkin()
Set skin object.
Gltf$setSkin(n, skin)
n
Skin number.
skin
New skin object.
getJoint()
Get joint node.
Gltf$getJoint(skin, num)
skin
Skin number.
num
Joint number.
Node object
getInverseBindMatrices()
Get "inverse bind matrices".
These matrices undo the existing transformation before applying the skin transformations.
Gltf$getInverseBindMatrices(skin)
skin
Skin number.
A 4x4xn array of matrices, one per joint.
getForwardBindMatrices()
Get "forward bind matrices".
These matrices applying the skin transformations.
Gltf$getForwardBindMatrices(skin)
skin
Skin number.
A 4x4xn array of matrices, one per joint.
getCamera()
Get camera object.
Gltf$getCamera(cam)
cam
Camera number.
Camera object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera.
getExtras()
Get top-level extras list.
Gltf$getExtras()
Extras list, including rgl objects.
setExtras()
Set extras list.
Gltf$setExtras(extras)
extras
New extras list.
getMesh()
Get mesh object.
Gltf$getMesh(m)
m
Mesh number.
Mesh object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-mesh.
setMesh()
Set mesh object.
Gltf$setMesh(m, mesh)
m
Mesh number.
mesh
New mesh object
addMesh()
Add a mesh object.
Gltf$addMesh(primitives)
primitives
A list of primitive objects.
Mesh number.
getMaterial()
Get material object.
Gltf$getMaterial(m)
m
Material number.
Material object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material.
getTexture()
Get texture object.
Gltf$getTexture(tex)
tex
Texture number.
Texture object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-texture.
getImage()
Get image object.
Gltf$getImage(im)
im
Image number.
Image object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-image.
addMaterial()
Construct and possibly add material.
This will return an existing material if possible.
Gltf$addMaterial(mat, defaultMaterial = list())
mat
An rgl
material record.
defaultMaterial
Default material properties.
Material number.
addTexture()
Add a texture.
Gltf$addTexture(mat)
mat
An rgl
material record.
Texture number.
addImage()
Add an image for a texture.
Gltf$addImage(mat)
mat
An rgl
material record.
Image number.
addSampler()
Add a sampler.
Gltf$addSampler(mat)
mat
An rgl
material record.
Sampler number.
getMaterialNumber()
Add or return a material.
Gltf$getMaterialNumber(material)
material
A glTF material record.
Material number.
writeVectors()
Write data.
Gltf$writeVectors( coords, target = targetArray, types = "anyGLTF", normalized = FALSE )
coords
Data to write, or NULL
.
target
Optional target use for data.
types
A character vector of allowed types, or "any" or "anyGLTF"
normalized
Are these integer values representing floats?
Accessor number, or NULL
.
makePrimitive()
Create a primitive record.
Gltf$makePrimitive(inds, mode = NULL, attributes = NULL, matnum = NULL)
inds
Indices of vertices.
mode
Mode of primitive.
attributes
Primitive attributes.
matnum
Material number.
Primitive record, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-primitive.
getAsset()
Get asset list.
Gltf$getAsset()
Asset object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-asset.
setAsset()
Set asset list.
Gltf$setAsset(version, generator)
version
Version number of glTF format.
generator
Identifier of code generating it.
getTransform()
Get local transform.
Gltf$getTransform(n)
n
Node number.
4x4 matrix of local transform.
getRglMaterial()
Reconstruct rgl
material.
Gltf$getRglMaterial(n)
n
Material number.
rgl
material record.
getAnimation()
Get animation.
Gltf$getAnimation(ani)
ani
Animation number
Animation object, documented here: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-animation.
setAnimation()
Set animation.
Gltf$setAnimation(ani, animation)
ani
Animation number
animation
New animation object
timerange()
Find time range of an animation
Gltf$timerange(ani)
ani
Animation number
Min and max times from the samplers in the animation.
initAnimation()
Initialize animation.
This builds all of the interpolation functions in the samplers.
Gltf$initAnimation(ani)
ani
Animation number
Modified animation object
settime()
Set time for an animation.
This evaluates all the interpolators and modifies self to reflect the specified time point.
Gltf$settime(time, ani = 0)
time
Time to set.
ani
Animation number.
Vector of node numbers that were changed.
print()
Print gltf
objects with various levels of detail.
Gltf$print(verbose = FALSE, names = FALSE, showExtras = TRUE, ...)
verbose
Logical indicator of verbose printing, or character vector of components to print verbosely.
names
Print names for components.
showExtras
Logical: show extra fields?
...
Passed ...
.
\donttest{ samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" gltf <- readGLB(paste0(samples, "/2CylinderEngine/glTF-Binary/2CylinderEngine.glb?raw=true")) gltf$print(names = "meshes") }
listCount()
Get number of items in private list.
Gltf$listCount(list)
list
Name of list to get.
clone()
The objects of this class are cloneable with this method.
Gltf$clone(deep = FALSE)
deep
Whether to make a deep clone.
## ------------------------------------------------ ## Method `Gltf$print` ## ------------------------------------------------ samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" gltf <- readGLB(paste0(samples, "/2CylinderEngine/glTF-Binary/2CylinderEngine.glb?raw=true")) gltf$print(names = "meshes")
## ------------------------------------------------ ## Method `Gltf$print` ## ------------------------------------------------ samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" gltf <- readGLB(paste0(samples, "/2CylinderEngine/glTF-Binary/2CylinderEngine.glb?raw=true")) gltf$print(names = "meshes")
This creates a widget holding a glTF scene, with controls to animate it if it supports animation, and with shaders that implement normal textures.
gltfWidget(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), method = c("shader", "rigid"), add = FALSE, close = !add, verbose = FALSE, open3dParams = getr3dDefaults(), usePBR = hasPBRparams(gltf), PBRargs = list(), ...)
gltfWidget(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), method = c("shader", "rigid"), add = FALSE, close = !add, verbose = FALSE, open3dParams = getr3dDefaults(), usePBR = hasPBRparams(gltf), PBRargs = list(), ...)
gltf |
A |
animation |
Which animation to use? If no animation is present, this is ignored. |
start , stop
|
The starting and stopping times for the animation. Ignored if no animation. |
times |
An alternate way to specify the times. Ignored if no animation. |
method |
The
|
add |
Should the gltf object be added to an existing rgl scene, or should it open a new scene? |
close |
Should |
verbose |
Give some progress information. |
open3dParams |
A list to pass as the |
usePBR |
Whether to use physically based rendering methods.
The default
uses an internal function to determine if |
PBRargs |
A list containing optional arguments to the |
... |
Additional parameters which will be passed to |
See playgltf
for a description of the method
used for animation. The "fixed"
method is fast, but
doesn't do a good job on some animations.
If the gltf
object doesn't contain any animations,
or animation = NA
, this
will simply display it as a widget with no controls.
A widget suitable for display or inclusion in an R Markdown document.
Physically based rendering (PBR, controlled by usePBR
) is
only used with method = "shader"
.
If PBR is not used, the V8 package is required so that the shaders can be modified.
if ((interactive() || rgl::in_pkgdown_example()) && requireNamespace("manipulateWidget")) { gltf <- readGLB(system.file("glb/RiggedSimple.glb", package = "rgl2gltf")) gltfWidget(gltf) }
if ((interactive() || rgl::in_pkgdown_example()) && requireNamespace("manipulateWidget")) { gltf <- readGLB(system.file("glb/RiggedSimple.glb", package = "rgl2gltf")) gltfWidget(gltf) }
These generic functions are imported from rgl.
plot3d(x, ...) as.rglscene(x, ...) as.mesh3d(x, ...)
plot3d(x, ...) as.rglscene(x, ...) as.mesh3d(x, ...)
x |
Objects to handle. |
... |
Additional arguments to pass to methods. |
The main documentation for these generics is in rgl:
plot3d
.
This package defines "gltf"
methods for the generics.
Documentation for as.rglscene.gltf
is included.
This is used for debugging, to see how an object within nested rgl subscenes is affected by their user matrices.
matrixSequence(tag, scene = scene3d()) ## S3 method for class 'matrixSequence' print(x, n = 5, ...)
matrixSequence(tag, scene = scene3d()) ## S3 method for class 'matrixSequence' print(x, n = 5, ...)
tag |
Which objects to report on? |
scene |
The rgl scene to work from. |
x |
Object to print. |
n |
In the print method, how many vertices and indices should be printed? |
... |
Ignored. |
A list containing records with entries as follows:
id |
The object id |
vertices |
The object's vertices |
indices |
The object's indices |
userMatrix |
A list of user matrices affecting this object |
This function applies specified edits to shader code to support new functions.
modifyShaders(shaders, mod, ...)
modifyShaders(shaders, mod, ...)
shaders |
A list of shaders, e.g. as produced by |
mod |
Either a character value naming a built-in set of mods (currently just |
... |
Optional arguments; all will be passed to any functions
in |
The mods
argument is organized in a nested list.
The top level can contain vertexShader
and
fragmentShader
components.
Each of those is a list of changes to apply to that shader.
Each change is a list with old
and new
entries.
The old
entry is used as a "fixed" pattern to
select one or more lines from the shader to be replaced.
Multiple matches are allowed, but they shouldn't overlap.
Changes will be applied in the order specified, so take care
that a pattern doesn't match new text from an earlier change.
The new
entry contains the replacement. It
can either be a character vector or a function that returns
a character vector. If it is a function, it will be passed
the ...
argument.
See rgl2gltf:::shaderChanges
for the built-in modifications.
A new shader object incorporating the edits.
‘.gltf’ and ‘.glb’ files can contain animation instructions. This function interprets them and plays them.
playgltf(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), method = c("rigid", "wholeScene", "partialScene"), speed = 1, by = NULL, verbose = FALSE, ...) showNodes(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), speed = 1, by = NULL)
playgltf(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), method = c("rigid", "wholeScene", "partialScene"), speed = 1, by = NULL, verbose = FALSE, ...) showNodes(gltf, animation = 0, start = times[1], stop = times[2], times = gltf$timerange(animation), speed = 1, by = NULL)
gltf |
A |
animation |
Which animation from the object? An integer from 0 to the
number of animations defined in |
start , stop
|
Starting and stopping times. |
times |
An alternate way to specify |
method |
Which drawing method to use? See details below. |
speed , by
|
Control the updates; see details below. |
verbose |
Whether to print status updates. |
... |
Parameter settings to pass to |
glTF files are animated by time dependent changes to the
transformations in their nodes. Those transformations
correspond to RGL par3d("userMatrix")
settings in
subscenes and can sometimes be directly imported as such.
However, glTF files also support "skins", a computer graphics concept not supported in RGL. A skin is a way to say that different vertices of the same object (typically a triangle mesh) respond to different nodes. This allows shapes to be stretched, similar to skin on a moving body. RGL assumes that all graphics objects are rigid.
The playgltf
function provides partial support for
skins. Using the "wholeScene"
method, it can modify the vertices of an entire scene
and redraw the scene. Typically this is quite slow, and
not very satisfactory. The "partialScene"
method
allows only the
changed objects to be redrawn, which might help speed things up.
Finally, the "rigid"
method converts all polygons
to rigid ones that are supported by rgl, so that motion
is done by changes to the transformations. This is likely the fastest
method, but for some animations the errors introduced by the
conversion are unacceptably large.
The showNodes
function displays each node number as
text at the origin for that node. By default it plays the
animation showing how the nodes move.
For both functions, the speed
and by
arguments
specify the “times” at which the animation is drawn. If
by
is specified, then a frame is drawn at time start
and
subsequent frames increment the time by by
. If it is
NULL
(the default), then the speed
argument is used
as a multiplier on the internal time (taken to be in seconds).
For example, with the default speed = 1
, the first frame will
be drawn at time start
, and when it is complete, the next one
will be drawn according to how many seconds have passed in real time,
etc.
Called for the side effect of drawing the animation.
if (interactive() && !rgl::in_pkgdown_example()) { # This example is fast enough using the "whole" method: gltf1 <- readGLB(system.file("glb/RiggedSimple.glb", package = "rgl2gltf")) playgltf(gltf1, start = 0, stop = 3, method = "whole") # It looks terrible using the "rigid" method, because some triangles # need to be deformed: playgltf(gltf1, start = 0, stop = 3, method = "rigid") # This example is too slow using anything but "rigid", but it's fine there: samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" gltf2 <- readGLB(paste0(samples, "/BrainStem/glTF-Binary/BrainStem.glb?raw=true")) playgltf(gltf2, start = 0, stop = 2, speed = 0.25, method = "rigid") }
if (interactive() && !rgl::in_pkgdown_example()) { # This example is fast enough using the "whole" method: gltf1 <- readGLB(system.file("glb/RiggedSimple.glb", package = "rgl2gltf")) playgltf(gltf1, start = 0, stop = 3, method = "whole") # It looks terrible using the "rigid" method, because some triangles # need to be deformed: playgltf(gltf1, start = 0, stop = 3, method = "rigid") # This example is too slow using anything but "rigid", but it's fine there: samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" gltf2 <- readGLB(paste0(samples, "/BrainStem/glTF-Binary/BrainStem.glb?raw=true")) playgltf(gltf2, start = 0, stop = 2, speed = 0.25, method = "rigid") }
GLB is the self-contained binary format of glTF
files. This function reads one, extracts the embedded files
into the temporary directory, and returns a "gltf"
object containing the information in R format.
readGLB(con, verbose = FALSE, ...)
readGLB(con, verbose = FALSE, ...)
con |
The connection or filename to read from. |
verbose |
Whether to report on the process. |
... |
Currently unused. |
An object of class "gltf"
. This is an R version of
the structure represented by a “glTF” file's JSON
information.
Duncan Murdoch
The specification of the glTF format: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" # Get one of them: an avocado gltf <- readGLB(paste0(samples, "/Avocado/glTF-Binary/Avocado.glb?raw=true")) if (interactive()) rgl::plot3d(gltf) if (rgl::in_pkgdown_example()) gltfWidget(gltf) gltf$closeBuffers()
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" # Get one of them: an avocado gltf <- readGLB(paste0(samples, "/Avocado/glTF-Binary/Avocado.glb?raw=true")) if (interactive()) rgl::plot3d(gltf) if (rgl::in_pkgdown_example()) gltfWidget(gltf) gltf$closeBuffers()
The glTF file is the JSON part of a glTF representation of a 3D
scene. This function reads one and returns a "gltf"
object containing the information in R format.
Typically most of the data for the scene is contained in other files named in this one, usually found in the same file folder.
readglTF(path, defaultbin = NULL, ...)
readglTF(path, defaultbin = NULL, ...)
path |
The path to the file being read. R connections cannot be used. |
defaultbin |
The name of the default associated binary file, if it is not named in the JSON. This is typically used when the JSON has been extracted from a GLB file. |
... |
Not currently used. |
An object of class "gltf"
.
Duncan Murdoch
The specification of the glTF format: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" filename <- tempfile(fileext = ".gltf") # Get one of them: a 2 cylinder engine. We need both parts # to be able to view it, though only the .gltf part is # needed for readglTF() download.file(paste0(samples, "/2CylinderEngine/glTF/2CylinderEngine.gltf"), destfile = filename) download.file(paste0(samples, "/2CylinderEngine/glTF/2CylinderEngine0.bin?raw=true"), destfile = file.path(tempdir(), "2CylinderEngine0.bin"), mode = "wb") gltf <- readglTF(filename) gltf # gltf files contain references to other files using # relative paths, so we can only use them from their # own directory olddir <- setwd(dirname(filename)) rgl::plot3d(gltf) setwd(olddir)
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" filename <- tempfile(fileext = ".gltf") # Get one of them: a 2 cylinder engine. We need both parts # to be able to view it, though only the .gltf part is # needed for readglTF() download.file(paste0(samples, "/2CylinderEngine/glTF/2CylinderEngine.gltf"), destfile = filename) download.file(paste0(samples, "/2CylinderEngine/glTF/2CylinderEngine0.bin?raw=true"), destfile = file.path(tempdir(), "2CylinderEngine0.bin"), mode = "wb") gltf <- readglTF(filename) gltf # gltf files contain references to other files using # relative paths, so we can only use them from their # own directory olddir <- setwd(dirname(filename)) rgl::plot3d(gltf) setwd(olddir)
The glTF format is designed to hold objects which are intended for "physically based rendering", where the parameters of the object map to physical properties such as metallicity, roughness, etc. This function replaces the default rgl shaders with PBR shaders based on the reference implementation in https://github.com/KhronosGroup/glTF-Sample-Viewer/tree/88eda8c5358efe03128b72b6c5f5f6e5b6d023e1/shaders.
setPBRshaders(gltf, gltfMat, id, scene = scene3d(minimal = TRUE), useIBL = TRUE, brdfLUT = system.file("textures/brdfLUT.png", package = "rgl2gltf"), IBLspecular = system.file("textures/refmap.png", package = "rgl"), IBLdiffuse = system.file("textures/refmapblur.jpeg", package = "rgl2gltf"), debugBaseColor = 0, debugMetallic = 0, debugRoughness = 0, debugSpecularReflection = 0, debugGeometricOcclusion = 0, debugMicrofacetDistribution = 0, debugSpecContrib = 0, debugDiffuseContrib = 0, debugIBLDiffuse = 1, debugIBLSpecular = 1, defines = list(), uniforms = list(), attributes = list(), textures = list())
setPBRshaders(gltf, gltfMat, id, scene = scene3d(minimal = TRUE), useIBL = TRUE, brdfLUT = system.file("textures/brdfLUT.png", package = "rgl2gltf"), IBLspecular = system.file("textures/refmap.png", package = "rgl"), IBLdiffuse = system.file("textures/refmapblur.jpeg", package = "rgl2gltf"), debugBaseColor = 0, debugMetallic = 0, debugRoughness = 0, debugSpecularReflection = 0, debugGeometricOcclusion = 0, debugMicrofacetDistribution = 0, debugSpecContrib = 0, debugDiffuseContrib = 0, debugIBLDiffuse = 1, debugIBLSpecular = 1, defines = list(), uniforms = list(), attributes = list(), textures = list())
gltf , gltfMat
|
A |
id , scene
|
The rgl id of the corresponding object and the scene holding it. |
useIBL |
Whether to use image based lighting. |
brdfLUT |
The texture to use for the "bidirectional reflectance distribution function" lookup table. |
IBLspecular |
The texture to use for the "image based specular lighting". |
IBLdiffuse |
The texture to use for the "image based diffuse lighting". |
debugBaseColor , debugMetallic , debugRoughness , debugSpecularReflection , debugGeometricOcclusion , debugMicrofacetDistribution , debugSpecContrib , debugDiffuseContrib
|
These are flags used for debugging. Setting one of these to 1 will display just that contribution to the rendering. |
debugIBLDiffuse , debugIBLSpecular
|
Two more debugging settings. These should be set to non-negative values to control the contribution from each of those components to the image based lighting. |
defines , uniforms , attributes , textures
|
Values to use in |
rgl is designed to work with WebGL version 1, which doesn't support all of the features used in the reference shaders. In particular, no extensions are assumed, and the IBL textures are single 2D textures rather than cube maps.
This function modifies the id
object in scene
,
and returns the modified scene.
Duncan Murdoch for the adaptation to rgl, various others for the original shaders.
https://github.com/KhronosGroup/glTF-Sample-Viewer
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" # Get one of them: a 2 cylinder engine gltf <- readGLB(paste0(samples, "/NormalTangentTest/glTF-Binary/NormalTangentTest.glb?raw=true")) gltfMat <- gltf$getMaterial(0) scene <- as.rglscene(gltf) id <- scene$objects[[1]]$id scene <- setPBRshaders(gltf, gltfMat, id, scene) cat(scene$objects[[1]]$userFragmentShader)
# This web page has lots of sample files samples <- "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0" # Get one of them: a 2 cylinder engine gltf <- readGLB(paste0(samples, "/NormalTangentTest/glTF-Binary/NormalTangentTest.glb?raw=true")) gltfMat <- gltf$getMaterial(0) scene <- as.rglscene(gltf) id <- scene$objects[[1]]$id scene <- setPBRshaders(gltf, gltfMat, id, scene) cat(scene$objects[[1]]$userFragmentShader)
This function uses text3d
to display the tags
at the center of the objects they label.
showTags(tags = NULL, ids = NULL, subscenes = ids3d("subscene", subscene = 0)$id, depth_test = "always", ...)
showTags(tags = NULL, ids = NULL, subscenes = ids3d("subscene", subscene = 0)$id, depth_test = "always", ...)
tags , ids
|
If non-NULL, display only these tags and ids. |
subscenes |
Which subscenes to examine. |
depth_test |
The |
... |
Other arguments to pass to |
If selected objects don't have tags, they will be labelled
using their id
value instead.
The rgl ids of the text objects added (one text object per tagged object, with tags as names).
example("plot3d", package = "rgl") showTags()
example("plot3d", package = "rgl") showTags()
glTF files contain nodes corresponding to objects and groups of objects in 3D scenes. They must be a tree or forest: a node can only have zero or one parent. This function displays that structure, or the similar structure for rglscene objects.
showtree(x, ...) ## S3 method for class 'gltf' showtree(x, ...) ## S3 method for class 'rglscene' showtree(x, transform = FALSE, ...)
showtree(x, ...) ## S3 method for class 'gltf' showtree(x, ...) ## S3 method for class 'rglscene' showtree(x, transform = FALSE, ...)
x |
A |
transform |
Whether to show the transform associated with a subscene. |
... |
Additional arguments, currently unused. |
GLB is the self-contained binary format of glTF
files. These functions write a "gltf"
object to one of these formats.
writeglTF(x, path, bin = TRUE) writeGLB(x, con)
writeglTF(x, path, bin = TRUE) writeGLB(x, con)
x |
A |
path |
A filename in which to write the JSON part of the file. |
bin |
logical; whether or not to write the binary part of the object. |
con |
A filename or connection to which to write the GLB file. |
If bin = TRUE
(the default),
writeglTF
will write the binary part of the object
to one or more separate files with filename constructed by
concatenating the main part of path
, followed by a number
and the extension ‘.bin’.
writeglTF
returns path
invisibly.
writeGLB
returns NULL
invisibly.
Duncan Murdoch
The specification of the glTF format: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html
filename <- tempfile(fileext = ".glb") writeGLB(as.gltf(rgl::cube3d(col = "red")), filename)
filename <- tempfile(fileext = ".glb") writeGLB(as.gltf(rgl::cube3d(col = "red")), filename)