class
TinyGltfImporterTinyGltf importer plugin.
Imports glTF (*.gltf
) and binary glTF (*.glb
) files using the TinyGLTF library.
This plugin provides the GltfImporter
plugin.
Usage
This plugin depends on the Trade library and the AnyImageImporter plugin and is built if MAGNUM_WITH_TINYGLTFIMPORTER
is enabled when building Magnum Plugins. To use as a dynamic plugin, load "TinyGltfImporter"
via Corrade::
Additionally, if you're using Magnum as a CMake subproject, bundle the magnum-plugins repository and do the following:
set(MAGNUM_WITH_ANYIMAGEIMPORTER ON CACHE BOOL "" FORCE) add_subdirectory(magnum EXCLUDE_FROM_ALL) set(MAGNUM_WITH_TINYGLTFIMPORTER ON CACHE BOOL "" FORCE) add_subdirectory(magnum-plugins EXCLUDE_FROM_ALL) # So the dynamically loaded plugin gets built implicitly add_dependencies(your-app MagnumPlugins::TinyGltfImporter)
To use as a static plugin or as a dependency of another plugin with CMake, put FindMagnumPlugins.cmake into your modules/
directory, request the TinyGltfImporter
component of the MagnumPlugins
package and link to the MagnumPlugins::TinyGltfImporter
target:
find_package(MagnumPlugins REQUIRED TinyGltfImporter) # ... target_link_libraries(your-app PRIVATE MagnumPlugins::TinyGltfImporter)
See Downloading and building plugins, Plugin usage with CMake, Loading and using plugins and File format support for more information.
Behavior and limitations
The plugin supports ImporterFeature::
Percent-encoded external file paths are not decoded before loading files. If you need to support those paths, you can intercept and decode them with a file callback.
The content of the global extensionsRequired
array is ignored. If a glTF file requires an unknown extension, the import will most likely succeed, but some things might be missing or not get imported correctly.
Import of morph data is not supported at the moment.
Scene import
- If no
"scene"
property is present and the file contains at least one scene, defaultScene() returns0
instead of-1
. According to the glTF 2.0 specification the importer is free to not render anything, but the suggested behavior would break even some official sample models. - Imported scenes always have SceneMappingType::
UnsignedInt and are always 3D. The objectCount() returns count of all nodes in the file, while SceneData:: mappingBound() returns an upper bound on node IDs contained in a particular scene. - Nodes that are not referenced by any scene are ignored.
- All objects contained in a scene have a SceneField::
Parent (of type SceneFieldType:: Int) and a SceneField:: ImporterState (of type SceneFieldType:: Pointer, see Access to internal importer state below). These two fields share the same object mapping, size of which gives count of nodes contained in the scene. The mapping is unordered and may be sparse if the file contains multiple scenes or nodes not referenced by any scene. - All nodes that contain transformation matrices or TRS components have a SceneField::
Transformation (of type SceneFieldType:: Matrix4x4). - If any node contains a translation, a SceneField::
Translation (of type SceneFieldType:: Vector3) is present; if any node contains a rotation, a SceneField:: Rotation (of type SceneFieldType:: Quaternion) is present; if any node contains a scaling, a SceneField:: Scaling (of type SceneFieldType:: Vector3) is present. However, if a node has both a transformation matrix and some TRS components, TinyGLTF parses only the matrix, ignoring the rest. - If the scene references meshes, a SceneField::
Mesh (of type SceneFieldType:: UnsignedInt) is present. If any of the referenced meshes have assigned materials, SceneField:: MeshMaterial (of type SceneFieldType:: Int) is present as well. While a single node can only reference a single mesh at most, in case it references a multi-primitive mesh, it's represented as several SceneField:: Mesh (and SceneField:: MeshMaterial) assignments. See Mesh import and Material import for further details. - If the scene references skins, a SceneField::
Skin (of type SceneFieldType:: UnsignedInt) is present. A single node can only reference one skin at most. See Animation and skin import for further details. - If the scene references cameras, a SceneField::
Camera (of type SceneFieldType:: UnsignedInt) is present. A single node can only reference one camera at most. See Camera import for further details. - If the scene references lights, a SceneField::
Light (of type SceneFieldType:: UnsignedInt) is present. A single node can only reference one light at most. See Light import for further details. - If node rotation quaternion is not normalized, the importer prints a warning and normalizes it. Can be disabled per-object with the
normalizeQuaternions
configuration option.
Animation and skin import
- Linear quaternion rotation tracks are postprocessed in order to make it possible to use the faster Math::
lerp() / Math:: slerp() functions instead of Math:: lerpShortestPath() / Math:: slerpShortestPath(). Can be disabled per-animation with the optimizeQuaternionShortestPath
configuration option. This doesn't affect spline-interpolated rotation tracks. - If linear quaternion rotation tracks are not normalized, the importer prints a warning and normalizes them. Can be disabled per-animation with the
normalizeQuaternions
option, see configuration option. This doesn't affect spline-interpolated rotation tracks. - Skin
skeleton
property is not imported, but you can retrieve it via SkinData::importerState() — see Access to internal importer state for more information - Morph targets are not supported
- Animation tracks are always imported with Animation::
Extrapolation:: Constant, because glTF doesn't support anything else - It's possible to request all animation clips to be merged into one using the
mergeAnimationClips
option in order to for example preserve cinematic animations when using the Blender glTF exporter (as it otherwise outputs a separate clip for each object). When this option is enabled, animationCount() always report either0
or1
and the merged animation has no name. With this option enabled, however, it can happen that multiple conflicting tracks affecting the same node are merged in the same clip, causing the animation to misbehave.
Camera import
- Cameras in glTF are specified with vertical FoV and vertical:horizontal aspect ratio, these values are recalculated for horizontal FoV and horizontal:vertical aspect ratio as is common in Magnum
Light import
- The importer supports the KHR_
lights_ punctual extension
Mesh import
- Indices are imported as either MeshIndexType::
UnsignedByte, MeshIndexType:: UnsignedShort or MeshIndexType:: UnsignedInt - Positions are imported as VertexFormat::
Vector3, VertexFormat:: Vector3ub, VertexFormat:: Vector3b, VertexFormat:: Vector3us, VertexFormat:: Vector3s, VertexFormat:: Vector3ubNormalized, VertexFormat:: Vector3bNormalized, VertexFormat:: Vector3usNormalized or VertexFormat:: Vector3sNormalized (which includes the additional types specified by KHR_ mesh_ quantization) - Normals are imported as VertexFormat::
Vector3, VertexFormat:: Vector3bNormalized or VertexFormat:: Vector3sNormalized - Tangents are imported as VertexFormat::
Vector4, VertexFormat:: Vector4bNormalized or VertexFormat:: Vector4sNormalized - Texture coordinates are imported as VertexFormat::
Vector2, VertexFormat:: Vector2ub, VertexFormat:: Vector2b, VertexFormat:: Vector2us, VertexFormat:: Vector2s, VertexFormat:: Vector2ubNormalized, VertexFormat:: Vector2bNormalized, VertexFormat:: Vector2usNormalized or VertexFormat:: Vector2sNormalized (which includes the additional types specified by KHR_ mesh_ quantization). The data are by default Y-flipped on import unless textureCoordinateYFlipInMaterial
is either explicitly enabled, or if the file contains non-normalized integer or normalized signed integer texture coordinates (which can't easily be flipped). In that case texture coordinate data are kept as-is and materials provide a texture transformation that does the Y-flip instead. - Colors are imported as VertexFormat::
Vector3, VertexFormat:: Vector4, VertexFormat:: Vector3ubNormalized, VertexFormat:: Vector4ubNormalized, VertexFormat:: Vector3usNormalized or VertexFormat:: Vector4usNormalized - Joint IDs and weights for skinning are imported as custom vertex attributes named "JOINTS_0", "JOINTS_1", etc. and "WEIGHTS_0", "WEIGHTS_1", etc. Their mapping to/from a string can be queried using meshAttributeName() and meshAttributeForName(). Joint IDs are imported as VertexFormat::
Vector4ub or VertexFormat:: Vector4us. Joint weights are imported as VertexFormat:: Vector4, VertexFormat:: Vector4ubNormalized or VertexFormat:: Vector4usNormalized. - Per-vertex object ID attribute is imported as either VertexFormat::
UnsignedInt, VertexFormat:: UnsignedShort or VertexFormat:: UnsignedByte. By default _OBJECT_ID
is the recognized name, use theobjectIdAttribute
configuration option to change the identifier that's being looked for. - Multi-primitive meshes are split into individual meshes, nodes that reference a multi-primitive mesh have multiple SceneField::
Mesh (and SceneField:: MeshMaterial) entries in the imported SceneData. - Attribute-less meshes either with or without an index buffer are supported, however since glTF has no way of specifying vertex count for those, returned Trade::
MeshData:: vertexCount() is set to 0
Custom and unrecognized vertex attributes of allowed types are present in the imported meshes as well. Their mapping to/from a string can be queried using meshAttributeName() and meshAttributeForName(). Attributes with unsupported types (such as non-normalized integer matrices) cause the import to fail.
Material import
- Builtin metallic/
roughness material is imported always, setting MaterialType:: PbrMetallicRoughness on the MaterialData. Unfortunately TinyGLTF doesn't provide a way to detect if metallic/roughness properties are actually present, so this type is set always. - If the KHR_
materials_ pbrSpecularGlossiness extension is present, its properties are imported with MaterialType:: PbrSpecularGlossiness present in material types. - Additional normal, occlusion and emissive maps are imported, together with related properties
- If the KHR_
materials_ unlit extension is present, MaterialType:: Flat is set in material types, replacing MaterialType:: PbrMetallicRoughness or MaterialType:: PbrSpecularGlossiness. - If the KHR_
materials_ clearcoat extension is present, MaterialType:: PbrClearCoat is set in material types, and a new layer with clearcoat properties is added - Custom texture coordinate sets as well as KHR_
texture_ transform properties are imported on all textures. - If the on-by-default
phongMaterialFallback
configuration option is enabled, the importer provides a Phong fallback for backwards compatibility:- MaterialType::
Phong is added to material types - Base color and base color texture along with custom texture coordinate set and transformation, if present, is exposed as a diffuse color and texture, unless already present together with specular color / texture from the specular/glossiness material
- All other PhongMaterialData values are is kept at their defaults
- MaterialType::
Texture and image import
- Texture type is always Trade::
TextureType:: Texture2D, as glTF doesn't support anything else - Z coordinate of Trade::
TextureData:: wrapping() is always SamplerWrapping:: Repeat, as glTF doesn't support 3D textures glTF leaves the defaults of sampler properties to the application, the following defaults have been chosen for this importer:
- Minification/magnification/mipmap filter: SamplerFilter::
Linear, SamplerMipmap:: Linear - Wrapping (all axes): SamplerWrapping::
Repeat
- Minification/magnification/mipmap filter: SamplerFilter::
The importer supports the following extensions for image types not defined in the core glTF 2.0 specification: KHR_
texture_ basisu for Khronos Texture 2.0 images ( *.ktx2
) with Basis Universal supercompression and the original provisionalGOOGLE_texture_basis
extension for referencing plain Basis Universal files (*.basis
). There was no formal specification of the extension but the use is like below, equivalently to Basis own glTF example:{ ... "textures": [ { "extensions": { "GOOGLE_texture_basis": { "source": 0 } } } ], "images": [ { "mimeType": "image/x-basis", "uri": "texture.basis" } ], "extensionsUsed": [ "GOOGLE_texture_basis" ], "extensionsRequired": [ "GOOGLE_texture_basis" ] }
While the
mimeType
field isn't checked by the importer, embedded data URIs for both extensions need to have their prefix set todata:application/octet-stream
. TinyGLTF has a whitelist for data URI detection that doesn't knowimage/ktx2
orimage/x-basis
and would treat the URI as a filename otherwise:{ ... "images": [ { "mimeType": "image/ktx2", "uri": "data:application/octet-stream;base64,..." } ] }
Plugin-specific configuration
It's possible to tune various output options through configuration(). See below for all options and their default values.
[configuration] # Optimize imported linearly-interpolated quaternion animation tracks to # ensure shortest path is always chosen. This can be controlled separately # for each animation import. optimizeQuaternionShortestPath=true # Normalize transformation quaternions and linearly-interpolated quaternion # animation tracks, if they are not already. Note that spline-interpolated # quaternion animation tracks are not patched. This can be controlled # separately for each object/animation import. normalizeQuaternions=true # Merge all animations into a single clip. Useful for preserving cinematic # animations when using the Blender glTF exporter, as it exports animation of # every object as a separate clip. For more information see # https://blender.stackexchange.com/q/5689 and # https://github.com/KhronosGroup/glTF-Blender-Exporter/pull/166. mergeAnimationClips=false # Perform Y-flip for texture coordinates in a material texture transform. By # default texture coordinates are Y-flipped directly in the mesh data to # avoid the need to supply texture transformation matrix to a shader, # enabling this will cause all texture coordinate data to be unchanged and # instead all materials will have a Y-flipping texture transformation # present. Note that this flag has to be enabled before opening a file, # changing it during import will have undefined behavior. textureCoordinateYFlipInMaterial=false # The non-standard MeshAttribute::ObjectId is by default recognized under # this name. Change if your file uses a different identifier. objectIdAttribute=_OBJECT_ID # Provide basic Phong material attributes even for PBR materials in order to # be compatible with PhongMaterialData workflows from version 2020.06 and # before. This option will eventually become disabled by default. phongMaterialFallback=true
See Editing plugin-specific configuration for more information and an example showing how to edit the configuration values.
Access to internal importer state
Access to the underlying TinyGLTF structures it is provided through importer-specific data accessors:
- Calling importerState() returns a pointer to the
tinygltf::Model
structure. If you use this class statically, you get the concrete type instead of aconst void*
pointer as returned by AbstractImporter::importerState(). - Importer state on data class instances returned from this importer return pointers to matching TinyGLTF structures:
- AnimationData::
importerState() returns tinygltf::Animation
, ornullptr
if themergeAnimationClips
option is enabled - MaterialData::
importerState() returns tinygltf::Material
- CameraData::
importerState() returns tinygltf::Camera
- ImageData::
importerState() returns tinygltf::Image
- LightData::
importerState() returns tinygltf::Light
- MeshData::
importerState() returns tinygltf::Mesh
- SceneData::
importerState() returns tinygltf::Scene
and all objects have a SceneField::ImporterState with their own tinygltf::Node
- SkinData::
importerState() returns tinygltf::Skin
- TextureData::
importerState() returns tinygltf::Texture
- AnimationData::
The TinyGLTF header is installed alsongside the plugin and is accessible like this:
#include <MagnumExternal/TinyGLTF/tiny_gltf.h>
Base classes
- class AbstractImporter
- Base for importer plugins.
Constructors, destructors, conversion operators
- TinyGltfImporter() explicit
- Default constructor.
-
TinyGltfImporter(PluginManager::
Manager<AbstractImporter>& manager) explicit - Constructor.
-
TinyGltfImporter(PluginManager::
AbstractManager& manager, const Containers:: StringView& plugin) explicit - Plugin manager constructor.
Public functions
- auto importerState() const -> const tinygltf::Model*
- Importer state.
Function documentation
Magnum:: Trade:: TinyGltfImporter:: TinyGltfImporter() explicit
Default constructor.
In case you want to open images, use TinyGltfImporter(PluginManager::
Magnum:: Trade:: TinyGltfImporter:: TinyGltfImporter(PluginManager:: Manager<AbstractImporter>& manager) explicit
Constructor.
The plugin needs access to plugin manager for importing images.
const tinygltf::Model* Magnum:: Trade:: TinyGltfImporter:: importerState() const
Importer state.
See class documentation for more information.