// Copyright 2018 The Draco Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #ifndef DRACO_IO_GLTF_DECODER_H_ #define DRACO_IO_GLTF_DECODER_H_ #include "draco/draco_features.h" #ifdef DRACO_TRANSCODER_SUPPORTED #include #include #include #include #include #include "draco/core/decoder_buffer.h" #include "draco/core/status.h" #include "draco/core/status_or.h" #include "draco/io/file_utils.h" #include "draco/io/texture_io.h" #include "draco/mesh/mesh.h" #include "draco/mesh/triangle_soup_mesh_builder.h" #include "draco/point_cloud/point_cloud_builder.h" #include "draco/scene/scene.h" #include "tiny_gltf.h" namespace draco { // Decodes a glTF file and returns a draco::Mesh. All of the |mesh|'s attributes // will be merged into one draco::Mesh class GltfDecoder { public: GltfDecoder(); // Decodes a glTF file stored in the input |file_name| or |buffer| to a Mesh. // The second form returns a vector of files used as input to the mesh during // the decoding process. Returns nullptr when decode fails. StatusOr> DecodeFromFile(const std::string &file_name); StatusOr> DecodeFromFile( const std::string &file_name, std::vector *mesh_files); StatusOr> DecodeFromBuffer(DecoderBuffer *buffer); // Decodes a glTF file stored in the input |file_name| or |buffer| to a Scene. // The second form returns a vector of files used as input to the scene during // the decoding process. Returns nullptr if the decode fails. StatusOr> DecodeFromFileToScene( const std::string &file_name); StatusOr> DecodeFromFileToScene( const std::string &file_name, std::vector *scene_files); StatusOr> DecodeFromBufferToScene( DecoderBuffer *buffer); // Scene graph can be loaded either as a tree or a general directed acyclic // graph (DAG) that allows multiple parent nodes. By default. we decode the // scene graph as a tree. If the tree mode is selected and the input contains // nodes with multiple parents, these nodes are duplicated to form a tree. // TODO(ostava): Add support for DAG mode to other parts of the Draco // library. enum class GltfSceneGraphMode { TREE, DAG }; void SetSceneGraphMode(GltfSceneGraphMode mode) { gltf_scene_graph_mode_ = mode; } private: // Loads |file_name| into |gltf_model_|. Fills |input_files| with paths to all // input files when non-null. Status LoadFile(const std::string &file_name, std::vector *input_files); // Loads |gltf_model_| from |buffer| in GLB format. Status LoadBuffer(const DecoderBuffer &buffer); // Builds mesh from |gltf_model_|. StatusOr> BuildMesh(); // Checks |gltf_model_| for unsupported features. If |gltf_model_| contains // unsupported features then the function will return with a status code of // UNSUPPORTED_FEATURE. Status CheckUnsupportedFeatures(); // Decodes a glTF Node as well as any child Nodes. If |node| contains a mesh // it will process all of the mesh's primitives. Status DecodeNode(int node_index, const Eigen::Matrix4d &parent_matrix); // Decodes the number of entries in the first attribute of a given glTF // |primitive|. Note that all attributes have the same entry count according // to glTF 2.0 spec. StatusOr DecodePrimitiveAttributeCount( const tinygltf::Primitive &primitive) const; // Decodes the number of indices in a given glTF |primitive|. If primitive's // indices property is not defined, the index count is implied from the entry // count of a primitive attribute. StatusOr DecodePrimitiveIndicesCount( const tinygltf::Primitive &primitive) const; // Decodes indices property of a given glTF |primitive|. If primitive's // indices property is not defined, the indices are generated based on entry // count of a primitive attribute. StatusOr> DecodePrimitiveIndices( const tinygltf::Primitive &primitive) const; // Decodes a glTF Primitive. All of the |primitive|'s attributes will be // merged into the draco::Mesh output if they are of the same type that // already has been decoded. Status DecodePrimitive(const tinygltf::Primitive &primitive, const Eigen::Matrix4d &transform_matrix); // Sums the number of elements per attribute for |node|'s mesh and any of // |node|'s children. Fills out the material index map. Status NodeGatherAttributeAndMaterialStats(const tinygltf::Node &node); // Sums the number of elements per attribute for all of the meshes and // primitives. Status GatherAttributeAndMaterialStats(); // Sums the attribute counts into total_attribute_counts_. void SumAttributeStats(const std::string &attribute_name, int count); // Checks that all the same glTF attribute types in different meshes and // primitives contain the same characteristics. Status CheckTypes(const std::string &attribute_name, int component_type, int type, bool normalized); // Accumulates the number of elements per attribute for |primitive|. Status AccumulatePrimitiveStats(const tinygltf::Primitive &primitive); // Adds all of the attributes from the glTF file to a Draco mesh. // GatherAttributeAndMaterialStats() must be called before this function. The // GeometryAttribute::MATERIAL attribute will be created only if the glTF file // contains more than one material. template Status AddAttributesToDracoMesh(BuilderT *builder); // Copies attribute data from |accessor| and adds it to a Draco mesh using the // geometry builder |builder|. template Status AddAttributeValuesToBuilder(const std::string &attribute_name, const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, const Eigen::Matrix4d &transform_matrix, BuilderT *builder); // Copies the tangent attribute data from |accessor| and adds it to a Draco // mesh. This function will transform all of the data by |transform_matrix| // and then normalize before adding the data to the Draco mesh. // |indices_data| is the indices data from the glTF file. |att_id| is the // attribute id of the tangent attribute in the Draco mesh. // |number_of_elements| is the number of faces or points this function will // process. |reverse_winding| if set will change the orientation of the data. template Status AddTangentToBuilder(const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, const Eigen::Matrix4d &transform_matrix, bool reverse_winding, BuilderT *builder); // Copies the texture coordinate attribute data from |accessor| and adds it to // a Draco mesh. This function will flip the data on the horizontal axis as // Draco meshes store the texture coordinates differently than glTF. // |indices_data| is the indices data from the glTF file. |att_id| is the // attribute id of the texture coordinate attribute in the Draco mesh. // |number_of_elements| is the number of faces or points this function will // process. |reverse_winding| if set will change the orientation of the data. template Status AddTexCoordToBuilder(const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, bool reverse_winding, BuilderT *builder); // Copies the mesh feature ID attribute data from |accessor| and adds it to a // Draco mesh. |indices_data| is the indices data from the glTF file. |att_id| // is the attribute ID of the mesh feature ID attribute in the Draco mesh. // |number_of_elements| is the number of faces or points this function will // process. |reverse_winding| if set will change the orientation of the data. template Status AddFeatureIdToBuilder(const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, bool reverse_winding, const std::string &attribute_name, BuilderT *builder); // Copies the attribute data from |accessor| and adds it to a Draco mesh. // This function will transform all of the data by |transform_matrix| before // adding the data to the Draco mesh. |indices_data| is the indices data // from the glTF file. |att_id| is the attribute id of the attribute in the // Draco mesh. |number_of_elements| is the number of faces or points this // function will process. |normalize| if set will normalize all of the vector // data after transformation. |reverse_winding| if set will change the // orientation of the data. template Status AddTransformedDataToBuilder(const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, const Eigen::Matrix4d &transform_matrix, bool normalize, bool reverse_winding, BuilderT *builder); // Sets values in |data| into the builder |builder| for |att_id|. template void SetValuesForBuilder(const std::vector &indices_data, int att_id, int number_of_elements, const std::vector &data, bool reverse_winding, TriangleSoupMeshBuilder *builder); template void SetValuesForBuilder(const std::vector &indices_data, int att_id, int number_of_elements, const std::vector &data, bool reverse_winding, PointCloudBuilder *builder); // Sets values in |data| into the mesh builder |mb| for |att_id|. // |reverse_winding| if set will change the orientation of the data. template void SetValuesPerFace(const std::vector &indices_data, int att_id, int number_of_faces, const std::vector &data, bool reverse_winding, TriangleSoupMeshBuilder *mb); // Returns an address pointing to the content stored in |data|. This is used // when passing values to mesh / point cloud builder when the input type can // be either a VectorD or an arithmetic type. template const void *GetDataContentAddress(const T &data) const; // Adds the attribute data in |accessor| to |mb| for unique attribute // |att_id|. |indices_data| is the mesh's indices data. |reverse_winding| if // set will change the orientation of the data. template Status AddAttributeDataByTypes(const tinygltf::Accessor &accessor, const std::vector &indices_data, int att_id, int number_of_elements, bool reverse_winding, BuilderT *builder); // Adds the textures to |owner|. template Status CopyTextures(T *owner); // Sets extra attribute properties on a constructed draco mesh. void SetAttributePropertiesOnDracoMesh(Mesh *mesh); // Adds the materials to |mesh|. Status AddMaterialsToDracoMesh(Mesh *mesh); // Adds the material data for the GeometryAttribute::MATERIAL attribute to the // Draco mesh. template Status AddMaterialDataToBuilder(int material_value, int number_of_elements, BuilderT *builder); template Status AddMaterialDataToBuilderInternal(T material_value, int number_of_faces, TriangleSoupMeshBuilder *builder); template Status AddMaterialDataToBuilderInternal(T material_value, int number_of_points, PointCloudBuilder *builder); // Checks if the glTF file contains a texture. If there is a texture, this // function will read the texture data and add it to the Draco |material|. If // there is no texture, this function will return OkStatus(). |texture_info| // is the data structure containing information about the texture in the glTF // file. |type| is the type of texture defined by Draco. This is not the same // as the texture coordinate attribute id. Status CheckAndAddTextureToDracoMaterial( int texture_index, int tex_coord_attribute_index, const tinygltf::ExtensionMap &tex_info_ext, Material *material, TextureMap::Type type); // Decode glTF file to scene. Status DecodeGltfToScene(); // Decode glTF lights into a scene. Status AddLightsToScene(); // Decodes glTF materials variants names into a scene. Status AddMaterialsVariantsNamesToScene(); // Decode glTF animations into a scene. All of the glTF nodes must be decoded // to the scene before this function is called. Status AddAnimationsToScene(); // Decode glTF node into a Draco scene. |parent_index| is the index of the // parent node. If |node| is a root node set |parent_index| to // |kInvalidSceneNodeIndex|. All glTF lights must be decoded to the scene // before this function is called. Status DecodeNodeForScene(int node_index, SceneNodeIndex parent_index); // Decode glTF primitive into a Draco scene. Status DecodePrimitiveForScene(const tinygltf::Primitive &primitive, MeshGroup *mesh_group); // Decodes glTF materials variants from |extension| and adds it into materials // variants |mappings|. Before calling this function, all materials variants // names must be decoded by calling AddMaterialsVariantsNamesToScene(). Status DecodeMaterialsVariantsMappings( const tinygltf::Value::Object &extension, std::vector *mappings); // Decodes glTF mesh feature ID sets from all glTF primitives and adds them to // |mesh|. Status AddMeshFeaturesToDracoMesh(Mesh *mesh); // Decodes glTF mesh feature ID sets from glTF primitive in glTF node at // |node_index| and adds them to |mesh|. Status AddMeshFeaturesToDracoMesh(int node_index, Mesh *mesh); // Decodes glTF structural metadata from glTF model and adds it to |geometry|. template Status AddStructuralMetadataToGeometry(GeometryT *geometry); // Decodes glTF mesh feature ID sets from |primitive| and adds them to |mesh|. Status DecodeMeshFeatures(const tinygltf::Primitive &primitive, TextureLibrary *texture_library, Mesh *mesh); // Decodes glTF mesh feature ID sets from |extension| and adds them to the // |mesh_features| vector. Status DecodeMeshFeatures( const tinygltf::Value::Object &extension, TextureLibrary *texture_library, std::vector> *mesh_features); // Adds an attribute of type |attribute_name| to |builder|. Returns the // attribute id. template StatusOr AddAttribute(const std::string &attribute_name, int component_type, int type, BuilderT *builder); // Adds an attribute of |attribute_type| to |builder|. Returns the attribute // id. template StatusOr AddAttribute(GeometryAttribute::Type attribute_type, int component_type, int type, BuilderT *builder); // Returns true if the KHR_texture_transform extension is set in |extension|. // If the KHR_texture_transform extension is set then the values are returned // in |transform|. StatusOr CheckKhrTextureTransform( const tinygltf::ExtensionMap &extension, TextureTransform *transform); // Adds glTF material |input_material_index| to |output_material|. Status AddGltfMaterial(int input_material_index, Material *output_material); // Adds unlit property from glTF |input_material| to |output_material|. void DecodeMaterialUnlitExtension(const tinygltf::Material &input_material, Material *output_material); // Adds sheen properties from glTF |input_material| to |output_material|. Status DecodeMaterialSheenExtension(const tinygltf::Material &input_material, Material *output_material); // Adds transmission from glTF |input_material| to |output_material|. Status DecodeMaterialTransmissionExtension( const tinygltf::Material &input_material, Material *output_material); // Adds clearcoat properties from glTF |input_material| to |output_material|. Status DecodeMaterialClearcoatExtension( const tinygltf::Material &input_material, Material *output_material); // Adds volume properties from glTF |input_material| to |output_material|. Status DecodeMaterialVolumeExtension(const tinygltf::Material &input_material, int input_material_index, Material *output_material); // Adds ior properties from glTF |input_material| to |output_material|. Status DecodeMaterialIorExtension(const tinygltf::Material &input_material, Material *output_material); // Adds specular properties from glTF |input_material| to |output_material|. Status DecodeMaterialSpecularExtension( const tinygltf::Material &input_material, Material *output_material); // Decodes a float value with |name| from |object| to |value| and returns true // if a well-formed value with such |name| is present. static StatusOr DecodeFloat(const std::string &name, const tinygltf::Value::Object &object, float *value); // Decodes an integer value with |name| from |object| to |value| and returns // true if a well-formed value with such |name| is present. static StatusOr DecodeInt(const std::string &name, const tinygltf::Value::Object &object, int *value); // Decodes a string value with |name| from |object| to |value| and returns // true if a well-formed value with such |name| is present. static StatusOr DecodeString(const std::string &name, const tinygltf::Value::Object &object, std::string *value); // Decodes data and data target from buffer view index with |name| in |object| // to |data| and returns true if a well-formed data is present. StatusOr DecodePropertyTableData(const std::string &name, const tinygltf::Value::Object &object, PropertyTable::Property::Data *data); // Decodes a 3D vector with |name| from |object| to |value| and returns true // if a well-formed vector with such |name| is present. static StatusOr DecodeVector3f(const std::string &name, const tinygltf::Value::Object &object, Vector3f *value); // Decodes a texture with |name| from |object| and adds it to |material| as a // texture map of |type|. Status DecodeTexture(const std::string &name, TextureMap::Type type, const tinygltf::Value::Object &object, Material *material); // Reads texture with |texture_name| from |container_object| into // |texture_info|. static Status ParseTextureInfo( const std::string &texture_name, const tinygltf::Value::Object &container_object, tinygltf::TextureInfo *texture_info); // Adds the materials to the scene. Status AddMaterialsToScene(); // Adds the skins to the scene. Status AddSkinsToScene(); // All material and non-material textures (e.g., from EXT_mesh_features) are // initially loaded into a texture library inside the the material library. // These methods move |non_material_textures| from material texture library // |material_tl| to non-material texture library |non_material_tl|. static void MoveNonMaterialTextures(Mesh *mesh); static void MoveNonMaterialTextures(Scene *scene); static void MoveNonMaterialTextures( const std::unordered_set &non_material_textures, TextureLibrary *material_tl, TextureLibrary *non_material_tl); // Builds and returns a mesh constructed from either mesh builder |mb| or // point cloud builder |pb|. Mesh builder is used if |use_mesh_builder| is set // to true. static StatusOr> BuildMeshFromBuilder( bool use_mesh_builder, TriangleSoupMeshBuilder *mb, PointCloudBuilder *pb); // Map of glTF Mesh to Draco scene mesh group. std::map gltf_mesh_to_scene_mesh_group_; // Data structure that stores the glTF data. tinygltf::Model gltf_model_; // Path to the glTF file. std::string input_file_name_; // Class used to build the Draco mesh. TriangleSoupMeshBuilder mb_; PointCloudBuilder pb_; // Next face index used when adding attribute data to the Draco mesh. int next_face_id_; // Next point index used when adding attribute data to the point cloud. int next_point_id_; // Total number of indices from all the meshes and primitives. int total_face_indices_count_; int total_point_indices_count_; // This is the id of the GeometryAttribute::MATERIAL attribute added to the // Draco mesh. int material_att_id_; // Data used when decoding the entire glTF asset into a single draco::Mesh. // The struct tracks the total number of elements across all matching // attributes and it ensures all matching attributes are compatible. struct MeshAttributeData { int component_type = 0; int attribute_type = 0; bool normalized = false; int total_attribute_counts = 0; }; // Map of glTF attribute name to attribute component type. std::map mesh_attribute_data_; // Map of glTF attribute name to Draco mesh attribute id. std::map attribute_name_to_draco_mesh_attribute_id_; // Map of glTF material to Draco material index. std::map gltf_primitive_material_to_draco_material_; // Map of glTF material index to transformation scales of primitives. std::map> gltf_primitive_material_to_scales_; // Map of glTF image to Draco textures. std::map gltf_image_to_draco_texture_; std::unique_ptr scene_; // Map of glTF Node to local store order. std::map gltf_node_to_scenenode_index_; // Selected mode of the decoded scene graph. GltfSceneGraphMode gltf_scene_graph_mode_ = GltfSceneGraphMode::TREE; // Functionality for deduping primitives on decode. struct PrimitiveSignature { const tinygltf::Primitive &primitive; explicit PrimitiveSignature(const tinygltf::Primitive &primitive) : primitive(primitive) {} bool operator==(const PrimitiveSignature &signature) const; struct Hash { size_t operator()(const PrimitiveSignature &signature) const; }; }; std::unordered_map gltf_primitive_to_draco_mesh_index_; }; } // namespace draco #endif // DRACO_TRANSCODER_SUPPORTED #endif // DRACO_IO_GLTF_DECODER_H_