/*========================================================================= Program: Visualization Toolkit Module: vtkGLTFDocumentLoader.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkGLTFDocumentLoader * @brief Deserialize a GLTF model file. * * * vtkGLTFDocument loader is an internal utility class which defines data structures and functions * with the purpose of deserializing a glTF model from a glTF file, loading its data from binary * buffers and creating vtk objects with the extracted geometry. * It contains an internal Model structure into which all loading is performed. * * The GL Transmission Format (glTF) is an API-neutral runtime asset delivery format. * A glTF asset is represented by: * - A JSON-formatted file (.gltf) containing a full scene description: node hierarchy, materials, * cameras, as well as descriptor information for meshes, animations, and other constructs * - Binary files (.bin) containing geometry and animation data, and other buffer-based data * - Image files (.jpg, .png) for textures * * For the full specification, see: * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 */ #ifndef vtkGLTFDocumentLoader_h #define vtkGLTFDocumentLoader_h #include "vtkIOGeometryModule.h" // For export macro #include "vtkObject.h" #include "vtkSmartPointer.h" // For SmartPointer #include // For std::map #include // For std::shared_ptr #include // For std::string #include // For std::vector class vtkCellArray; class vtkDataArray; class vtkFloatArray; class vtkImageData; class vtkMatrix4x4; class vtkPoints; class vtkPolyData; class vtkTransform; class vtkUnsignedShortArray; class VTKIOGEOMETRY_EXPORT vtkGLTFDocumentLoader : public vtkObject { public: static vtkGLTFDocumentLoader* New(); vtkTypeMacro(vtkGLTFDocumentLoader, vtkObject); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Define an openGL draw target. */ enum class Target : unsigned short { ARRAY_BUFFER = 34962, ELEMENT_ARRAY_BUFFER = 34963 }; /** * Defines an accessor's type. These are defined as strings in the glTF specification. * Each type implies a specific number of components. */ enum class AccessorType : unsigned char { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4, INVALID }; /** * Define a type for different data components. Values match with the corresponding GLenum, as * they are used in the glTF specification. */ enum class ComponentType : unsigned short { BYTE = 5120, UNSIGNED_BYTE = 5121, SHORT = 5122, UNSIGNED_SHORT = 5123, UNSIGNED_INT = 5125, FLOAT = 5126 }; /* The following structs help deserialize a glTF document, representing each object. As such, * their members mostly match with the specification. Default values and boundaries are set * according to the specification. * Most of these structs contain a name property, which is optional, and, while being loaded, is * not currently exploited by the loader. * They are mostly root-level properties, and once created, are stored into vectors in the Model * structure. */ /** * This struct describes a glTF bufferView object. * A bufferView represents a subset of a glTF binary buffer */ struct BufferView { int Buffer; int ByteOffset; int ByteLength; int ByteStride; int Target; std::string Name; }; /** * This struct describes an accessor glTF object. * An accessor defines a method for retrieving data as typed arrays from a bufferView. * They contain type information, as well as the location and size of of the data within the * bufferView. */ struct Accessor { /** * This struct describes an accessor.sparse glTF object. * This object describes the elements that deviate from their initialization value. */ struct Sparse { int Count; int IndicesBufferView; int IndicesByteOffset; ComponentType IndicesComponentType; int ValuesBufferView; int ValuesByteOffset; }; int BufferView; int ByteOffset; ComponentType ComponentTypeValue; bool Normalized; int Count; unsigned int NumberOfComponents; AccessorType Type; std::vector Max; std::vector Min; bool IsSparse; Sparse SparseObject; std::string Name; }; /** * This struct describes a glTF Morph Target object. * A Morph Target is a morphable Mesh where primitives' attributes are obtained by adding the * original attributes to a weighted sum of targets attributes. * Only three attributes (position, normals and tangents) are supported. */ struct MorphTarget { // accessor indices from the .gltf file, the map's keys correspond to attribute names std::map AttributeIndices; // attribute values std::map > AttributeValues; }; /** * This struct describes a glTF primitive object. * primitives specify vertex attributes, as well as connectivity information for a draw call. * A primitive also specifies a material and GPU primitive type (e.g: triangle set) * Data is first stored as integer indices, pointing to different accessors, then extracted into * vtk data structures and finally used to build a vtkPolyData object. */ struct Primitive { // accessor indices from the .glTF file, the map's keys correspond to attribute names std::map AttributeIndices; int IndicesId; vtkSmartPointer Indices; // attribute values from buffer data std::map > AttributeValues; vtkSmartPointer Geometry; std::vector Targets; int Material; int Mode; int CellSize; // 1, 2 or 3, depending on draw mode }; /** * This struct describes a glTF node object. * A node represents an object within a scene. * Nodes can contain transform properties (stored as vtkTransform objects) as well as indices to * children nodes, forming a hierarchy. No node may be a direct descendant of more than one node. */ struct Node { std::vector Children; int Camera; int Mesh; int Skin; vtkSmartPointer Transform; vtkSmartPointer GlobalTransform; bool TRSLoaded; vtkSmartPointer Matrix; std::vector InitialRotation; std::vector InitialTranslation; std::vector InitialScale; std::vector InitialWeights; std::vector Rotation; std::vector Translation; std::vector Scale; std::vector Weights; // Object-specific extension metadata struct Extensions { // KHR_lights_punctual extension struct KHRLightsPunctual { int Light = -1; }; Node::Extensions::KHRLightsPunctual KHRLightsPunctualMetaData; }; Node::Extensions ExtensionMetaData; std::string Name; void UpdateTransform(); }; /** * This struct describes a glTF mesh object. * A mesh contains an array of primitives. */ struct Mesh { std::vector Primitives; std::vector Weights; std::string Name; }; /** * This struct describes a glTF textureInfo object, mostly used in material descriptions * They contain two indexes, one to a texture object, and the second being used to construct a * string with the format TEXCOORD_, which references a key in mesh.primitives.attributes. */ struct TextureInfo { int Index = -1; int TexCoord; }; /** * This struct describes a glTF image object. * Images can be referenced either by URI or with a bufferView. mimeType is required in this case. */ struct Image { int BufferView; std::string MimeType; std::string Uri; vtkSmartPointer ImageData; std::string Name; }; /** * This struct describes a glTF material object. * glTF materials are defined using the metallic-roughness model. The values for most properties * can be defined using either factors or textures (via textureInfo). * Materials also define normal, occlusion and emissive maps. */ struct Material { enum class AlphaModeType : unsigned char { OPAQUE, MASK, BLEND }; struct PbrMetallicRoughness { TextureInfo BaseColorTexture; std::vector BaseColorFactor; TextureInfo MetallicRoughnessTexture; float MetallicFactor; float RoughnessFactor; }; PbrMetallicRoughness PbrMetallicRoughness; TextureInfo NormalTexture; double NormalTextureScale; TextureInfo OcclusionTexture; double OcclusionTextureStrength; TextureInfo EmissiveTexture; std::vector EmissiveFactor; AlphaModeType AlphaMode; double AlphaCutoff; bool DoubleSided; std::string Name; }; /** * This struct describes a glTF texture object. * A texture is defined two indexes, one to an image resource, and the second to a sampler index. */ struct Texture { int Sampler; int Source; std::string Name; }; /** * This struct describes a glTF sampler object. * Samplers specify filter and wrapping options corresponding to GL types. */ struct Sampler { enum FilterType : unsigned short { NEAREST = 9728, LINEAR = 9729, NEAREST_MIPMAP_NEAREST = 9984, LINEAR_MIPMAP_NEAREST = 9985, NEAREST_MIPMAP_LINEAR = 9986, LINEAR_MIPMAP_LINEAR = 9987 }; enum WrapType : unsigned short { CLAMP_TO_EDGE = 33071, MIRRORED_REPEAT = 33648, REPEAT = 10497 }; FilterType MagFilter; FilterType MinFilter; WrapType WrapS; WrapType WrapT; std::string Name; }; /** * This struct describes a glTF scene object. * A scene contains a set of indices of nodes to render. * Scene.Nodes can be empty, in which case nothing is required to be rendered */ struct Scene { std::vector Nodes; std::string Name; }; /** * This struct describes a glTF asset. * It is meant to mimic a .glTF file, containing all its root-level properties, stored as arrays * when relevant. */ struct Skin { std::vector > InverseBindMatrices; std::vector Joints; int InverseBindMatricesAccessorId; int Skeleton; std::string Name; }; /** * This struct describes a glTF animation object. * Animations contain multiple channel and sampler objects. * Channels define the target node and value to be animated. * Samplers define keyframes and how to interpolate in between them. */ struct Animation { struct Sampler { enum class InterpolationMode : unsigned char { LINEAR, STEP, CUBICSPLINE }; InterpolationMode Interpolation; unsigned int Input; unsigned int Output; int NumberOfComponents; vtkSmartPointer InputData; vtkSmartPointer OutputData; /** * Get the interpolated animation output at time t */ void GetInterpolatedData(float t, size_t numberOfComponents, std::vector* output, bool forceStep = false, bool isRotation = false) const; }; struct Channel { enum class PathType : unsigned char { ROTATION, TRANSLATION, SCALE, WEIGHTS }; int Sampler; int TargetNode; PathType TargetPath; }; float Duration; // In seconds std::vector Channels; std::vector Samplers; std::string Name; }; /** * This struct describes a glTF camera object. * glTF can define both perpective or orthographic cameras. * Some of the struct's members will be unused depending on the camera type. */ struct Camera { // common properties double Znear; double Zfar; bool IsPerspective; // if not, camera mode is orthographic // perspective double Xmag; double Ymag; // orthographic double Yfov; double AspectRatio; std::string Name; }; /** * This struct contains extension metadata. * This is for extension properties in the root-level 'extensions' object. * Object-specific extension metadata is added directly to the extended object (see Node for an * example) */ struct Extensions { // KHR_lights_punctual extension struct KHRLightsPunctual { struct Light { enum class LightType : unsigned char { DIRECTIONAL, POINT, SPOT }; LightType Type; std::vector Color; double Intensity; double Range; // Type-specific parameters double SpotInnerConeAngle; double SpotOuterConeAngle; std::string Name; }; std::vector Lights; }; KHRLightsPunctual KHRLightsPunctualMetaData; }; /** * This struct contains all data from a gltf asset */ struct Model { std::vector Accessors; std::vector Animations; std::vector > Buffers; std::vector BufferViews; std::vector Cameras; std::vector Images; std::vector Materials; std::vector Meshes; std::vector Nodes; std::vector Samplers; std::vector Scenes; std::vector Skins; std::vector Textures; Extensions ExtensionMetaData; std::string BufferMetaData; int DefaultScene; std::string FileName; }; /** * Apply the specified animation, at the specified time, to the internal Model. Changes node * transforms and morphing weights. */ bool ApplyAnimation(float t, int animationId, bool forceStep = false); /** * Restore the transforms that were modified by an animation to their initial state */ void ResetAnimation(int animationId); /** * Load the binary part of a binary glTF (.glb) file. Returns false if no valid binary part was * found. */ bool LoadFileBuffer(const std::string& fileName, std::vector& glbBuffer); /** * Reset internal Model struct, and serialize glTF metadata (all json information) into it. * To load buffers, use LoadModelData */ bool LoadModelMetaDataFromFile(std::string FileName); /** * Load buffer data into the internal Model. */ bool LoadModelData(const std::vector& glbBuffer); /** * Converts the internal Model's loaded data into more convenient vtk objects. */ bool BuildModelVTKGeometry(); /** * Get the internal Model. */ std::shared_ptr GetInternalModel(); /** * Returns the number of components for a given accessor type. */ static unsigned int GetNumberOfComponentsForType(vtkGLTFDocumentLoader::AccessorType type); /** * Get the list of extensions that are supported by this loader */ const std::vector& GetSupportedExtensions(); /** * Get the list of extensions that are used by the current model */ const std::vector& GetUsedExtensions(); protected: vtkGLTFDocumentLoader() = default; ~vtkGLTFDocumentLoader() override = default; private: struct AccessorLoadingWorker; struct SparseAccessorLoadingWorker; template struct BufferDataExtractionWorker; vtkGLTFDocumentLoader(const vtkGLTFDocumentLoader&) = delete; void operator=(const vtkGLTFDocumentLoader&) = delete; /** * Load inverse bind matrices from buffers into the model's Skin structs. */ bool LoadSkinMatrixData(); /** * Uses the Primitive's attributeIndices member to extract all vertex attributes from accessors * into the Primitive's corresponding vtk arrays. */ bool ExtractPrimitiveAttributes(Primitive& primitive); /** * Uses all the primitive's different accessor indices to extract the corresponding data from * binary buffers. These arrays are then stored in the primitive's different vtk arrays. * Extracts connectivity information then calls ExtractPrimitiveAttributes for the vertex * attributes */ bool ExtractPrimitiveAccessorData(Primitive& primitive); /** * Creates and populates the Primitive's geometry vtkPolyData member with all the vertex attribute * and connectivity information the Primitive contains. */ bool BuildPolyDataFromPrimitive(Primitive& primitive); /** * Load keyframes from buffers. */ bool LoadAnimationData(); /** * Load Model's Images into vtkImageData objects, from filesystem and bufferView when specified. */ bool LoadImageData(); /** * Concatenate the current node's local transform to its parent's global transform, storing * the resulting transform in the node's globalTransform field. Then does the same for the current * node's children. * Recursive. */ void BuildGlobalTransforms(unsigned int nodeIndex, vtkSmartPointer parentTransform); std::shared_ptr InternalModel; static const std::vector SupportedExtensions; std::vector UsedExtensions; }; #endif