Merge pull request #1423 from Matter-and-Form/feature/gltf2
glTF 2 Importer + glTF 2 Spec Conformitypull/1431/head
commit
d139b4d180
|
@ -52,7 +52,8 @@ __Importers__:
|
|||
- DXF
|
||||
- ENFF
|
||||
- FBX
|
||||
- GLB/GLTF
|
||||
- glTF 1.0 + GLB
|
||||
- glTF 2.0
|
||||
- HMB
|
||||
- IFC-STEP
|
||||
- IRR / IRRMESH
|
||||
|
@ -106,8 +107,8 @@ __Exporters__:
|
|||
- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
|
||||
- ASSBIN
|
||||
- STEP
|
||||
- glTF (partial)
|
||||
- glTF2.0
|
||||
- glTF 1.0 (partial)
|
||||
- glTF 2.0 (partial)
|
||||
|
||||
### Building ###
|
||||
Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
|
||||
|
|
|
@ -666,6 +666,8 @@ ADD_ASSIMP_IMPORTER( GLTF
|
|||
glTF2Asset.inl
|
||||
glTF2AssetWriter.h
|
||||
glTF2AssetWriter.inl
|
||||
glTF2Importer.cpp
|
||||
glTF2Importer.h
|
||||
glTF2Exporter.h
|
||||
glTF2Exporter.cpp
|
||||
)
|
||||
|
|
|
@ -119,7 +119,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
|
|||
* might be NULL and it's our duty to return true here.
|
||||
*/
|
||||
if (!pIOHandler)return true;
|
||||
const char* tokens[] = {"collada"};
|
||||
const char* tokens[] = {"<collada"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -182,6 +182,7 @@ corresponding preprocessor flag to selectively disable formats.
|
|||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
# include "glTFImporter.h"
|
||||
# include "glTF2Importer.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
||||
# include "C4DImporter.h"
|
||||
|
@ -336,6 +337,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
|||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER )
|
||||
out.push_back( new glTFImporter() );
|
||||
out.push_back( new glTF2Importer() );
|
||||
#endif
|
||||
#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER )
|
||||
out.push_back( new C4DImporter() );
|
||||
|
|
|
@ -94,7 +94,7 @@ bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool
|
|||
{
|
||||
if (!pIOHandler)return true;
|
||||
const char* tokens[] = {"off"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -43,8 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* Declares a glTF class to handle gltf/glb files
|
||||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_binary_glTF: full
|
||||
* KHR_materials_common: full
|
||||
* KHR_materials_pbrSpecularGlossiness full
|
||||
*/
|
||||
#ifndef GLTF2ASSET_H_INC
|
||||
#define GLTF2ASSET_H_INC
|
||||
|
@ -130,15 +129,12 @@ namespace glTF2
|
|||
|
||||
struct BufferView; // here due to cross-reference
|
||||
struct Texture;
|
||||
struct Light;
|
||||
struct Skin;
|
||||
|
||||
|
||||
// Vec/matrix types, as raw float arrays
|
||||
typedef float (vec3)[3];
|
||||
typedef float (vec4)[4];
|
||||
typedef float (mat4)[16];
|
||||
|
||||
typedef float (mat4)[16];
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
@ -166,23 +162,36 @@ namespace glTF2
|
|||
|
||||
|
||||
//! Magic number for GLB files
|
||||
#define AI_GLB_MAGIC_NUMBER "glTF"
|
||||
#define AI_GLB_MAGIC_NUMBER "glTF"
|
||||
|
||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0
|
||||
#define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0
|
||||
#define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR "$clr.diffuse", 0, 1
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR "$clr.specular", 0, 1
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE aiTextureType_DIFFUSE, 1
|
||||
#define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE aiTextureType_UNKNOWN, 1
|
||||
|
||||
#define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord"
|
||||
#define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname"
|
||||
#define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid"
|
||||
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag"
|
||||
#define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin"
|
||||
|
||||
#define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N
|
||||
#define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N
|
||||
#define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N
|
||||
#define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N
|
||||
#define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N
|
||||
|
||||
#ifdef ASSIMP_API
|
||||
#include "./../include/assimp/Compiler/pushpack1.h"
|
||||
#endif
|
||||
|
||||
//! For the KHR_binary_glTF extension (binary .glb file)
|
||||
//! 20-byte header (+ the JSON + a "body" data section)
|
||||
struct GLB_Header
|
||||
{
|
||||
uint8_t magic[4]; //!< Magic number: "glTF"
|
||||
uint32_t version; //!< Version number
|
||||
uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes
|
||||
uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
|
||||
uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
|
||||
} PACK_STRUCT;
|
||||
|
||||
#ifdef ASSIMP_API
|
||||
#include "./../include/assimp/Compiler/poppack1.h"
|
||||
#endif
|
||||
|
@ -232,7 +241,7 @@ namespace glTF2
|
|||
case ComponentType_UNSIGNED_BYTE:
|
||||
return 1;
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Unsupported Component Type "+t);
|
||||
throw DeadlyImportError("GLTF: Unsupported Component Type " + std::to_string(t));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,15 +253,17 @@ namespace glTF2
|
|||
};
|
||||
|
||||
//! Values for the Sampler::magFilter field
|
||||
enum SamplerMagFilter
|
||||
enum class SamplerMagFilter: unsigned int
|
||||
{
|
||||
UNSET = 0,
|
||||
SamplerMagFilter_Nearest = 9728,
|
||||
SamplerMagFilter_Linear = 9729
|
||||
};
|
||||
|
||||
//! Values for the Sampler::minFilter field
|
||||
enum SamplerMinFilter
|
||||
enum class SamplerMinFilter: unsigned int
|
||||
{
|
||||
UNSET = 0,
|
||||
SamplerMinFilter_Nearest = 9728,
|
||||
SamplerMinFilter_Linear = 9729,
|
||||
SamplerMinFilter_Nearest_Mipmap_Nearest = 9984,
|
||||
|
@ -262,11 +273,12 @@ namespace glTF2
|
|||
};
|
||||
|
||||
//! Values for the Sampler::wrapS and Sampler::wrapT field
|
||||
enum SamplerWrap
|
||||
enum class SamplerWrap: unsigned int
|
||||
{
|
||||
SamplerWrap_Clamp_To_Edge = 33071,
|
||||
SamplerWrap_Mirrored_Repeat = 33648,
|
||||
SamplerWrap_Repeat = 10497
|
||||
UNSET = 0,
|
||||
Clamp_To_Edge = 33071,
|
||||
Mirrored_Repeat = 33648,
|
||||
Repeat = 10497
|
||||
};
|
||||
|
||||
//! Values for the Texture::format and Texture::internalFormat fields
|
||||
|
@ -382,6 +394,7 @@ namespace glTF2
|
|||
struct Object
|
||||
{
|
||||
int index; //!< The index of this object within its property container
|
||||
int oIndex; //!< The original index of this object defined in the JSON
|
||||
std::string id; //!< The globally unique ID used to reference this object
|
||||
std::string name; //!< The user-defined name of this object
|
||||
|
||||
|
@ -629,7 +642,7 @@ namespace glTF2
|
|||
float zfar; //! The floating-point distance to the far clipping plane. (required)
|
||||
float znear; //! The floating-point distance to the near clipping plane. (required)
|
||||
} ortographic;
|
||||
};
|
||||
} cameraProperties;
|
||||
|
||||
Camera() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
|
@ -668,43 +681,68 @@ namespace glTF2
|
|||
inline uint8_t* StealData();
|
||||
|
||||
inline void SetData(uint8_t* data, size_t length, Asset& r);
|
||||
};
|
||||
};
|
||||
|
||||
//! Holds a material property that can be a texture or a color
|
||||
struct TexProperty
|
||||
const vec4 defaultBaseColor = {1, 1, 1, 1};
|
||||
const vec3 defaultEmissiveFactor = {0, 0, 0};
|
||||
const vec4 defaultDiffuseFactor = {1, 1, 1, 1};
|
||||
const vec3 defaultSpecularFactor = {1, 1, 1};
|
||||
|
||||
struct TextureInfo
|
||||
{
|
||||
Ref<Texture> texture;
|
||||
vec4 color;
|
||||
unsigned int index;
|
||||
unsigned int texCoord = 0;
|
||||
};
|
||||
|
||||
struct NormalTextureInfo : TextureInfo
|
||||
{
|
||||
float scale = 1;
|
||||
};
|
||||
|
||||
struct OcclusionTextureInfo : TextureInfo
|
||||
{
|
||||
float strength = 1;
|
||||
};
|
||||
|
||||
struct PbrMetallicRoughness
|
||||
{
|
||||
vec4 baseColorFactor;
|
||||
TextureInfo baseColorTexture;
|
||||
TextureInfo metallicRoughnessTexture;
|
||||
float metallicFactor;
|
||||
float roughnessFactor;
|
||||
};
|
||||
|
||||
struct PbrSpecularGlossiness
|
||||
{
|
||||
vec4 diffuseFactor;
|
||||
vec3 specularFactor;
|
||||
float glossinessFactor;
|
||||
TextureInfo diffuseTexture;
|
||||
TextureInfo specularGlossinessTexture;
|
||||
|
||||
PbrSpecularGlossiness() { SetDefaults(); }
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
//! The material appearance of a primitive.
|
||||
struct Material : public Object
|
||||
{
|
||||
//Ref<Sampler> source; //!< The ID of the technique.
|
||||
//std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values.
|
||||
|
||||
//! Techniques defined by KHR_materials_common
|
||||
enum Technique
|
||||
{
|
||||
Technique_undefined = 0,
|
||||
Technique_BLINN,
|
||||
Technique_PHONG,
|
||||
Technique_LAMBERT,
|
||||
Technique_CONSTANT
|
||||
};
|
||||
|
||||
TexProperty ambient;
|
||||
TexProperty diffuse;
|
||||
TexProperty specular;
|
||||
TexProperty emission;
|
||||
Ref<Texture> normal;
|
||||
//PBR metallic roughness properties
|
||||
PbrMetallicRoughness pbrMetallicRoughness;
|
||||
|
||||
//other basic material properties
|
||||
NormalTextureInfo normalTexture;
|
||||
OcclusionTextureInfo occlusionTexture;
|
||||
TextureInfo emissiveTexture;
|
||||
vec3 emissiveFactor;
|
||||
std::string alphaMode;
|
||||
float alphaCutoff;
|
||||
bool doubleSided;
|
||||
bool transparent;
|
||||
float transparency;
|
||||
float shininess;
|
||||
|
||||
Technique technique;
|
||||
//extension: KHR_materials_pbrSpecularGlossiness
|
||||
Nullable<PbrSpecularGlossiness> pbrSpecularGlossiness;
|
||||
|
||||
Material() { SetDefaults(); }
|
||||
void Read(Value& obj, Asset& r);
|
||||
|
@ -729,92 +767,21 @@ namespace glTF2
|
|||
Ref<Material> material;
|
||||
};
|
||||
|
||||
/// \struct SExtension
|
||||
/// Extension used for mesh.
|
||||
struct SExtension
|
||||
{
|
||||
/// \enum EType
|
||||
/// Type of extension.
|
||||
enum EType
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
Compression_Open3DGC,///< Compression of mesh data using Open3DGC algorithm.
|
||||
#endif
|
||||
|
||||
Unknown
|
||||
};
|
||||
|
||||
EType Type;///< Type of extension.
|
||||
|
||||
/// \fn SExtension
|
||||
/// Constructor.
|
||||
/// \param [in] pType - type of extension.
|
||||
SExtension(const EType pType)
|
||||
: Type(pType)
|
||||
{}
|
||||
|
||||
virtual ~SExtension() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
/// \struct SCompression_Open3DGC
|
||||
/// Compression of mesh data using Open3DGC algorithm.
|
||||
struct SCompression_Open3DGC : public SExtension
|
||||
{
|
||||
using SExtension::Type;
|
||||
|
||||
std::string Buffer;///< ID of "buffer" used for storing compressed data.
|
||||
size_t Offset;///< Offset in "bufferView" where compressed data are stored.
|
||||
size_t Count;///< Count of elements in compressed data. Is always equivalent to size in bytes: look comments for "Type" and "Component_Type".
|
||||
bool Binary;///< If true then "binary" mode is used for coding, if false - "ascii" mode.
|
||||
size_t IndicesCount;///< Count of indices in mesh.
|
||||
size_t VerticesCount;///< Count of vertices in mesh.
|
||||
// AttribType::Value Type;///< Is always "SCALAR".
|
||||
// ComponentType Component_Type;///< Is always "ComponentType_UNSIGNED_BYTE" (5121).
|
||||
|
||||
/// \fn SCompression_Open3DGC
|
||||
/// Constructor.
|
||||
SCompression_Open3DGC()
|
||||
: SExtension(Compression_Open3DGC) {
|
||||
// empty
|
||||
}
|
||||
|
||||
virtual ~SCompression_Open3DGC() {
|
||||
// empty
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
std::vector<Primitive> primitives;
|
||||
std::list<SExtension*> Extension;///< List of extensions used in mesh.
|
||||
|
||||
Mesh() {}
|
||||
|
||||
/// \fn ~Mesh()
|
||||
/// Destructor.
|
||||
~Mesh() { for(std::list<SExtension*>::iterator it = Extension.begin(), it_end = Extension.end(); it != it_end; it++) { delete *it; }; }
|
||||
|
||||
/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)
|
||||
/// Get mesh data from JSON-object and place them to root asset.
|
||||
/// \param [in] pJSON_Object - reference to pJSON-object from which data are read.
|
||||
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
|
||||
void Read(Value& pJSON_Object, Asset& pAsset_Root);
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
/// \fn void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
|
||||
/// Decode part of "buffer" which encoded with Open3DGC algorithm.
|
||||
/// \param [in] pCompression_Open3DGC - reference to structure which describe encoded region.
|
||||
/// \param [out] pAsset_Root - reference to root assed where data will be stored.
|
||||
void Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Node : public Object
|
||||
{
|
||||
std::vector< Ref<Node> > children;
|
||||
std::vector< Ref<Mesh> > meshes;
|
||||
Ref<Mesh> mesh;
|
||||
|
||||
Nullable<mat4> matrix;
|
||||
Nullable<vec3> translation;
|
||||
|
@ -822,10 +789,9 @@ namespace glTF2
|
|||
Nullable<vec3> scale;
|
||||
|
||||
Ref<Camera> camera;
|
||||
Ref<Light> light;
|
||||
|
||||
std::vector< Ref<Node> > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy.
|
||||
Ref<Skin> skin; //!< The ID of the skin referenced by this node.
|
||||
Ref<Skin> skin; //!< The ID of the skin referenced by this node.
|
||||
std::string jointName; //!< Name used when this node is a joint in a skin.
|
||||
|
||||
Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
|
||||
|
@ -843,12 +809,12 @@ namespace glTF2
|
|||
|
||||
struct Sampler : public Object
|
||||
{
|
||||
SamplerMagFilter magFilter; //!< The texture magnification filter. (required)
|
||||
SamplerMinFilter minFilter; //!< The texture minification filter. (required)
|
||||
SamplerWrap wrapS; //!< The texture wrapping in the S direction. (required)
|
||||
SamplerWrap wrapT; //!< The texture wrapping in the T direction. (required)
|
||||
SamplerMagFilter magFilter; //!< The texture magnification filter.
|
||||
SamplerMinFilter minFilter; //!< The texture minification filter.
|
||||
SamplerWrap wrapS; //!< The texture wrapping in the S direction.
|
||||
SamplerWrap wrapT; //!< The texture wrapping in the T direction.
|
||||
|
||||
Sampler() {}
|
||||
Sampler() { SetDefaults(); }
|
||||
void Read(Value& obj, Asset& r);
|
||||
void SetDefaults();
|
||||
};
|
||||
|
@ -878,27 +844,6 @@ namespace glTF2
|
|||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
||||
struct Technique : public Object
|
||||
{
|
||||
struct Parameters
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct States
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct Functions
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
Technique() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
||||
//! A texture and its sampler.
|
||||
struct Texture : public Object
|
||||
{
|
||||
|
@ -915,35 +860,6 @@ namespace glTF2
|
|||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
||||
|
||||
//! A light (from KHR_materials_common extension)
|
||||
struct Light : public Object
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
Type_undefined,
|
||||
Type_ambient,
|
||||
Type_directional,
|
||||
Type_point,
|
||||
Type_spot
|
||||
};
|
||||
|
||||
Type type;
|
||||
|
||||
vec4 color;
|
||||
float distance;
|
||||
float constantAttenuation;
|
||||
float linearAttenuation;
|
||||
float quadraticAttenuation;
|
||||
float falloffAngle;
|
||||
float falloffExponent;
|
||||
|
||||
Light() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
|
||||
void SetDefaults();
|
||||
};
|
||||
|
||||
struct Animation : public Object
|
||||
{
|
||||
struct AnimSampler {
|
||||
|
@ -1025,14 +941,16 @@ namespace glTF2
|
|||
friend class Asset;
|
||||
friend class AssetWriter;
|
||||
|
||||
typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict;
|
||||
typedef typename std::gltf_unordered_map< unsigned int, unsigned int > Dict;
|
||||
typedef typename std::gltf_unordered_map< std::string, unsigned int > IdDict;
|
||||
|
||||
std::vector<T*> mObjs; //! The read objects
|
||||
Dict mObjsById; //! The read objects accessible by id
|
||||
const char* mDictId; //! ID of the dictionary object
|
||||
const char* mExtId; //! ID of the extension defining the dictionary
|
||||
Value* mDict; //! JSON dictionary object
|
||||
Asset& mAsset; //! The asset instance
|
||||
std::vector<T*> mObjs; //! The read objects
|
||||
Dict mObjsByOIndex; //! The read objects accessible by original index
|
||||
IdDict mObjsById; //! The read objects accessible by id
|
||||
const char* mDictId; //! ID of the dictionary object
|
||||
const char* mExtId; //! ID of the extension defining the dictionary
|
||||
Value* mDict; //! JSON dictionary object
|
||||
Asset& mAsset; //! The asset instance
|
||||
|
||||
void AttachToDocument(Document& doc);
|
||||
void DetachFromDocument();
|
||||
|
@ -1046,9 +964,10 @@ namespace glTF2
|
|||
LazyDict(Asset& asset, const char* dictId, const char* extId = 0);
|
||||
~LazyDict();
|
||||
|
||||
Ref<T> Get(const char* id);
|
||||
Ref<T> Retrieve(unsigned int i);
|
||||
|
||||
Ref<T> Get(unsigned int i);
|
||||
Ref<T> Get(const std::string& pID) { return Get(pID.c_str()); }
|
||||
Ref<T> Get(const char* id);
|
||||
|
||||
Ref<T> Create(const char* id);
|
||||
Ref<T> Create(const std::string& id)
|
||||
|
@ -1067,22 +986,17 @@ namespace glTF2
|
|||
{
|
||||
std::string copyright; //!< A copyright message suitable for display to credit the content creator.
|
||||
std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
|
||||
bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false)
|
||||
|
||||
struct {
|
||||
std::string api; //!< Specifies the target rendering API (default: "WebGL")
|
||||
std::string version; //!< Specifies the target rendering API (default: "1.0.3")
|
||||
} profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
|
||||
|
||||
float version; //!< The glTF format version
|
||||
std::string version; //!< The glTF format version
|
||||
|
||||
void Read(Document& doc);
|
||||
|
||||
AssetMetadata()
|
||||
: premultipliedAlpha(false)
|
||||
, version(0)
|
||||
{
|
||||
}
|
||||
AssetMetadata() : version("") {}
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -1123,8 +1037,7 @@ namespace glTF2
|
|||
//! Keeps info about the enabled extensions
|
||||
struct Extensions
|
||||
{
|
||||
bool KHR_binary_glTF;
|
||||
bool KHR_materials_common;
|
||||
bool KHR_materials_pbrSpecularGlossiness;
|
||||
|
||||
} extensionsUsed;
|
||||
|
||||
|
@ -1142,16 +1055,11 @@ namespace glTF2
|
|||
LazyDict<Material> materials;
|
||||
LazyDict<Mesh> meshes;
|
||||
LazyDict<Node> nodes;
|
||||
//LazyDict<Program> programs;
|
||||
LazyDict<Sampler> samplers;
|
||||
LazyDict<Scene> scenes;
|
||||
//LazyDict<Shader> shaders;
|
||||
LazyDict<Skin> skins;
|
||||
//LazyDict<Technique> techniques;
|
||||
LazyDict<Skin> skins;
|
||||
LazyDict<Texture> textures;
|
||||
|
||||
LazyDict<Light> lights; // KHR_materials_common ext
|
||||
|
||||
Ref<Scene> scene;
|
||||
|
||||
public:
|
||||
|
@ -1167,23 +1075,16 @@ namespace glTF2
|
|||
, materials (*this, "materials")
|
||||
, meshes (*this, "meshes")
|
||||
, nodes (*this, "nodes")
|
||||
//, programs (*this, "programs")
|
||||
, samplers (*this, "samplers")
|
||||
, scenes (*this, "scenes")
|
||||
//, shaders (*this, "shaders")
|
||||
, skins (*this, "skins")
|
||||
//, techniques (*this, "techniques")
|
||||
, skins (*this, "skins")
|
||||
, textures (*this, "textures")
|
||||
, lights (*this, "lights", "KHR_materials_common")
|
||||
{
|
||||
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
|
||||
}
|
||||
|
||||
//! Main function
|
||||
void Load(const std::string& file, bool isBinary = false);
|
||||
|
||||
//! Enables the "KHR_binary_glTF" extension on the asset
|
||||
void SetAsBinary();
|
||||
void Load(const std::string& file);
|
||||
|
||||
//! Search for an available name, starting from the given strings
|
||||
std::string FindUniqueID(const std::string& str, const char* suffix);
|
||||
|
@ -1192,11 +1093,8 @@ namespace glTF2
|
|||
{ return mBodyBuffer; }
|
||||
|
||||
private:
|
||||
void ReadBinaryHeader(IOStream& stream);
|
||||
|
||||
void ReadExtensionsUsed(Document& doc);
|
||||
|
||||
|
||||
IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
@ -44,11 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// Header files, Assimp
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Header files, Open3DGC.
|
||||
# include <Open3DGC/o3dgcSC3DMCDecoder.h>
|
||||
#endif
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace glTF2 {
|
||||
|
@ -128,6 +123,18 @@ namespace {
|
|||
return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
|
||||
}
|
||||
|
||||
inline Value* FindNumber(Value& val, const char* id)
|
||||
{
|
||||
Value::MemberIterator it = val.FindMember(id);
|
||||
return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
|
||||
}
|
||||
|
||||
inline Value* FindUInt(Value& val, const char* id)
|
||||
{
|
||||
Value::MemberIterator it = val.FindMember(id);
|
||||
return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : 0;
|
||||
}
|
||||
|
||||
inline Value* FindArray(Value& val, const char* id)
|
||||
{
|
||||
Value::MemberIterator it = val.FindMember(id);
|
||||
|
@ -176,7 +183,7 @@ inline void LazyDict<T>::AttachToDocument(Document& doc)
|
|||
}
|
||||
|
||||
if (container) {
|
||||
mDict = FindObject(*container, mDictId);
|
||||
mDict = FindArray(*container, mDictId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,18 +194,11 @@ inline void LazyDict<T>::DetachFromDocument()
|
|||
}
|
||||
|
||||
template<class T>
|
||||
Ref<T> LazyDict<T>::Get(unsigned int i)
|
||||
Ref<T> LazyDict<T>::Retrieve(unsigned int i)
|
||||
{
|
||||
return Ref<T>(mObjs, i);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Ref<T> LazyDict<T>::Get(const char* id)
|
||||
{
|
||||
id = T::TranslateId(mAsset, id);
|
||||
|
||||
typename Dict::iterator it = mObjsById.find(id);
|
||||
if (it != mObjsById.end()) { // already created?
|
||||
typename Dict::iterator it = mObjsByOIndex.find(i);
|
||||
if (it != mObjsByOIndex.end()) {// already created?
|
||||
return Ref<T>(mObjs, it->second);
|
||||
}
|
||||
|
||||
|
@ -207,27 +207,52 @@ Ref<T> LazyDict<T>::Get(const char* id)
|
|||
throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\"");
|
||||
}
|
||||
|
||||
Value::MemberIterator obj = mDict->FindMember(id);
|
||||
if (obj == mDict->MemberEnd()) {
|
||||
throw DeadlyImportError("GLTF: Missing object with id \"" + std::string(id) + "\" in \"" + mDictId + "\"");
|
||||
}
|
||||
if (!obj->value.IsObject()) {
|
||||
throw DeadlyImportError("GLTF: Object with id \"" + std::string(id) + "\" is not a JSON object");
|
||||
if (!mDict->IsArray()) {
|
||||
throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\"");
|
||||
}
|
||||
|
||||
Value &obj = (*mDict)[i];
|
||||
|
||||
if (!obj.IsObject()) {
|
||||
throw DeadlyImportError("GLTF: Object at index \"" + std::to_string(i) + "\" is not a JSON object");
|
||||
}
|
||||
|
||||
// create an instance of the given type
|
||||
T* inst = new T();
|
||||
inst->id = id;
|
||||
ReadMember(obj->value, "name", inst->name);
|
||||
inst->Read(obj->value, mAsset);
|
||||
inst->id = std::string(mDictId) + "_" + std::to_string(i);
|
||||
inst->oIndex = i;
|
||||
ReadMember(obj, "name", inst->name);
|
||||
inst->Read(obj, mAsset);
|
||||
|
||||
return Add(inst);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Ref<T> LazyDict<T>::Get(unsigned int i)
|
||||
{
|
||||
|
||||
return Ref<T>(mObjs, i);
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Ref<T> LazyDict<T>::Get(const char* id)
|
||||
{
|
||||
id = T::TranslateId(mAsset, id);
|
||||
|
||||
typename IdDict::iterator it = mObjsById.find(id);
|
||||
if (it != mObjsById.end()) { // already created?
|
||||
return Ref<T>(mObjs, it->second);
|
||||
}
|
||||
|
||||
return Ref<T>();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Ref<T> LazyDict<T>::Add(T* obj)
|
||||
{
|
||||
unsigned int idx = unsigned(mObjs.size());
|
||||
mObjs.push_back(obj);
|
||||
mObjsByOIndex[obj->oIndex] = idx;
|
||||
mObjsById[obj->id] = idx;
|
||||
mAsset.mUsedIds[obj->id] = true;
|
||||
return Ref<T>(mObjs, idx);
|
||||
|
@ -241,8 +266,10 @@ Ref<T> LazyDict<T>::Create(const char* id)
|
|||
throw DeadlyImportError("GLTF: two objects with the same ID exist");
|
||||
}
|
||||
T* inst = new T();
|
||||
unsigned int idx = unsigned(mObjs.size());
|
||||
inst->id = id;
|
||||
inst->index = static_cast<int>(mObjs.size());
|
||||
inst->index = idx;
|
||||
inst->oIndex = idx;
|
||||
return Add(inst);
|
||||
}
|
||||
|
||||
|
@ -263,11 +290,6 @@ inline Buffer::~Buffer()
|
|||
|
||||
inline const char* Buffer::TranslateId(Asset& r, const char* id)
|
||||
{
|
||||
// Compatibility with old spec
|
||||
if (r.extensionsUsed.KHR_binary_glTF && strcmp(id, "KHR_binary_glTF") == 0) {
|
||||
return "binary_glTF";
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -310,7 +332,9 @@ inline void Buffer::Read(Value& obj, Asset& r)
|
|||
}
|
||||
else { // Local file
|
||||
if (byteLength > 0) {
|
||||
IOStream* file = r.OpenFile(uri, "rb");
|
||||
std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
|
||||
|
||||
IOStream* file = r.OpenFile(dir + uri, "rb");
|
||||
if (file) {
|
||||
bool ok = LoadFromStream(*file, byteLength);
|
||||
delete file;
|
||||
|
@ -437,9 +461,9 @@ inline void Buffer::Grow(size_t amount)
|
|||
|
||||
inline void BufferView::Read(Value& obj, Asset& r)
|
||||
{
|
||||
const char* bufferId = MemberOrDefault<const char*>(obj, "buffer", 0);
|
||||
if (bufferId) {
|
||||
buffer = r.buffers.Get(bufferId);
|
||||
|
||||
if (Value* bufferVal = FindUInt(obj, "buffer")) {
|
||||
buffer = r.buffers.Retrieve(bufferVal->GetUint());
|
||||
}
|
||||
|
||||
byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
|
||||
|
@ -452,9 +476,9 @@ inline void BufferView::Read(Value& obj, Asset& r)
|
|||
|
||||
inline void Accessor::Read(Value& obj, Asset& r)
|
||||
{
|
||||
const char* bufferViewId = MemberOrDefault<const char*>(obj, "bufferView", 0);
|
||||
if (bufferViewId) {
|
||||
bufferView = r.bufferViews.Get(bufferViewId);
|
||||
|
||||
if (Value* bufferViewVal = FindUInt(obj, "bufferView")) {
|
||||
bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint());
|
||||
}
|
||||
|
||||
byteOffset = MemberOrDefault(obj, "byteOffset", 0u);
|
||||
|
@ -601,29 +625,6 @@ inline Image::Image()
|
|||
|
||||
inline void Image::Read(Value& obj, Asset& r)
|
||||
{
|
||||
// Check for extensions first (to detect binary embedded data)
|
||||
if (Value* extensions = FindObject(obj, "extensions")) {
|
||||
if (r.extensionsUsed.KHR_binary_glTF) {
|
||||
if (Value* ext = FindObject(*extensions, "KHR_binary_glTF")) {
|
||||
|
||||
width = MemberOrDefault(*ext, "width", 0);
|
||||
height = MemberOrDefault(*ext, "height", 0);
|
||||
|
||||
ReadMember(*ext, "mimeType", mimeType);
|
||||
|
||||
const char* bufferViewId;
|
||||
if (ReadMember(*ext, "bufferView", bufferViewId)) {
|
||||
Ref<BufferView> bv = r.bufferViews.Get(bufferViewId);
|
||||
if (bv) {
|
||||
mDataLength = bv->byteLength;
|
||||
mData = new uint8_t[mDataLength];
|
||||
memcpy(mData, bv->buffer->GetPointer() + bv->byteOffset, mDataLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mDataLength) {
|
||||
if (Value* uri = FindString(obj, "uri")) {
|
||||
const char* uristr = uri->GetString();
|
||||
|
@ -671,6 +672,7 @@ inline void Sampler::Read(Value& obj, Asset& r)
|
|||
{
|
||||
SetDefaults();
|
||||
|
||||
ReadMember(obj, "name", name);
|
||||
ReadMember(obj, "magFilter", magFilter);
|
||||
ReadMember(obj, "minFilter", minFilter);
|
||||
ReadMember(obj, "wrapS", wrapS);
|
||||
|
@ -679,34 +681,61 @@ inline void Sampler::Read(Value& obj, Asset& r)
|
|||
|
||||
inline void Sampler::SetDefaults()
|
||||
{
|
||||
magFilter = SamplerMagFilter_Linear;
|
||||
minFilter = SamplerMinFilter_Linear;
|
||||
wrapS = SamplerWrap_Repeat;
|
||||
wrapT = SamplerWrap_Repeat;
|
||||
//only wrapping modes have defaults
|
||||
wrapS = SamplerWrap::Repeat;
|
||||
wrapT = SamplerWrap::Repeat;
|
||||
magFilter = SamplerMagFilter::UNSET;
|
||||
minFilter = SamplerMinFilter::UNSET;
|
||||
}
|
||||
|
||||
inline void Texture::Read(Value& obj, Asset& r)
|
||||
{
|
||||
const char* sourcestr;
|
||||
if (ReadMember(obj, "source", sourcestr)) {
|
||||
source = r.images.Get(sourcestr);
|
||||
if (Value* sourceVal = FindUInt(obj, "source")) {
|
||||
source = r.images.Retrieve(sourceVal->GetUint());
|
||||
}
|
||||
|
||||
const char* samplerstr;
|
||||
if (ReadMember(obj, "sampler", samplerstr)) {
|
||||
sampler = r.samplers.Get(samplerstr);
|
||||
if (Value* samplerVal = FindUInt(obj, "sampler")) {
|
||||
sampler = r.samplers.Retrieve(samplerVal->GetUint());
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
inline void ReadMaterialProperty(Asset& r, Value& vals, const char* propName, TexProperty& out)
|
||||
inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
|
||||
{
|
||||
if (Value* index = FindUInt(*prop, "index")) {
|
||||
out.texture = r.textures.Retrieve(index->GetUint());
|
||||
}
|
||||
|
||||
if (Value* texcoord = FindUInt(*prop, "texCoord")) {
|
||||
out.texCoord = texcoord->GetUint();
|
||||
}
|
||||
}
|
||||
|
||||
inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, TextureInfo& out)
|
||||
{
|
||||
if (Value* prop = FindMember(vals, propName)) {
|
||||
if (prop->IsString()) {
|
||||
out.texture = r.textures.Get(prop->GetString());
|
||||
SetTextureProperties(r, prop, out);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, NormalTextureInfo& out)
|
||||
{
|
||||
if (Value* prop = FindMember(vals, propName)) {
|
||||
SetTextureProperties(r, prop, out);
|
||||
|
||||
if (Value* scale = FindNumber(*prop, "scale")) {
|
||||
out.scale = scale->GetDouble();
|
||||
}
|
||||
else {
|
||||
ReadValue(*prop, out.color);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, OcclusionTextureInfo& out)
|
||||
{
|
||||
if (Value* prop = FindMember(vals, propName)) {
|
||||
SetTextureProperties(r, prop, out);
|
||||
|
||||
if (Value* strength = FindNumber(*prop, "strength")) {
|
||||
out.strength = strength->GetDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -716,59 +745,67 @@ inline void Material::Read(Value& material, Asset& r)
|
|||
{
|
||||
SetDefaults();
|
||||
|
||||
if (Value* values = FindObject(material, "values")) {
|
||||
ReadMaterialProperty(r, *values, "ambient", this->ambient);
|
||||
ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
|
||||
ReadMaterialProperty(r, *values, "specular", this->specular);
|
||||
|
||||
ReadMember(*values, "transparency", transparency);
|
||||
ReadMember(*values, "shininess", shininess);
|
||||
if (Value* pbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) {
|
||||
ReadMember(*pbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor);
|
||||
ReadTextureProperty(r, *pbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture);
|
||||
ReadTextureProperty(r, *pbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture);
|
||||
ReadMember(*pbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor);
|
||||
ReadMember(*pbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor);
|
||||
}
|
||||
|
||||
ReadTextureProperty(r, material, "normalTexture", this->normalTexture);
|
||||
ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture);
|
||||
ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture);
|
||||
ReadMember(material, "emissiveFactor", this->emissiveFactor);
|
||||
|
||||
ReadMember(material, "doubleSided", this->doubleSided);
|
||||
ReadMember(material, "alphaMode", this->alphaMode);
|
||||
ReadMember(material, "alphaCutoff", this->alphaCutoff);
|
||||
|
||||
if (Value* extensions = FindObject(material, "extensions")) {
|
||||
if (r.extensionsUsed.KHR_materials_common) {
|
||||
if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
|
||||
if (Value* tnq = FindString(*ext, "technique")) {
|
||||
const char* t = tnq->GetString();
|
||||
if (strcmp(t, "BLINN") == 0) technique = Technique_BLINN;
|
||||
else if (strcmp(t, "PHONG") == 0) technique = Technique_PHONG;
|
||||
else if (strcmp(t, "LAMBERT") == 0) technique = Technique_LAMBERT;
|
||||
else if (strcmp(t, "CONSTANT") == 0) technique = Technique_CONSTANT;
|
||||
}
|
||||
if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
|
||||
if (Value* pbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) {
|
||||
PbrSpecularGlossiness pbrSG;
|
||||
|
||||
if (Value* values = FindObject(*ext, "values")) {
|
||||
ReadMaterialProperty(r, *values, "ambient", this->ambient);
|
||||
ReadMaterialProperty(r, *values, "diffuse", this->diffuse);
|
||||
ReadMaterialProperty(r, *values, "specular", this->specular);
|
||||
ReadMember(*pbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor);
|
||||
ReadTextureProperty(r, *pbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture);
|
||||
ReadTextureProperty(r, *pbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture);
|
||||
ReadMember(*pbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor);
|
||||
ReadMember(*pbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor);
|
||||
|
||||
ReadMember(*values, "doubleSided", doubleSided);
|
||||
ReadMember(*values, "transparent", transparent);
|
||||
ReadMember(*values, "transparency", transparency);
|
||||
ReadMember(*values, "shininess", shininess);
|
||||
}
|
||||
this->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void SetVector(vec4& v, float x, float y, float z, float w)
|
||||
{ v[0] = x; v[1] = y; v[2] = z; v[3] = w; }
|
||||
void SetVector(vec4& v, const float(&in)[4])
|
||||
{ v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; v[3] = in[3]; }
|
||||
|
||||
void SetVector(vec3& v, const float(&in)[3])
|
||||
{ v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; }
|
||||
}
|
||||
|
||||
inline void Material::SetDefaults()
|
||||
{
|
||||
SetVector(ambient.color, 0, 0, 0, 1);
|
||||
SetVector(diffuse.color, 0, 0, 0, 1);
|
||||
SetVector(specular.color, 0, 0, 0, 1);
|
||||
SetVector(emission.color, 0, 0, 0, 1);
|
||||
//pbr materials
|
||||
SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor);
|
||||
pbrMetallicRoughness.metallicFactor = 1.0;
|
||||
pbrMetallicRoughness.roughnessFactor = 1.0;
|
||||
|
||||
SetVector(emissiveFactor, defaultEmissiveFactor);
|
||||
alphaMode = "OPAQUE";
|
||||
alphaCutoff = 0.5;
|
||||
doubleSided = false;
|
||||
transparent = false;
|
||||
transparency = 1.0;
|
||||
shininess = 0.0;
|
||||
}
|
||||
|
||||
technique = Technique_undefined;
|
||||
inline void PbrSpecularGlossiness::SetDefaults()
|
||||
{
|
||||
//pbrSpecularGlossiness properties
|
||||
SetVector(diffuseFactor, defaultDiffuseFactor);
|
||||
SetVector(specularFactor, defaultSpecularFactor);
|
||||
glossinessFactor = 1.0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -808,6 +845,10 @@ namespace {
|
|||
|
||||
inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
|
||||
{
|
||||
if (Value* name = FindMember(pJSON_Object, "name")) {
|
||||
this->name = name->GetString();
|
||||
}
|
||||
|
||||
/****************** Mesh primitives ******************/
|
||||
if (Value* primitives = FindArray(pJSON_Object, "primitives")) {
|
||||
this->primitives.resize(primitives->Size());
|
||||
|
@ -819,7 +860,7 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
|
|||
|
||||
if (Value* attrs = FindObject(primitive, "attributes")) {
|
||||
for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) {
|
||||
if (!it->value.IsString()) continue;
|
||||
if (!it->value.IsUint()) continue;
|
||||
const char* attr = it->name.GetString();
|
||||
// Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX,
|
||||
// and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc.
|
||||
|
@ -829,262 +870,22 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
|
|||
if (GetAttribVector(prim, attr, vec, undPos)) {
|
||||
size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
|
||||
if ((*vec).size() <= idx) (*vec).resize(idx + 1);
|
||||
(*vec)[idx] = pAsset_Root.accessors.Get(it->value.GetString());
|
||||
(*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Value* indices = FindString(primitive, "indices")) {
|
||||
prim.indices = pAsset_Root.accessors.Get(indices->GetString());
|
||||
if (Value* indices = FindUInt(primitive, "indices")) {
|
||||
prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
|
||||
}
|
||||
|
||||
if (Value* material = FindString(primitive, "material")) {
|
||||
prim.material = pAsset_Root.materials.Get(material->GetString());
|
||||
if (Value* material = FindUInt(primitive, "material")) {
|
||||
prim.material = pAsset_Root.materials.Retrieve(material->GetUint());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************** Mesh extensions ******************/
|
||||
Value* json_extensions = FindObject(pJSON_Object, "extensions");
|
||||
|
||||
if(json_extensions == nullptr) goto mr_skip_extensions;
|
||||
|
||||
for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); it_memb++)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
if(it_memb->name.GetString() == std::string("Open3DGC-compression"))
|
||||
{
|
||||
// Search for compressed data.
|
||||
// Compressed data contain description of part of "buffer" which is encoded. This part must be decoded and
|
||||
// new data will replace old encoded part by request. In fact \"compressedData\" is kind of "accessor" structure.
|
||||
Value* comp_data = FindObject(it_memb->value, "compressedData");
|
||||
|
||||
if(comp_data == nullptr) throw DeadlyImportError("GLTF: \"Open3DGC-compression\" must has \"compressedData\".");
|
||||
|
||||
DefaultLogger::get()->info("GLTF: Decompressing Open3DGC data.");
|
||||
|
||||
/************** Read data from JSON-document **************/
|
||||
#define MESH_READ_COMPRESSEDDATA_MEMBER(pFieldName, pOut) \
|
||||
if(!ReadMember(*comp_data, pFieldName, pOut)) \
|
||||
{ \
|
||||
throw DeadlyImportError(std::string("GLTF: \"compressedData\" must has \"") + pFieldName + "\"."); \
|
||||
}
|
||||
|
||||
const char* mode_str;
|
||||
const char* type_str;
|
||||
ComponentType component_type;
|
||||
SCompression_Open3DGC* ext_o3dgc = new SCompression_Open3DGC;
|
||||
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("buffer", ext_o3dgc->Buffer);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("byteOffset", ext_o3dgc->Offset);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("componentType", component_type);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("type", type_str);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("count", ext_o3dgc->Count);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("mode", mode_str);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("indicesCount", ext_o3dgc->IndicesCount);
|
||||
MESH_READ_COMPRESSEDDATA_MEMBER("verticesCount", ext_o3dgc->VerticesCount);
|
||||
|
||||
#undef MESH_READ_COMPRESSEDDATA_MEMBER
|
||||
|
||||
// Check some values
|
||||
if(strcmp(type_str, "SCALAR")) throw DeadlyImportError("GLTF: only \"SCALAR\" type is supported for compressed data.");
|
||||
if(component_type != ComponentType_UNSIGNED_BYTE) throw DeadlyImportError("GLTF: only \"UNSIGNED_BYTE\" component type is supported for compressed data.");
|
||||
|
||||
// Set read/write data mode.
|
||||
if(strcmp(mode_str, "binary") == 0)
|
||||
ext_o3dgc->Binary = true;
|
||||
else if(strcmp(mode_str, "ascii") == 0)
|
||||
ext_o3dgc->Binary = false;
|
||||
else
|
||||
throw DeadlyImportError(std::string("GLTF: for compressed data supported modes is: \"ascii\", \"binary\". Not the: \"") + mode_str + "\".");
|
||||
|
||||
/************************ Decoding ************************/
|
||||
Decode_O3DGC(*ext_o3dgc, pAsset_Root);
|
||||
Extension.push_back(ext_o3dgc);// store info in mesh extensions list.
|
||||
}// if(it_memb->name.GetString() == "Open3DGC-compression")
|
||||
else
|
||||
#endif
|
||||
{
|
||||
throw DeadlyImportError(std::string("GLTF: Unknown mesh extension: \"") + it_memb->name.GetString() + "\".");
|
||||
}
|
||||
}// for(Value::MemberIterator it_memb = json_extensions->MemberBegin(); it_memb != json_extensions->MemberEnd(); json_extensions++)
|
||||
|
||||
mr_skip_extensions:
|
||||
|
||||
return;// After label some operators must be present.
|
||||
}
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC& pCompression_Open3DGC, Asset& pAsset_Root)
|
||||
{
|
||||
typedef unsigned short IndicesType;///< \sa glTFExporter::ExportMeshes.
|
||||
|
||||
o3dgc::SC3DMCDecoder<IndicesType> decoder;
|
||||
o3dgc::IndexedFaceSet<IndicesType> ifs;
|
||||
o3dgc::BinaryStream bstream;
|
||||
uint8_t* decoded_data;
|
||||
size_t decoded_data_size = 0;
|
||||
Ref<Buffer> buf = pAsset_Root.buffers.Get(pCompression_Open3DGC.Buffer);
|
||||
|
||||
// Read data from buffer and place it in BinaryStream for decoder.
|
||||
// Just "Count" because always is used type equivalent to uint8_t.
|
||||
bstream.LoadFromBuffer(&buf->GetPointer()[pCompression_Open3DGC.Offset], static_cast<unsigned long>(pCompression_Open3DGC.Count));
|
||||
|
||||
// After decoding header we can get size of primitives.
|
||||
if(decoder.DecodeHeader(ifs, bstream) != o3dgc::O3DGC_OK) throw DeadlyImportError("GLTF: can not decode Open3DGC header.");
|
||||
|
||||
/****************** Get sizes of arrays and check sizes ******************/
|
||||
// Note. See "Limitations for meshes when using Open3DGC-compression".
|
||||
|
||||
// Indices
|
||||
size_t size_coordindex = ifs.GetNCoordIndex() * 3;// See float attributes note.
|
||||
|
||||
if(primitives[0].indices->count != size_coordindex)
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed indices count (" + std::to_string(size_coordindex) +
|
||||
") not equal to uncompressed (" + std::to_string(primitives[0].indices->count) + ").");
|
||||
|
||||
size_coordindex *= sizeof(IndicesType);
|
||||
// Coordinates
|
||||
size_t size_coord = ifs.GetNCoord();// See float attributes note.
|
||||
|
||||
if(primitives[0].attributes.position[0]->count != size_coord)
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed positions count (" + std::to_string(size_coord) +
|
||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.position[0]->count) + ").");
|
||||
|
||||
size_coord *= 3 * sizeof(float);
|
||||
// Normals
|
||||
size_t size_normal = ifs.GetNNormal();// See float attributes note.
|
||||
|
||||
if(primitives[0].attributes.normal[0]->count != size_normal)
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed normals count (" + std::to_string(size_normal) +
|
||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.normal[0]->count) + ").");
|
||||
|
||||
size_normal *= 3 * sizeof(float);
|
||||
// Additional attributes.
|
||||
std::vector<size_t> size_floatattr;
|
||||
std::vector<size_t> size_intattr;
|
||||
|
||||
size_floatattr.resize(ifs.GetNumFloatAttributes());
|
||||
size_intattr.resize(ifs.GetNumIntAttributes());
|
||||
|
||||
decoded_data_size = size_coordindex + size_coord + size_normal;
|
||||
for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
|
||||
{
|
||||
// size = number_of_elements * components_per_element * size_of_component.
|
||||
// Note. But as you can see above, at first we are use this variable in meaning "count". After checking count of objects...
|
||||
size_t tval = ifs.GetNFloatAttribute(static_cast<unsigned long>(idx));
|
||||
|
||||
switch(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))
|
||||
{
|
||||
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
||||
// Check situation when encoded data contain texture coordinates but primitive not.
|
||||
if(idx_texcoord < primitives[0].attributes.texcoord.size())
|
||||
{
|
||||
if(primitives[0].attributes.texcoord[idx]->count != tval)
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Compressed texture coordinates count (" + std::to_string(tval) +
|
||||
") not equal to uncompressed (" + std::to_string(primitives[0].attributes.texcoord[idx]->count) + ").");
|
||||
|
||||
idx_texcoord++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ifs.SetNFloatAttribute(static_cast<unsigned long>(idx), 0ul);// Disable decoding this attribute.
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
||||
}
|
||||
|
||||
tval *= ifs.GetFloatAttributeDim(static_cast<unsigned long>(idx)) * sizeof(o3dgc::Real);// After checking count of objects we can get size of array.
|
||||
size_floatattr[idx] = tval;
|
||||
decoded_data_size += tval;
|
||||
}
|
||||
|
||||
for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++)
|
||||
{
|
||||
// size = number_of_elements * components_per_element * size_of_component. See float attributes note.
|
||||
size_t tval = ifs.GetNIntAttribute(static_cast<unsigned long>(idx));
|
||||
switch( ifs.GetIntAttributeType(static_cast<unsigned long>(idx) ) )
|
||||
{
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
||||
}
|
||||
|
||||
tval *= ifs.GetIntAttributeDim(static_cast<unsigned long>(idx)) * sizeof(long);// See float attributes note.
|
||||
size_intattr[idx] = tval;
|
||||
decoded_data_size += tval;
|
||||
}
|
||||
|
||||
// Create array for decoded data.
|
||||
decoded_data = new uint8_t[decoded_data_size];
|
||||
|
||||
/****************** Set right array regions for decoder ******************/
|
||||
|
||||
auto get_buf_offset = [](Ref<Accessor>& pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
|
||||
|
||||
// Indices
|
||||
ifs.SetCoordIndex((IndicesType* const)(decoded_data + get_buf_offset(primitives[0].indices)));
|
||||
// Coordinates
|
||||
ifs.SetCoord((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
|
||||
// Normals
|
||||
if(size_normal)
|
||||
{
|
||||
ifs.SetNormal((o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
|
||||
}
|
||||
|
||||
for(size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++)
|
||||
{
|
||||
switch(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx)))
|
||||
{
|
||||
case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
|
||||
if(idx_texcoord < primitives[0].attributes.texcoord.size())
|
||||
{
|
||||
// See above about absent attributes.
|
||||
ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real* const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
|
||||
idx_texcoord++;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of float attribute: " + to_string(ifs.GetFloatAttributeType(static_cast<unsigned long>(idx))));
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t idx = 0, idx_end = size_intattr.size(); idx < idx_end; idx++) {
|
||||
switch(ifs.GetIntAttributeType(static_cast<unsigned int>(idx))) {
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID:
|
||||
case o3dgc::O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID:
|
||||
break;
|
||||
|
||||
// ifs.SetIntAttribute(idx, (long* const)(decoded_data + get_buf_offset(primitives[0].attributes.joint)));
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Open3DGC. Unsupported type of int attribute: " + to_string(ifs.GetIntAttributeType(static_cast<unsigned long>(idx))));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Decode data
|
||||
//
|
||||
if ( decoder.DecodePayload( ifs, bstream ) != o3dgc::O3DGC_OK ) {
|
||||
throw DeadlyImportError( "GLTF: can not decode Open3DGC data." );
|
||||
}
|
||||
|
||||
// Set encoded region for "buffer".
|
||||
buf->EncodedRegion_Mark(pCompression_Open3DGC.Offset, pCompression_Open3DGC.Count, decoded_data, decoded_data_size, id);
|
||||
// No. Do not delete "output_data". After calling "EncodedRegion_Mark" bufferView is owner of "output_data".
|
||||
// "delete [] output_data;"
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void Camera::Read(Value& obj, Asset& r)
|
||||
{
|
||||
type = MemberOrDefault(obj, "type", Camera::Perspective);
|
||||
|
@ -1095,80 +896,34 @@ inline void Camera::Read(Value& obj, Asset& r)
|
|||
if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters");
|
||||
|
||||
if (type == Camera::Perspective) {
|
||||
perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
|
||||
perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
|
||||
perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
|
||||
perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
|
||||
cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f);
|
||||
cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f);
|
||||
cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f);
|
||||
cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f);
|
||||
}
|
||||
else {
|
||||
ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f);
|
||||
ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f);
|
||||
ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f);
|
||||
ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
|
||||
cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f);
|
||||
cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f);
|
||||
cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f);
|
||||
cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Light::Read(Value& obj, Asset& r)
|
||||
{
|
||||
SetDefaults();
|
||||
|
||||
if (Value* type = FindString(obj, "type")) {
|
||||
const char* t = type->GetString();
|
||||
if (strcmp(t, "ambient") == 0) this->type = Type_ambient;
|
||||
else if (strcmp(t, "directional") == 0) this->type = Type_directional;
|
||||
else if (strcmp(t, "point") == 0) this->type = Type_point;
|
||||
else if (strcmp(t, "spot") == 0) this->type = Type_spot;
|
||||
|
||||
if (this->type != Type_undefined) {
|
||||
if (Value* vals = FindString(obj, t)) {
|
||||
ReadMember(*vals, "color", color);
|
||||
|
||||
ReadMember(*vals, "constantAttenuation", constantAttenuation);
|
||||
ReadMember(*vals, "linearAttenuation", linearAttenuation);
|
||||
ReadMember(*vals, "quadraticAttenuation", quadraticAttenuation);
|
||||
ReadMember(*vals, "distance", distance);
|
||||
|
||||
ReadMember(*vals, "falloffAngle", falloffAngle);
|
||||
ReadMember(*vals, "falloffExponent", falloffExponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Light::SetDefaults()
|
||||
{
|
||||
#ifndef M_PI
|
||||
const float M_PI = 3.14159265358979323846f;
|
||||
#endif
|
||||
|
||||
type = Type_undefined;
|
||||
|
||||
SetVector(color, 0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
constantAttenuation = 0.f;
|
||||
linearAttenuation = 1.f;
|
||||
quadraticAttenuation = 1.f;
|
||||
distance = 0.f;
|
||||
|
||||
falloffAngle = static_cast<float>(M_PI / 2.f);
|
||||
falloffExponent = 0.f;
|
||||
}
|
||||
|
||||
inline void Node::Read(Value& obj, Asset& r)
|
||||
{
|
||||
|
||||
if (Value* children = FindArray(obj, "children")) {
|
||||
this->children.reserve(children->Size());
|
||||
for (unsigned int i = 0; i < children->Size(); ++i) {
|
||||
Value& child = (*children)[i];
|
||||
if (child.IsString()) {
|
||||
if (child.IsUint()) {
|
||||
// get/create the child node
|
||||
Ref<Node> chn = r.nodes.Get(child.GetString());
|
||||
Ref<Node> chn = r.nodes.Retrieve(child.GetUint());
|
||||
if (chn) this->children.push_back(chn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Value* matrix = FindArray(obj, "matrix")) {
|
||||
ReadValue(*matrix, this->matrix);
|
||||
}
|
||||
|
@ -1178,64 +933,46 @@ inline void Node::Read(Value& obj, Asset& r)
|
|||
ReadMember(obj, "rotation", rotation);
|
||||
}
|
||||
|
||||
if (Value* meshes = FindArray(obj, "meshes")) {
|
||||
unsigned numMeshes = (unsigned)meshes->Size();
|
||||
if (Value* mesh = FindUInt(obj, "mesh")) {
|
||||
Ref<Mesh> meshRef = r.meshes.Retrieve((*mesh).GetUint());
|
||||
|
||||
std::vector<unsigned int> meshList;
|
||||
|
||||
this->meshes.reserve(numMeshes);
|
||||
for (unsigned i = 0; i < numMeshes; ++i) {
|
||||
if ((*meshes)[i].IsString()) {
|
||||
Ref<Mesh> mesh = r.meshes.Get((*meshes)[i].GetString());
|
||||
if (mesh) this->meshes.push_back(mesh);
|
||||
}
|
||||
}
|
||||
if (meshRef) this->mesh = meshRef;
|
||||
}
|
||||
|
||||
if (Value* camera = FindString(obj, "camera")) {
|
||||
this->camera = r.cameras.Get(camera->GetString());
|
||||
if (Value* camera = FindUInt(obj, "camera")) {
|
||||
this->camera = r.cameras.Retrieve(camera->GetUint());
|
||||
if (this->camera)
|
||||
this->camera->id = this->id;
|
||||
}
|
||||
|
||||
// TODO load "skeletons", "skin", "jointName"
|
||||
|
||||
if (Value* extensions = FindObject(obj, "extensions")) {
|
||||
if (r.extensionsUsed.KHR_materials_common) {
|
||||
|
||||
if (Value* ext = FindObject(*extensions, "KHR_materials_common")) {
|
||||
if (Value* light = FindString(*ext, "light")) {
|
||||
this->light = r.lights.Get(light->GetString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Scene::Read(Value& obj, Asset& r)
|
||||
{
|
||||
if (Value* array = FindArray(obj, "nodes")) {
|
||||
for (unsigned int i = 0; i < array->Size(); ++i) {
|
||||
if (!(*array)[i].IsString()) continue;
|
||||
Ref<Node> node = r.nodes.Get((*array)[i].GetString());
|
||||
if (!(*array)[i].IsUint()) continue;
|
||||
Ref<Node> node = r.nodes.Retrieve((*array)[i].GetUint());
|
||||
if (node)
|
||||
this->nodes.push_back(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void AssetMetadata::Read(Document& doc)
|
||||
{
|
||||
// read the version, etc.
|
||||
float statedVersion = 0;
|
||||
if (Value* obj = FindObject(doc, "asset")) {
|
||||
ReadMember(*obj, "copyright", copyright);
|
||||
ReadMember(*obj, "generator", generator);
|
||||
|
||||
premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
|
||||
statedVersion = MemberOrDefault(*obj, "version", 0);
|
||||
if (Value* versionString = FindString(*obj, "version")) {
|
||||
version = versionString->GetString();
|
||||
} else if (Value* versionNumber = FindNumber (*obj, "version")) {
|
||||
char buf[4];
|
||||
|
||||
ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
|
||||
|
||||
version = buf;
|
||||
}
|
||||
|
||||
if (Value* profile = FindObject(*obj, "profile")) {
|
||||
ReadMember(*profile, "api", this->profile.api);
|
||||
|
@ -1243,60 +980,16 @@ inline void AssetMetadata::Read(Document& doc)
|
|||
}
|
||||
}
|
||||
|
||||
version = std::max(statedVersion, version);
|
||||
|
||||
if (version == 0) {
|
||||
// if missing version, we'll assume version 1.0...
|
||||
version = 1;
|
||||
}
|
||||
|
||||
if (version != 1) {
|
||||
char msg[128];
|
||||
ai_snprintf(msg, 128, "GLTF: Unsupported glTF version: %.1f", version);
|
||||
throw DeadlyImportError(msg);
|
||||
if (version.empty() || version[0] != '2') {
|
||||
throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Asset methods implementation
|
||||
//
|
||||
|
||||
inline void Asset::ReadBinaryHeader(IOStream& stream)
|
||||
{
|
||||
GLB_Header header;
|
||||
if (stream.Read(&header, sizeof(header), 1) != 1) {
|
||||
throw DeadlyImportError("GLTF: Unable to read the file header");
|
||||
}
|
||||
|
||||
if (strncmp((char*)header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic)) != 0) {
|
||||
throw DeadlyImportError("GLTF: Invalid binary glTF file");
|
||||
}
|
||||
|
||||
AI_SWAP4(header.version);
|
||||
asset.version = header.version;
|
||||
if (header.version != 1) {
|
||||
throw DeadlyImportError("GLTF: Unsupported binary glTF version");
|
||||
}
|
||||
|
||||
AI_SWAP4(header.sceneFormat);
|
||||
if (header.sceneFormat != SceneFormat_JSON) {
|
||||
throw DeadlyImportError("GLTF: Unsupported binary glTF scene format");
|
||||
}
|
||||
|
||||
AI_SWAP4(header.length);
|
||||
AI_SWAP4(header.sceneLength);
|
||||
|
||||
mSceneLength = static_cast<size_t>(header.sceneLength);
|
||||
|
||||
mBodyOffset = sizeof(header)+mSceneLength;
|
||||
mBodyOffset = (mBodyOffset + 3) & ~3; // Round up to next multiple of 4
|
||||
|
||||
mBodyLength = header.length - mBodyOffset;
|
||||
}
|
||||
|
||||
inline void Asset::Load(const std::string& pFile, bool isBinary)
|
||||
inline void Asset::Load(const std::string& pFile)
|
||||
{
|
||||
mCurrentAssetDir.clear();
|
||||
int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\')));
|
||||
|
@ -1307,16 +1000,8 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
|
|||
throw DeadlyImportError("GLTF: Could not open file for reading");
|
||||
}
|
||||
|
||||
// is binary? then read the header
|
||||
if (isBinary) {
|
||||
SetAsBinary(); // also creates the body buffer
|
||||
ReadBinaryHeader(*stream);
|
||||
}
|
||||
else {
|
||||
mSceneLength = stream->FileSize();
|
||||
mBodyLength = 0;
|
||||
}
|
||||
|
||||
mSceneLength = stream->FileSize();
|
||||
mBodyLength = 0;
|
||||
|
||||
// read the scene data
|
||||
|
||||
|
@ -1361,12 +1046,14 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
|
|||
mDicts[i]->AttachToDocument(doc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Read the "scene" property, which specifies which scene to load
|
||||
// and recursively load everything referenced by it
|
||||
if (Value* scene = FindString(doc, "scene")) {
|
||||
this->scene = scenes.Get(scene->GetString());
|
||||
if (Value* scene = FindUInt(doc, "scene")) {
|
||||
unsigned int sceneIndex = scene->GetUint();
|
||||
|
||||
Ref<Scene> s = scenes.Retrieve(sceneIndex);
|
||||
|
||||
this->scene = s;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
@ -1375,16 +1062,6 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
|
|||
}
|
||||
}
|
||||
|
||||
inline void Asset::SetAsBinary()
|
||||
{
|
||||
if (!extensionsUsed.KHR_binary_glTF) {
|
||||
extensionsUsed.KHR_binary_glTF = true;
|
||||
mBodyBuffer = buffers.Create("binary_glTF");
|
||||
mBodyBuffer->MarkAsSpecial();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void Asset::ReadExtensionsUsed(Document& doc)
|
||||
{
|
||||
Value* extsUsed = FindArray(doc, "extensionsUsed");
|
||||
|
@ -1401,8 +1078,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
|
|||
#define CHECK_EXT(EXT) \
|
||||
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
|
||||
|
||||
CHECK_EXT(KHR_binary_glTF);
|
||||
CHECK_EXT(KHR_materials_common);
|
||||
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
|
||||
|
||||
#undef CHECK_EXT
|
||||
}
|
||||
|
|
|
@ -43,8 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* Declares a class to write gltf/glb files
|
||||
*
|
||||
* glTF Extensions Support:
|
||||
* KHR_binary_glTF: full
|
||||
* KHR_materials_common: full
|
||||
* KHR_materials_pbrSpecularGlossiness: full
|
||||
*/
|
||||
#ifndef GLTF2ASSETWRITER_H_INC
|
||||
#define GLTF2ASSETWRITER_H_INC
|
||||
|
@ -82,7 +81,6 @@ public:
|
|||
AssetWriter(Asset& asset);
|
||||
|
||||
void WriteFile(const char* path);
|
||||
void WriteGLBFile(const char* path);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -72,6 +72,12 @@ namespace glTF2 {
|
|||
return val;
|
||||
}
|
||||
|
||||
inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& al) {
|
||||
val.SetDouble(r);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
|
||||
if (v.empty()) return;
|
||||
|
@ -91,7 +97,11 @@ namespace glTF2 {
|
|||
{
|
||||
obj.AddMember("bufferView", a.bufferView->index, w.mAl);
|
||||
obj.AddMember("byteOffset", a.byteOffset, w.mAl);
|
||||
obj.AddMember("byteStride", a.byteStride, w.mAl);
|
||||
|
||||
if (a.byteStride != 0) {
|
||||
obj.AddMember("byteStride", a.byteStride, w.mAl);
|
||||
}
|
||||
|
||||
obj.AddMember("componentType", int(a.componentType), w.mAl);
|
||||
obj.AddMember("count", a.count, w.mAl);
|
||||
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
|
||||
|
@ -169,21 +179,7 @@ namespace glTF2 {
|
|||
inline void Write(Value& obj, Image& img, AssetWriter& w)
|
||||
{
|
||||
std::string uri;
|
||||
if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) {
|
||||
Value exts, ext;
|
||||
exts.SetObject();
|
||||
ext.SetObject();
|
||||
|
||||
ext.AddMember("bufferView", img.bufferView->index, w.mAl);
|
||||
|
||||
if (!img.mimeType.empty())
|
||||
ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
|
||||
|
||||
exts.AddMember("KHR_binary_glTF", ext, w.mAl);
|
||||
obj.AddMember("extensions", exts, w.mAl);
|
||||
return;
|
||||
}
|
||||
else if (img.HasData()) {
|
||||
if (img.HasData()) {
|
||||
uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
|
||||
uri += ";base64,";
|
||||
Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri);
|
||||
|
@ -196,51 +192,149 @@ namespace glTF2 {
|
|||
}
|
||||
|
||||
namespace {
|
||||
inline void WriteTex(Value& obj, Ref<Texture> texture, const char* propName, MemoryPoolAllocator<>& al)
|
||||
inline void SetTexBasic(TextureInfo t, Value& tex, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
if (texture) {
|
||||
tex.SetObject();
|
||||
tex.AddMember("index", t.texture->index, al);
|
||||
|
||||
if (t.texCoord != 0) {
|
||||
tex.AddMember("texCoord", t.texCoord, al);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteTex(Value& obj, TextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
|
||||
if (t.texture) {
|
||||
Value tex;
|
||||
tex.SetObject();
|
||||
tex.AddMember("index", texture->index, al);
|
||||
|
||||
SetTexBasic(t, tex, al);
|
||||
|
||||
obj.AddMember(StringRef(propName), tex, al);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
|
||||
inline void WriteTex(Value& obj, NormalTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
WriteTex(obj, prop.texture, propName, al);
|
||||
if (!prop.texture) {
|
||||
Value col;
|
||||
obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
|
||||
|
||||
if (t.texture) {
|
||||
Value tex;
|
||||
|
||||
SetTexBasic(t, tex, al);
|
||||
|
||||
if (t.scale != 1) {
|
||||
tex.AddMember("scale", t.scale, al);
|
||||
}
|
||||
|
||||
obj.AddMember(StringRef(propName), tex, al);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteTex(Value& obj, OcclusionTextureInfo t, const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
|
||||
if (t.texture) {
|
||||
Value tex;
|
||||
|
||||
SetTexBasic(t, tex, al);
|
||||
|
||||
if (t.strength != 1) {
|
||||
tex.AddMember("strength", t.strength, al);
|
||||
}
|
||||
|
||||
obj.AddMember(StringRef(propName), tex, al);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
Value arr;
|
||||
obj.AddMember(StringRef(propName), MakeValue(arr, prop, al), al);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, const float(&defaultVal)[N], MemoryPoolAllocator<>& al)
|
||||
{
|
||||
if (!std::equal(std::begin(prop), std::end(prop), std::begin(defaultVal))) {
|
||||
WriteVec(obj, prop, propName, al);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteFloat(Value& obj, float prop, const char* propName, MemoryPoolAllocator<>& al)
|
||||
{
|
||||
Value num;
|
||||
obj.AddMember(StringRef(propName), MakeValue(num, prop, al), al);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Material& m, AssetWriter& w)
|
||||
{
|
||||
if (m.transparent) {
|
||||
obj.AddMember("alphaMode", "BLEND", w.mAl);
|
||||
}
|
||||
|
||||
Value v;
|
||||
v.SetObject();
|
||||
Value pbrMetallicRoughness;
|
||||
pbrMetallicRoughness.SetObject();
|
||||
{
|
||||
if (m.transparent && !m.diffuse.texture) {
|
||||
m.diffuse.color[3] = m.transparency;
|
||||
}
|
||||
WriteColorOrTex(v, m.ambient, m.ambient.texture ? "ambientTexture" : "ambientFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.diffuse, m.diffuse.texture ? "diffuseTexture" : "diffuseFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.specular, m.specular.texture ? "specularTexture" : "specularFactor", w.mAl);
|
||||
WriteColorOrTex(v, m.emission, m.emission.texture ? "emissionTexture" : "emissionFactor", w.mAl);
|
||||
v.AddMember("shininessFactor", m.shininess, w.mAl);
|
||||
}
|
||||
v.AddMember("type", "commonPhong", w.mAl);
|
||||
Value ext;
|
||||
ext.SetObject();
|
||||
ext.AddMember("KHR_materials_common", v, w.mAl);
|
||||
obj.AddMember("extensions", ext, w.mAl);
|
||||
WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorTexture, "baseColorTexture", w.mAl);
|
||||
WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicRoughnessTexture, "metallicRoughnessTexture", w.mAl);
|
||||
WriteVec(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorFactor, "baseColorFactor", defaultBaseColor, w.mAl);
|
||||
|
||||
WriteTex(obj, m.normal, "normalTexture", w.mAl);
|
||||
if (m.pbrMetallicRoughness.metallicFactor != 1) {
|
||||
WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicFactor, "metallicFactor", w.mAl);
|
||||
}
|
||||
|
||||
if (m.pbrMetallicRoughness.roughnessFactor != 1) {
|
||||
WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.roughnessFactor, "roughnessFactor", w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pbrMetallicRoughness.ObjectEmpty()) {
|
||||
obj.AddMember("pbrMetallicRoughness", pbrMetallicRoughness, w.mAl);
|
||||
}
|
||||
|
||||
WriteTex(obj, m.normalTexture, "normalTexture", w.mAl);
|
||||
WriteTex(obj, m.emissiveTexture, "emissiveTexture", w.mAl);
|
||||
WriteTex(obj, m.occlusionTexture, "occlusionTexture", w.mAl);
|
||||
WriteVec(obj, m.emissiveFactor, "emissiveFactor", defaultEmissiveFactor, w.mAl);
|
||||
|
||||
if (m.alphaCutoff != 0.5) {
|
||||
WriteFloat(obj, m.alphaCutoff, "alphaCutoff", w.mAl);
|
||||
}
|
||||
|
||||
if (m.alphaMode != "OPAQUE") {
|
||||
obj.AddMember("alphaMode", Value(m.alphaMode, w.mAl).Move(), w.mAl);
|
||||
}
|
||||
|
||||
if (m.doubleSided) {
|
||||
obj.AddMember("doubleSided", m.doubleSided, w.mAl);
|
||||
}
|
||||
|
||||
Value exts;
|
||||
exts.SetObject();
|
||||
|
||||
if (m.pbrSpecularGlossiness.isPresent) {
|
||||
Value pbrSpecularGlossiness;
|
||||
pbrSpecularGlossiness.SetObject();
|
||||
|
||||
PbrSpecularGlossiness &pbrSG = m.pbrSpecularGlossiness.value;
|
||||
|
||||
//pbrSpecularGlossiness
|
||||
WriteVec(pbrSpecularGlossiness, pbrSG.diffuseFactor, "diffuseFactor", defaultDiffuseFactor, w.mAl);
|
||||
WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
|
||||
|
||||
if (pbrSG.glossinessFactor != 1) {
|
||||
WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
|
||||
}
|
||||
|
||||
WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
|
||||
WriteTex(pbrSpecularGlossiness, pbrSG.specularGlossinessTexture, "specularGlossinessTexture", w.mAl);
|
||||
|
||||
if (!pbrSpecularGlossiness.ObjectEmpty()) {
|
||||
exts.AddMember("KHR_materials_pbrSpecularGlossiness", pbrSpecularGlossiness, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exts.ObjectEmpty()) {
|
||||
obj.AddMember("extensions", exts, w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -263,59 +357,6 @@ namespace glTF2 {
|
|||
|
||||
inline void Write(Value& obj, Mesh& m, AssetWriter& w)
|
||||
{
|
||||
/********************* Name **********************/
|
||||
obj.AddMember("name", m.name, w.mAl);
|
||||
|
||||
/**************** Mesh extensions ****************/
|
||||
if(m.Extension.size() > 0)
|
||||
{
|
||||
Value json_extensions;
|
||||
|
||||
json_extensions.SetObject();
|
||||
for(Mesh::SExtension* ptr_ext : m.Extension)
|
||||
{
|
||||
switch(ptr_ext->Type)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
case Mesh::SExtension::EType::Compression_Open3DGC:
|
||||
{
|
||||
Value json_comp_data;
|
||||
Mesh::SCompression_Open3DGC* ptr_ext_comp = (Mesh::SCompression_Open3DGC*)ptr_ext;
|
||||
|
||||
// filling object "compressedData"
|
||||
json_comp_data.SetObject();
|
||||
json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl);
|
||||
json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl);
|
||||
json_comp_data.AddMember("componentType", 5121, w.mAl);
|
||||
json_comp_data.AddMember("type", "SCALAR", w.mAl);
|
||||
json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl);
|
||||
if(ptr_ext_comp->Binary)
|
||||
json_comp_data.AddMember("mode", "binary", w.mAl);
|
||||
else
|
||||
json_comp_data.AddMember("mode", "ascii", w.mAl);
|
||||
|
||||
json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl);
|
||||
json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl);
|
||||
// filling object "Open3DGC-compression"
|
||||
Value json_o3dgc;
|
||||
|
||||
json_o3dgc.SetObject();
|
||||
json_o3dgc.AddMember("compressedData", json_comp_data, w.mAl);
|
||||
// add member to object "extensions"
|
||||
json_extensions.AddMember("Open3DGC-compression", json_o3dgc, w.mAl);
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
throw DeadlyImportError("GLTF: Can not write mesh: unknown mesh extension, only Open3DGC is supported.");
|
||||
}// switch(ptr_ext->Type)
|
||||
}// for(Mesh::SExtension* ptr_ext : m.Extension)
|
||||
|
||||
// Add extensions to mesh
|
||||
obj.AddMember("extensions", json_extensions, w.mAl);
|
||||
}// if(m.Extension.size() > 0)
|
||||
|
||||
/****************** Primitives *******************/
|
||||
Value primitives;
|
||||
primitives.SetArray();
|
||||
|
@ -340,10 +381,9 @@ namespace glTF2 {
|
|||
WriteAttrs(w, attrs, p.attributes.position, "POSITION");
|
||||
WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
|
||||
WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
|
||||
WriteAttrs(w, attrs, p.attributes.color, "COLOR");
|
||||
WriteAttrs(w, attrs, p.attributes.joint, "JOINT");
|
||||
WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX");
|
||||
WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT");
|
||||
WriteAttrs(w, attrs, p.attributes.color, "COLOR", true);
|
||||
WriteAttrs(w, attrs, p.attributes.joint, "JOINTS", true);
|
||||
WriteAttrs(w, attrs, p.attributes.weight, "WEIGHTS", true);
|
||||
}
|
||||
prim.AddMember("attributes", attrs, w.mAl);
|
||||
}
|
||||
|
@ -377,7 +417,9 @@ namespace glTF2 {
|
|||
|
||||
AddRefsVector(obj, "children", n.children, w.mAl);
|
||||
|
||||
AddRefsVector(obj, "meshes", n.meshes, w.mAl);
|
||||
if (n.mesh) {
|
||||
obj.AddMember("mesh", n.mesh->index, w.mAl);
|
||||
}
|
||||
|
||||
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||
|
||||
|
@ -397,17 +439,24 @@ namespace glTF2 {
|
|||
|
||||
inline void Write(Value& obj, Sampler& b, AssetWriter& w)
|
||||
{
|
||||
if (b.wrapS) {
|
||||
obj.AddMember("wrapS", b.wrapS, w.mAl);
|
||||
if (!b.name.empty()) {
|
||||
obj.AddMember("name", b.name, w.mAl);
|
||||
}
|
||||
if (b.wrapT) {
|
||||
obj.AddMember("wrapT", b.wrapT, w.mAl);
|
||||
|
||||
if (b.wrapS != SamplerWrap::UNSET && b.wrapS != SamplerWrap::Repeat) {
|
||||
obj.AddMember("wrapS", static_cast<unsigned int>(b.wrapS), w.mAl);
|
||||
}
|
||||
if (b.magFilter) {
|
||||
obj.AddMember("magFilter", b.magFilter, w.mAl);
|
||||
|
||||
if (b.wrapT != SamplerWrap::UNSET && b.wrapT != SamplerWrap::Repeat) {
|
||||
obj.AddMember("wrapT", static_cast<unsigned int>(b.wrapT), w.mAl);
|
||||
}
|
||||
if (b.minFilter) {
|
||||
obj.AddMember("minFilter", b.minFilter, w.mAl);
|
||||
|
||||
if (b.magFilter != SamplerMagFilter::UNSET) {
|
||||
obj.AddMember("magFilter", static_cast<unsigned int>(b.magFilter), w.mAl);
|
||||
}
|
||||
|
||||
if (b.minFilter != SamplerMinFilter::UNSET) {
|
||||
obj.AddMember("minFilter", static_cast<unsigned int>(b.minFilter), w.mAl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,11 +493,6 @@ namespace glTF2 {
|
|||
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Technique& b, AssetWriter& w)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Texture& tex, AssetWriter& w)
|
||||
{
|
||||
if (tex.source) {
|
||||
|
@ -459,11 +503,6 @@ namespace glTF2 {
|
|||
}
|
||||
}
|
||||
|
||||
inline void Write(Value& obj, Light& b, AssetWriter& w)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline AssetWriter::AssetWriter(Asset& a)
|
||||
: mDoc()
|
||||
|
@ -523,88 +562,12 @@ namespace glTF2 {
|
|||
}
|
||||
}
|
||||
|
||||
inline void AssetWriter::WriteGLBFile(const char* path)
|
||||
{
|
||||
std::unique_ptr<IOStream> outfile(mAsset.OpenFile(path, "wb", true));
|
||||
|
||||
if (outfile == 0) {
|
||||
throw DeadlyExportError("Could not open output file: " + std::string(path));
|
||||
}
|
||||
|
||||
// we will write the header later, skip its size
|
||||
outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
|
||||
|
||||
StringBuffer docBuffer;
|
||||
Writer<StringBuffer> writer(docBuffer);
|
||||
mDoc.Accept(writer);
|
||||
|
||||
if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
|
||||
throw DeadlyExportError("Failed to write scene data!");
|
||||
}
|
||||
|
||||
WriteBinaryData(outfile.get(), docBuffer.GetSize());
|
||||
}
|
||||
|
||||
inline void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
|
||||
{
|
||||
//
|
||||
// write the body data
|
||||
//
|
||||
|
||||
size_t bodyLength = 0;
|
||||
if (Ref<Buffer> b = mAsset.GetBodyBuffer()) {
|
||||
bodyLength = b->byteLength;
|
||||
|
||||
if (bodyLength > 0) {
|
||||
size_t bodyOffset = sizeof(GLB_Header) + sceneLength;
|
||||
bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4
|
||||
|
||||
outfile->Seek(bodyOffset, aiOrigin_SET);
|
||||
|
||||
if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
|
||||
throw DeadlyExportError("Failed to write body data!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// write the header
|
||||
//
|
||||
|
||||
GLB_Header header;
|
||||
memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
|
||||
|
||||
header.version = 2;
|
||||
AI_SWAP4(header.version);
|
||||
|
||||
header.length = uint32_t(sizeof(header) + sceneLength + bodyLength);
|
||||
AI_SWAP4(header.length);
|
||||
|
||||
header.sceneLength = uint32_t(sceneLength);
|
||||
AI_SWAP4(header.sceneLength);
|
||||
|
||||
header.sceneFormat = SceneFormat_JSON;
|
||||
AI_SWAP4(header.sceneFormat);
|
||||
|
||||
outfile->Seek(0, aiOrigin_SET);
|
||||
|
||||
if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) {
|
||||
throw DeadlyExportError("Failed to write the header!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void AssetWriter::WriteMetadata()
|
||||
{
|
||||
Value asset;
|
||||
asset.SetObject();
|
||||
{
|
||||
char versionChar[10];
|
||||
ai_snprintf(versionChar, sizeof(versionChar), "%.1f", mAsset.asset.version);
|
||||
asset.AddMember("version", Value(versionChar, mAl).Move(), mAl);
|
||||
|
||||
asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
|
||||
}
|
||||
asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
|
||||
asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
|
||||
mDoc.AddMember("asset", asset, mAl);
|
||||
}
|
||||
|
||||
|
@ -613,11 +576,10 @@ namespace glTF2 {
|
|||
Value exts;
|
||||
exts.SetArray();
|
||||
{
|
||||
if (false)
|
||||
exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
|
||||
|
||||
// This is used to export common materials with GLTF 2.
|
||||
exts.PushBack(StringRef("KHR_materials_common"), mAl);
|
||||
// This is used to export pbrSpecularGlossiness materials with GLTF 2.
|
||||
if (this->mAsset.extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
|
||||
exts.PushBack(StringRef("KHR_materials_pbrSpecularGlossiness"), mAl);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exts.Empty())
|
||||
|
|
|
@ -62,11 +62,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "glTF2AssetWriter.h"
|
||||
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Header files, Open3DGC.
|
||||
# include <Open3DGC/o3dgcSC3DMCEncoder.h>
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
using namespace Assimp;
|
||||
|
@ -106,16 +101,8 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
|
|||
|
||||
mAsset.reset( new Asset( pIOSystem ) );
|
||||
|
||||
if (isBinary) {
|
||||
mAsset->SetAsBinary();
|
||||
}
|
||||
|
||||
ExportMetadata();
|
||||
|
||||
//for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
|
||||
|
||||
//for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
|
||||
|
||||
ExportMaterials();
|
||||
|
||||
if (mScene->mRootNode) {
|
||||
|
@ -124,19 +111,13 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
|
|||
|
||||
ExportMeshes();
|
||||
|
||||
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
||||
|
||||
ExportScene();
|
||||
|
||||
ExportAnimations();
|
||||
|
||||
AssetWriter writer(*mAsset);
|
||||
|
||||
if (isBinary) {
|
||||
writer.WriteGLBFile(filename);
|
||||
} else {
|
||||
writer.WriteFile(filename);
|
||||
}
|
||||
writer.WriteFile(filename);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -234,63 +215,86 @@ inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& bu
|
|||
return acc;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) {
|
||||
if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {}
|
||||
inline void SetSamplerWrap(SamplerWrap& wrap, aiTextureMapMode map)
|
||||
{
|
||||
switch (map) {
|
||||
case aiTextureMapMode_Clamp:
|
||||
wrap = SamplerWrap::Clamp_To_Edge;
|
||||
break;
|
||||
case aiTextureMapMode_Mirror:
|
||||
wrap = SamplerWrap::Mirrored_Repeat;
|
||||
break;
|
||||
case aiTextureMapMode_Wrap:
|
||||
case aiTextureMapMode_Decal:
|
||||
default:
|
||||
wrap = SamplerWrap::Repeat;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture, aiTextureType tt, unsigned int slot)
|
||||
{
|
||||
aiString aId;
|
||||
std::string id;
|
||||
if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) {
|
||||
id = aId.C_Str();
|
||||
}
|
||||
|
||||
if (Ref<Sampler> ref = mAsset->samplers.Get(id.c_str())) {
|
||||
texture->sampler = ref;
|
||||
} else {
|
||||
id = mAsset->FindUniqueID(id, "sampler");
|
||||
|
||||
texture->sampler = mAsset->samplers.Create(id.c_str());
|
||||
|
||||
aiTextureMapMode mapU, mapV;
|
||||
SamplerMagFilter filterMag;
|
||||
SamplerMinFilter filterMin;
|
||||
|
||||
if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) {
|
||||
SetSamplerWrap(texture->sampler->wrapS, mapU);
|
||||
}
|
||||
|
||||
if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) {
|
||||
SetSamplerWrap(texture->sampler->wrapT, mapV);
|
||||
}
|
||||
|
||||
if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) {
|
||||
texture->sampler->magFilter = filterMag;
|
||||
}
|
||||
|
||||
if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) {
|
||||
texture->sampler->minFilter = filterMin;
|
||||
}
|
||||
|
||||
aiString name;
|
||||
if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) {
|
||||
texture->sampler->name = name.C_Str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref<Texture> texture)
|
||||
void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot)
|
||||
{
|
||||
std::string samplerId = mAsset->FindUniqueID("", "sampler");
|
||||
texture->sampler = mAsset->samplers.Create(samplerId);
|
||||
std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
|
||||
|
||||
aiTextureMapMode mapU, mapV;
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0),(int*)&mapU);
|
||||
aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0),(int*)&mapV);
|
||||
|
||||
switch (mapU) {
|
||||
case aiTextureMapMode_Wrap:
|
||||
texture->sampler->wrapS = SamplerWrap_Repeat;
|
||||
break;
|
||||
case aiTextureMapMode_Clamp:
|
||||
texture->sampler->wrapS = SamplerWrap_Clamp_To_Edge;
|
||||
break;
|
||||
case aiTextureMapMode_Mirror:
|
||||
texture->sampler->wrapS = SamplerWrap_Mirrored_Repeat;
|
||||
break;
|
||||
case aiTextureMapMode_Decal:
|
||||
default:
|
||||
texture->sampler->wrapS = SamplerWrap_Repeat;
|
||||
break;
|
||||
};
|
||||
|
||||
switch (mapV) {
|
||||
case aiTextureMapMode_Wrap:
|
||||
texture->sampler->wrapT = SamplerWrap_Repeat;
|
||||
break;
|
||||
case aiTextureMapMode_Clamp:
|
||||
texture->sampler->wrapT = SamplerWrap_Clamp_To_Edge;
|
||||
break;
|
||||
case aiTextureMapMode_Mirror:
|
||||
texture->sampler->wrapT = SamplerWrap_Mirrored_Repeat;
|
||||
break;
|
||||
case aiTextureMapMode_Decal:
|
||||
default:
|
||||
texture->sampler->wrapT = SamplerWrap_Repeat;
|
||||
break;
|
||||
};
|
||||
|
||||
// Hard coded Texture filtering options because I do not know where to find them in the aiMaterial.
|
||||
texture->sampler->magFilter = SamplerMagFilter_Linear;
|
||||
texture->sampler->minFilter = SamplerMinFilter_Linear_Mipmap_Linear;
|
||||
mat->Get(textureKey.c_str(), tt, slot, prop);
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTextureType tt)
|
||||
void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot)
|
||||
{
|
||||
aiString tex;
|
||||
std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName;
|
||||
|
||||
mat->Get(textureKey.c_str(), tt, slot, prop);
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTextureType tt, unsigned int slot = 0)
|
||||
{
|
||||
|
||||
if (mat->GetTextureCount(tt) > 0) {
|
||||
if (mat->Get(AI_MATKEY_TEXTURE(tt, 0), tex) == AI_SUCCESS) {
|
||||
aiString tex;
|
||||
|
||||
if (mat->Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) {
|
||||
std::string path = tex.C_Str();
|
||||
|
||||
if (path.size() > 0) {
|
||||
|
@ -325,22 +329,63 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
|
|||
texture->source->uri = path;
|
||||
}
|
||||
|
||||
GetTexSampler(mat, texture);
|
||||
GetTexSampler(mat, texture, tt, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatColorOrTex(const aiMaterial* mat, TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
|
||||
{
|
||||
Ref<Texture>& texture = prop.texture;
|
||||
|
||||
GetMatTex(mat, texture, tt, slot);
|
||||
|
||||
if (texture) {
|
||||
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
|
||||
{
|
||||
Ref<Texture>& texture = prop.texture;
|
||||
|
||||
GetMatTex(mat, texture, tt, slot);
|
||||
|
||||
if (texture) {
|
||||
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
GetMatTexProp(mat, prop.scale, "scale", tt, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0)
|
||||
{
|
||||
Ref<Texture>& texture = prop.texture;
|
||||
|
||||
GetMatTex(mat, texture, tt, slot);
|
||||
|
||||
if (texture) {
|
||||
GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot);
|
||||
GetMatTexProp(mat, prop.strength, "strength", tt, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const char* propName, int type, int idx)
|
||||
{
|
||||
aiColor4D col;
|
||||
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
|
||||
prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
|
||||
prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a;
|
||||
}
|
||||
GetMatTex(mat, prop.texture, tt);
|
||||
}
|
||||
|
||||
void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec3& prop, const char* propName, int type, int idx)
|
||||
{
|
||||
aiColor3D col;
|
||||
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
|
||||
prop[0] = col.r; prop[1] = col.g; prop[2] = col.b;
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Exporter::ExportMaterials()
|
||||
{
|
||||
|
@ -348,6 +393,9 @@ void glTF2Exporter::ExportMaterials()
|
|||
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
||||
const aiMaterial* mat = mScene->mMaterials[i];
|
||||
|
||||
std::string id = "material_" + std::to_string(i);
|
||||
|
||||
Ref<Material> m = mAsset->materials.Create(id);
|
||||
|
||||
std::string name;
|
||||
if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) {
|
||||
|
@ -355,17 +403,70 @@ void glTF2Exporter::ExportMaterials()
|
|||
}
|
||||
name = mAsset->FindUniqueID(name, "material");
|
||||
|
||||
Ref<Material> m = mAsset->materials.Create(name);
|
||||
m->name = name;
|
||||
|
||||
GetMatColorOrTex(mat, m->ambient, AI_MATKEY_COLOR_AMBIENT, aiTextureType_AMBIENT);
|
||||
GetMatColorOrTex(mat, m->diffuse, AI_MATKEY_COLOR_DIFFUSE, aiTextureType_DIFFUSE);
|
||||
GetMatColorOrTex(mat, m->specular, AI_MATKEY_COLOR_SPECULAR, aiTextureType_SPECULAR);
|
||||
GetMatColorOrTex(mat, m->emission, AI_MATKEY_COLOR_EMISSIVE, aiTextureType_EMISSIVE);
|
||||
GetMatTex(mat, m->normal, aiTextureType_NORMALS);
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_DIFFUSE);
|
||||
GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
|
||||
GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
||||
m->transparent = mat->Get(AI_MATKEY_OPACITY, m->transparency) == aiReturn_SUCCESS && m->transparency != 1.0;
|
||||
if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) {
|
||||
//if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0
|
||||
m->pbrMetallicRoughness.metallicFactor = 0;
|
||||
}
|
||||
|
||||
GetMatScalar(mat, m->shininess, AI_MATKEY_SHININESS);
|
||||
mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor);
|
||||
|
||||
GetMatTex(mat, m->normalTexture, aiTextureType_NORMALS);
|
||||
GetMatTex(mat, m->occlusionTexture, aiTextureType_LIGHTMAP);
|
||||
GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE);
|
||||
GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE);
|
||||
|
||||
mat->Get(AI_MATKEY_TWOSIDED, m->doubleSided);
|
||||
mat->Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff);
|
||||
|
||||
bool foundAlphaMode = false;
|
||||
for (size_t i = 0; i < mat->mNumProperties; ++i) {
|
||||
aiMaterialProperty *prop = mat->mProperties[i];
|
||||
if (prop->mKey != aiString("$mat.gltf.alphaMode"))
|
||||
continue;
|
||||
|
||||
std::string alphaMode;
|
||||
for (size_t c = 0; c < prop->mDataLength; ++c)
|
||||
alphaMode += prop->mData[c];
|
||||
m->alphaMode = alphaMode;
|
||||
foundAlphaMode = true;
|
||||
}
|
||||
|
||||
if (!foundAlphaMode) {
|
||||
float opacity;
|
||||
|
||||
if (mat->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) {
|
||||
if (opacity < 1) {
|
||||
m->alphaMode = "MASK";
|
||||
m->pbrMetallicRoughness.baseColorFactor[3] *= opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hasPbrSpecularGlossiness = false;
|
||||
mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS, hasPbrSpecularGlossiness);
|
||||
|
||||
if (hasPbrSpecularGlossiness) {
|
||||
|
||||
if (!mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness) {
|
||||
mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true;
|
||||
}
|
||||
|
||||
PbrSpecularGlossiness pbrSG;
|
||||
|
||||
GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR);
|
||||
GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR);
|
||||
mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR, pbrSG.glossinessFactor);
|
||||
GetMatTex(mat, pbrSG.diffuseTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE);
|
||||
GetMatTex(mat, pbrSG.specularGlossinessTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE);
|
||||
|
||||
m->pbrSpecularGlossiness = Nullable<PbrSpecularGlossiness>(pbrSG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,16 +476,15 @@ void glTF2Exporter::ExportMaterials()
|
|||
*/
|
||||
bool FindMeshNode(Ref<Node>& nodeIn, Ref<Node>& meshNode, std::string meshID)
|
||||
{
|
||||
for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) {
|
||||
if (meshID.compare(nodeIn->meshes[i]->id) == 0) {
|
||||
meshNode = nodeIn;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nodeIn->mesh && meshID.compare(nodeIn->mesh->id) == 0) {
|
||||
meshNode = nodeIn;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < nodeIn->children.size(); ++i) {
|
||||
if(FindMeshNode(nodeIn->children[i], meshNode, meshID)) {
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,15 +602,6 @@ void glTF2Exporter::ExportMeshes()
|
|||
// because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
|
||||
typedef unsigned short IndicesType;
|
||||
|
||||
// Variables needed for compression. BEGIN.
|
||||
// Indices, not pointers - because pointer to buffer is changing while writing to it.
|
||||
size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer.
|
||||
size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals.
|
||||
std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
|
||||
size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer.
|
||||
bool comp_allow;// Point that data of current mesh can be compressed.
|
||||
// Variables needed for compression. END.
|
||||
|
||||
std::string fname = std::string(mFilename);
|
||||
std::string bufferIdPrefix = fname.substr(0, fname.rfind(".gltf"));
|
||||
std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str());
|
||||
|
@ -543,48 +634,22 @@ void glTF2Exporter::ExportMeshes()
|
|||
for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) {
|
||||
const aiMesh* aim = mScene->mMeshes[idx_mesh];
|
||||
|
||||
// Check if compressing requested and mesh can be encoded.
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
comp_allow = mProperties->GetPropertyBool("extensions.Open3DGC.use", false);
|
||||
#else
|
||||
comp_allow = false;
|
||||
#endif
|
||||
std::string name = aim->mName.C_Str();
|
||||
|
||||
if(comp_allow && (aim->mPrimitiveTypes == aiPrimitiveType_TRIANGLE) && (aim->mNumVertices > 0) && (aim->mNumFaces > 0))
|
||||
{
|
||||
idx_srcdata_tc.clear();
|
||||
idx_srcdata_tc.reserve(AI_MAX_NUMBER_OF_TEXTURECOORDS);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
if(aim->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
||||
msg = "all primitives of the mesh must be a triangles.";
|
||||
else
|
||||
msg = "mesh must has vertices and faces.";
|
||||
|
||||
DefaultLogger::get()->warn("GLTF: can not use Open3DGC-compression: " + msg);
|
||||
comp_allow = false;
|
||||
}
|
||||
|
||||
std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
|
||||
std::string meshId = mAsset->FindUniqueID(name, "mesh");
|
||||
Ref<Mesh> m = mAsset->meshes.Create(meshId);
|
||||
m->primitives.resize(1);
|
||||
Mesh::Primitive& p = m->primitives.back();
|
||||
|
||||
m->name = name;
|
||||
|
||||
p.material = mAsset->materials.Get(aim->mMaterialIndex);
|
||||
|
||||
/******************* Vertices ********************/
|
||||
// If compression is used then you need parameters of uncompressed region: begin and size. At this step "begin" is stored.
|
||||
if(comp_allow) idx_srcdata_begin = b->byteLength;
|
||||
|
||||
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||
if (v) p.attributes.position.push_back(v);
|
||||
|
||||
/******************** Normals ********************/
|
||||
if(comp_allow && (aim->mNormals != 0)) idx_srcdata_normal = b->byteLength;// Store index of normals array.
|
||||
|
||||
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||
if (n) p.attributes.normal.push_back(n);
|
||||
|
||||
|
@ -600,16 +665,12 @@ void glTF2Exporter::ExportMeshes()
|
|||
if (aim->mNumUVComponents[i] > 0) {
|
||||
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
|
||||
|
||||
if(comp_allow) idx_srcdata_tc.push_back(b->byteLength);// Store index of texture coordinates array.
|
||||
|
||||
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, false);
|
||||
if (tc) p.attributes.texcoord.push_back(tc);
|
||||
}
|
||||
}
|
||||
|
||||
/*************** Vertices indices ****************/
|
||||
idx_srcdata_ind = b->byteLength;// Store index of indices array.
|
||||
|
||||
if (aim->mNumFaces > 0) {
|
||||
std::vector<IndicesType> indices;
|
||||
unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
|
||||
|
@ -634,104 +695,12 @@ void glTF2Exporter::ExportMeshes()
|
|||
p.mode = PrimitiveMode_TRIANGLES;
|
||||
}
|
||||
|
||||
/*************** Skins ****************/
|
||||
if(aim->HasBones()) {
|
||||
ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
|
||||
/*************** Skins ****************/
|
||||
if(aim->HasBones()) {
|
||||
ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData);
|
||||
}
|
||||
}
|
||||
|
||||
/****************** Compression ******************/
|
||||
///TODO: animation: weights, joints.
|
||||
if(comp_allow)
|
||||
{
|
||||
#ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC
|
||||
// Only one type of compression supported at now - Open3DGC.
|
||||
//
|
||||
o3dgc::BinaryStream bs;
|
||||
o3dgc::SC3DMCEncoder<IndicesType> encoder;
|
||||
o3dgc::IndexedFaceSet<IndicesType> comp_o3dgc_ifs;
|
||||
o3dgc::SC3DMCEncodeParams comp_o3dgc_params;
|
||||
|
||||
//
|
||||
// Fill data for encoder.
|
||||
//
|
||||
// Quantization
|
||||
unsigned quant_coord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.POSITION", 12);
|
||||
unsigned quant_normal = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.NORMAL", 10);
|
||||
unsigned quant_texcoord = mProperties->GetPropertyInteger("extensions.Open3DGC.quantization.TEXCOORD", 10);
|
||||
|
||||
// Prediction
|
||||
o3dgc::O3DGCSC3DMCPredictionMode prediction_position = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
|
||||
o3dgc::O3DGCSC3DMCPredictionMode prediction_normal = o3dgc::O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;
|
||||
o3dgc::O3DGCSC3DMCPredictionMode prediction_texcoord = o3dgc::O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
|
||||
|
||||
// IndexedFacesSet: "Crease angle", "solid", "convex" are set to default.
|
||||
comp_o3dgc_ifs.SetCCW(true);
|
||||
comp_o3dgc_ifs.SetIsTriangularMesh(true);
|
||||
comp_o3dgc_ifs.SetNumFloatAttributes(0);
|
||||
// Coordinates
|
||||
comp_o3dgc_params.SetCoordQuantBits(quant_coord);
|
||||
comp_o3dgc_params.SetCoordPredMode(prediction_position);
|
||||
comp_o3dgc_ifs.SetNCoord(aim->mNumVertices);
|
||||
comp_o3dgc_ifs.SetCoord((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_begin]);
|
||||
// Normals
|
||||
if(idx_srcdata_normal != SIZE_MAX)
|
||||
{
|
||||
comp_o3dgc_params.SetNormalQuantBits(quant_normal);
|
||||
comp_o3dgc_params.SetNormalPredMode(prediction_normal);
|
||||
comp_o3dgc_ifs.SetNNormal(aim->mNumVertices);
|
||||
comp_o3dgc_ifs.SetNormal((o3dgc::Real* const)&b->GetPointer()[idx_srcdata_normal]);
|
||||
}
|
||||
|
||||
// Texture coordinates
|
||||
for(size_t num_tc = 0; num_tc < idx_srcdata_tc.size(); num_tc++)
|
||||
{
|
||||
size_t num = comp_o3dgc_ifs.GetNumFloatAttributes();
|
||||
|
||||
comp_o3dgc_params.SetFloatAttributeQuantBits(static_cast<unsigned long>(num), quant_texcoord);
|
||||
comp_o3dgc_params.SetFloatAttributePredMode(static_cast<unsigned long>(num), prediction_texcoord);
|
||||
comp_o3dgc_ifs.SetNFloatAttribute(static_cast<unsigned long>(num), aim->mNumVertices);// number of elements.
|
||||
comp_o3dgc_ifs.SetFloatAttributeDim(static_cast<unsigned long>(num), aim->mNumUVComponents[num_tc]);// components per element: aiVector3D => x * float
|
||||
comp_o3dgc_ifs.SetFloatAttributeType(static_cast<unsigned long>(num), o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD);
|
||||
comp_o3dgc_ifs.SetFloatAttribute(static_cast<unsigned long>(num), (o3dgc::Real* const)&b->GetPointer()[idx_srcdata_tc[num_tc]]);
|
||||
comp_o3dgc_ifs.SetNumFloatAttributes(static_cast<unsigned long>(num + 1));
|
||||
}
|
||||
|
||||
// Coordinates indices
|
||||
comp_o3dgc_ifs.SetNCoordIndex(aim->mNumFaces);
|
||||
comp_o3dgc_ifs.SetCoordIndex((IndicesType* const)&b->GetPointer()[idx_srcdata_ind]);
|
||||
// Prepare to enconding
|
||||
comp_o3dgc_params.SetNumFloatAttributes(comp_o3dgc_ifs.GetNumFloatAttributes());
|
||||
if(mProperties->GetPropertyBool("extensions.Open3DGC.binary", true))
|
||||
comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_BINARY);
|
||||
else
|
||||
comp_o3dgc_params.SetStreamType(o3dgc::O3DGC_STREAM_TYPE_ASCII);
|
||||
|
||||
comp_o3dgc_ifs.ComputeMinMax(o3dgc::O3DGC_SC3DMC_MAX_ALL_DIMS);
|
||||
//
|
||||
// Encoding
|
||||
//
|
||||
encoder.Encode(comp_o3dgc_params, comp_o3dgc_ifs, bs);
|
||||
// Replace data in buffer.
|
||||
b->ReplaceData(idx_srcdata_begin, b->byteLength - idx_srcdata_begin, bs.GetBuffer(), bs.GetSize());
|
||||
//
|
||||
// Add information about extension to mesh.
|
||||
//
|
||||
// Create extension structure.
|
||||
Mesh::SCompression_Open3DGC* ext = new Mesh::SCompression_Open3DGC;
|
||||
|
||||
// Fill it.
|
||||
ext->Buffer = b->id;
|
||||
ext->Offset = idx_srcdata_begin;
|
||||
ext->Count = b->byteLength - idx_srcdata_begin;
|
||||
ext->Binary = mProperties->GetPropertyBool("extensions.Open3DGC.binary");
|
||||
ext->IndicesCount = comp_o3dgc_ifs.GetNCoordIndex() * 3;
|
||||
ext->VerticesCount = comp_o3dgc_ifs.GetNCoord();
|
||||
// And assign to mesh.
|
||||
m->Extension.push_back(ext);
|
||||
#endif
|
||||
}// if(comp_allow)
|
||||
}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i)
|
||||
|
||||
//----------------------------------------
|
||||
// Finish the skin
|
||||
// Create the Accessor for skinRef->inverseBindMatrices
|
||||
|
@ -786,8 +755,8 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n)
|
|||
CopyValue(n->mTransformation, node->matrix.value);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
if (n->mNumMeshes > 0) {
|
||||
node->mesh = mAsset->meshes.Get(n->mMeshes[0]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||
|
@ -815,8 +784,8 @@ unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref<Node>& parent)
|
|||
CopyValue(n->mTransformation, node->matrix.value);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||
if (n->mNumMeshes > 0) {
|
||||
node->mesh = mAsset->meshes.Get(n->mMeshes[0]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||
|
@ -845,7 +814,7 @@ void glTF2Exporter::ExportScene()
|
|||
void glTF2Exporter::ExportMetadata()
|
||||
{
|
||||
AssetMetadata& asset = mAsset->asset;
|
||||
asset.version = 2;
|
||||
asset.version = "2.0";
|
||||
|
||||
char buffer[256];
|
||||
ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)",
|
||||
|
@ -963,7 +932,7 @@ void glTF2Exporter::ExportAnimations()
|
|||
name = mAsset->FindUniqueID(name, "animation");
|
||||
Ref<Animation> animRef = mAsset->animations.Create(name);
|
||||
|
||||
/******************* Parameters ********************/
|
||||
// Parameters
|
||||
ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel, anim->mTicksPerSecond);
|
||||
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
|
|
|
@ -66,8 +66,15 @@ namespace glTF2
|
|||
|
||||
class Asset;
|
||||
struct TexProperty;
|
||||
struct TextureInfo;
|
||||
struct NormalTextureInfo;
|
||||
struct OcclusionTextureInfo;
|
||||
struct Node;
|
||||
struct Texture;
|
||||
|
||||
// Vec/matrix types, as raw float arrays
|
||||
typedef float (vec3)[3];
|
||||
typedef float (vec4)[4];
|
||||
}
|
||||
|
||||
namespace Assimp
|
||||
|
@ -101,9 +108,15 @@ namespace Assimp
|
|||
|
||||
void WriteBinaryData(IOStream* outfile, std::size_t sceneLength);
|
||||
|
||||
void GetTexSampler(const aiMaterial* mat, glTF2::Ref<glTF2::Texture> texture);
|
||||
void GetMatTex(const aiMaterial* mat, glTF2::Ref<glTF2::Texture>& texture, aiTextureType tt);
|
||||
void GetMatColorOrTex(const aiMaterial* mat, glTF2::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt);
|
||||
void GetTexSampler(const aiMaterial* mat, glTF2::Ref<glTF2::Texture> texture, aiTextureType tt, unsigned int slot);
|
||||
void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx);
|
||||
void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx);
|
||||
void GetMatTex(const aiMaterial* mat, glTF2::Ref<glTF2::Texture>& texture, aiTextureType tt, unsigned int slot);
|
||||
void GetMatTex(const aiMaterial* mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot);
|
||||
void GetMatTex(const aiMaterial* mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot);
|
||||
void GetMatTex(const aiMaterial* mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot);
|
||||
void GetMatColor(const aiMaterial* mat, glTF2::vec4& prop, const char* propName, int type, int idx);
|
||||
void GetMatColor(const aiMaterial* mat, glTF2::vec3& prop, const char* propName, int type, int idx);
|
||||
void ExportMetadata();
|
||||
void ExportMaterials();
|
||||
void ExportMeshes();
|
||||
|
|
|
@ -0,0 +1,645 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2017, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
|
||||
#include "glTF2Importer.h"
|
||||
#include "StringComparison.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/importerdesc.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "MakeVerboseFormat.h"
|
||||
|
||||
#include "glTF2Asset.h"
|
||||
// This is included here so WriteLazyDict<T>'s definition is found.
|
||||
#include "glTF2AssetWriter.h"
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/rapidjson.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace glTF2;
|
||||
|
||||
|
||||
//
|
||||
// glTF2Importer
|
||||
//
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
"glTF2 Importer",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"gltf glb"
|
||||
};
|
||||
|
||||
glTF2Importer::glTF2Importer()
|
||||
: BaseImporter()
|
||||
, meshOffsets()
|
||||
, embeddedTexIdxs()
|
||||
, mScene( NULL ) {
|
||||
// empty
|
||||
}
|
||||
|
||||
glTF2Importer::~glTF2Importer() {
|
||||
// empty
|
||||
}
|
||||
|
||||
const aiImporterDesc* glTF2Importer::GetInfo() const
|
||||
{
|
||||
return &desc;
|
||||
}
|
||||
|
||||
bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
|
||||
if (extension != "gltf") // We currently can't read glTF2 binary files (.glb), yet
|
||||
return false;
|
||||
|
||||
if (checkSig && pIOHandler) {
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
try {
|
||||
asset.Load(pFile);
|
||||
std::string version = asset.asset.version;
|
||||
return !version.empty() && version[0] == '2';
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
|
||||
//{
|
||||
// out.r = v[0]; out.g = v[1]; out.b = v[2];
|
||||
//}
|
||||
|
||||
static void CopyValue(const glTF2::vec4& v, aiColor4D& out)
|
||||
{
|
||||
out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
|
||||
}
|
||||
|
||||
/*static void CopyValue(const glTF2::vec4& v, aiColor3D& out)
|
||||
{
|
||||
out.r = v[0]; out.g = v[1]; out.b = v[2];
|
||||
}*/
|
||||
|
||||
static void CopyValue(const glTF2::vec3& v, aiColor4D& out)
|
||||
{
|
||||
out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = 1.0;
|
||||
}
|
||||
|
||||
static void CopyValue(const glTF2::vec3& v, aiVector3D& out)
|
||||
{
|
||||
out.x = v[0]; out.y = v[1]; out.z = v[2];
|
||||
}
|
||||
|
||||
static void CopyValue(const glTF2::vec4& v, aiQuaternion& out)
|
||||
{
|
||||
out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
|
||||
}
|
||||
|
||||
static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o)
|
||||
{
|
||||
o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
|
||||
o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
|
||||
o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
|
||||
o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
|
||||
}
|
||||
|
||||
inline void SetMaterialColorProperty(Asset& r, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
|
||||
{
|
||||
aiColor4D col;
|
||||
CopyValue(prop, col);
|
||||
mat->AddProperty(&col, 1, pKey, type, idx);
|
||||
}
|
||||
|
||||
inline void SetMaterialColorProperty(Asset& r, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx)
|
||||
{
|
||||
aiColor4D col;
|
||||
CopyValue(prop, col);
|
||||
mat->AddProperty(&col, 1, pKey, type, idx);
|
||||
}
|
||||
|
||||
inline void SetMaterialTextureProperty(std::vector<int>& embeddedTexIdxs, Asset& r, glTF2::TextureInfo prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0)
|
||||
{
|
||||
if (prop.texture && prop.texture->source) {
|
||||
aiString uri(prop.texture->source->uri);
|
||||
|
||||
int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
|
||||
if (texIdx != -1) { // embedded
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
uri.data[0] = '*';
|
||||
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
||||
}
|
||||
|
||||
mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot));
|
||||
mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot);
|
||||
|
||||
if (prop.texture->sampler) {
|
||||
Ref<Sampler> sampler = prop.texture->sampler;
|
||||
|
||||
aiString name(sampler->name);
|
||||
aiString id(sampler->id);
|
||||
|
||||
mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot));
|
||||
mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot));
|
||||
|
||||
mat->AddProperty(&sampler->wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
|
||||
mat->AddProperty(&sampler->wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
|
||||
|
||||
if (sampler->magFilter != SamplerMagFilter::UNSET) {
|
||||
mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot));
|
||||
}
|
||||
|
||||
if (sampler->minFilter != SamplerMinFilter::UNSET) {
|
||||
mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportMaterials(glTF2::Asset& r)
|
||||
{
|
||||
mScene->mNumMaterials = unsigned(r.materials.Size());
|
||||
mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
|
||||
|
||||
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
||||
aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
|
||||
|
||||
Material& mat = r.materials[i];
|
||||
|
||||
if (!mat.name.empty()) {
|
||||
aiString str(mat.name);
|
||||
|
||||
aimat->AddProperty(&str, AI_MATKEY_NAME);
|
||||
}
|
||||
|
||||
SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE);
|
||||
aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR);
|
||||
aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR);
|
||||
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE);
|
||||
SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE);
|
||||
|
||||
aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED);
|
||||
aimat->AddProperty(&mat.alphaMode, 1, AI_MATKEY_GLTF_ALPHAMODE);
|
||||
aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
|
||||
|
||||
//pbrSpecularGlossiness
|
||||
if (mat.pbrSpecularGlossiness.isPresent) {
|
||||
PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
|
||||
|
||||
aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS);
|
||||
SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR);
|
||||
SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR);
|
||||
aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE);
|
||||
SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void SetFace(aiFace& face, int a)
|
||||
{
|
||||
face.mNumIndices = 1;
|
||||
face.mIndices = new unsigned int[1];
|
||||
face.mIndices[0] = a;
|
||||
}
|
||||
|
||||
static inline void SetFace(aiFace& face, int a, int b)
|
||||
{
|
||||
face.mNumIndices = 2;
|
||||
face.mIndices = new unsigned int[2];
|
||||
face.mIndices[0] = a;
|
||||
face.mIndices[1] = b;
|
||||
}
|
||||
|
||||
static inline void SetFace(aiFace& face, int a, int b, int c)
|
||||
{
|
||||
face.mNumIndices = 3;
|
||||
face.mIndices = new unsigned int[3];
|
||||
face.mIndices[0] = a;
|
||||
face.mIndices[1] = b;
|
||||
face.mIndices[2] = c;
|
||||
}
|
||||
|
||||
static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts)
|
||||
{
|
||||
for (unsigned i = 0; i < nFaces; ++i) {
|
||||
for (unsigned j = 0; j < faces[i].mNumIndices; ++j) {
|
||||
unsigned idx = faces[i].mIndices[j];
|
||||
if (idx >= nVerts)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportMeshes(glTF2::Asset& r)
|
||||
{
|
||||
std::vector<aiMesh*> meshes;
|
||||
|
||||
unsigned int k = 0;
|
||||
|
||||
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||
Mesh& mesh = r.meshes[m];
|
||||
|
||||
meshOffsets.push_back(k);
|
||||
k += unsigned(mesh.primitives.size());
|
||||
|
||||
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
|
||||
Mesh::Primitive& prim = mesh.primitives[p];
|
||||
|
||||
aiMesh* aim = new aiMesh();
|
||||
meshes.push_back(aim);
|
||||
|
||||
aim->mName = mesh.name.empty() ? mesh.id : mesh.name;
|
||||
|
||||
if (mesh.primitives.size() > 1) {
|
||||
size_t& len = aim->mName.length;
|
||||
aim->mName.data[len] = '-';
|
||||
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p);
|
||||
}
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||
break;
|
||||
|
||||
case PrimitiveMode_LINES:
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
break;
|
||||
|
||||
case PrimitiveMode_TRIANGLES:
|
||||
case PrimitiveMode_TRIANGLE_STRIP:
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Mesh::Primitive::Attributes& attr = prim.attributes;
|
||||
|
||||
if (attr.position.size() > 0 && attr.position[0]) {
|
||||
aim->mNumVertices = attr.position[0]->count;
|
||||
attr.position[0]->ExtractData(aim->mVertices);
|
||||
}
|
||||
|
||||
if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals);
|
||||
|
||||
for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
|
||||
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
||||
aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
|
||||
|
||||
aiVector3D* values = aim->mTextureCoords[tc];
|
||||
for (unsigned int i = 0; i < aim->mNumVertices; ++i) {
|
||||
values[i].y = 1 - values[i].y; // Flip Y coords
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (prim.indices) {
|
||||
aiFace* faces = 0;
|
||||
unsigned int nFaces = 0;
|
||||
|
||||
unsigned int count = prim.indices->count;
|
||||
|
||||
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||
ai_assert(data.IsValid());
|
||||
|
||||
switch (prim.mode) {
|
||||
case PrimitiveMode_POINTS: {
|
||||
nFaces = count;
|
||||
faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
SetFace(faces[i], data.GetUInt(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINES: {
|
||||
nFaces = count / 2;
|
||||
faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 2) {
|
||||
SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_LINE_LOOP:
|
||||
case PrimitiveMode_LINE_STRIP: {
|
||||
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||
faces = new aiFace[nFaces];
|
||||
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
|
||||
for (unsigned int i = 2; i < count; ++i) {
|
||||
SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
|
||||
}
|
||||
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||
SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PrimitiveMode_TRIANGLES: {
|
||||
nFaces = count / 3;
|
||||
faces = new aiFace[nFaces];
|
||||
for (unsigned int i = 0; i < count; i += 3) {
|
||||
SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||
nFaces = count - 2;
|
||||
faces = new aiFace[nFaces];
|
||||
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
for (unsigned int i = 3; i < count; ++i) {
|
||||
SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PrimitiveMode_TRIANGLE_FAN:
|
||||
nFaces = count - 2;
|
||||
faces = new aiFace[nFaces];
|
||||
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||
for (unsigned int i = 3; i < count; ++i) {
|
||||
SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (faces) {
|
||||
aim->mFaces = faces;
|
||||
aim->mNumFaces = nFaces;
|
||||
ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (prim.material) {
|
||||
aim->mMaterialIndex = prim.material.GetIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
meshOffsets.push_back(k);
|
||||
|
||||
CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportCameras(glTF2::Asset& r)
|
||||
{
|
||||
if (!r.cameras.Size()) return;
|
||||
|
||||
mScene->mNumCameras = r.cameras.Size();
|
||||
mScene->mCameras = new aiCamera*[r.cameras.Size()];
|
||||
|
||||
for (size_t i = 0; i < r.cameras.Size(); ++i) {
|
||||
Camera& cam = r.cameras[i];
|
||||
|
||||
aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
|
||||
|
||||
if (cam.type == Camera::Perspective) {
|
||||
|
||||
aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
|
||||
aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * aicam->mAspect;
|
||||
aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
|
||||
aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear;
|
||||
}
|
||||
else {
|
||||
// assimp does not support orthographic cameras
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector<unsigned int>& meshOffsets, glTF2::Ref<glTF2::Node>& ptr)
|
||||
{
|
||||
Node& node = *ptr;
|
||||
|
||||
aiNode* ainode = new aiNode(node.id);
|
||||
|
||||
if (!node.children.empty()) {
|
||||
ainode->mNumChildren = unsigned(node.children.size());
|
||||
ainode->mChildren = new aiNode*[ainode->mNumChildren];
|
||||
|
||||
for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
|
||||
aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
|
||||
child->mParent = ainode;
|
||||
ainode->mChildren[i] = child;
|
||||
}
|
||||
}
|
||||
|
||||
aiMatrix4x4& matrix = ainode->mTransformation;
|
||||
if (node.matrix.isPresent) {
|
||||
CopyValue(node.matrix.value, matrix);
|
||||
}
|
||||
else {
|
||||
if (node.translation.isPresent) {
|
||||
aiVector3D trans;
|
||||
CopyValue(node.translation.value, trans);
|
||||
aiMatrix4x4 t;
|
||||
aiMatrix4x4::Translation(trans, t);
|
||||
matrix = t * matrix;
|
||||
}
|
||||
|
||||
if (node.scale.isPresent) {
|
||||
aiVector3D scal(1.f);
|
||||
CopyValue(node.scale.value, scal);
|
||||
aiMatrix4x4 s;
|
||||
aiMatrix4x4::Scaling(scal, s);
|
||||
matrix = s * matrix;
|
||||
}
|
||||
|
||||
|
||||
if (node.rotation.isPresent) {
|
||||
aiQuaternion rot;
|
||||
CopyValue(node.rotation.value, rot);
|
||||
matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.mesh) {
|
||||
ainode->mNumMeshes = 1;
|
||||
ainode->mMeshes = new unsigned int[1];
|
||||
|
||||
int k = 0;
|
||||
int idx = node.mesh.GetIndex();
|
||||
|
||||
for (unsigned int j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
|
||||
ainode->mMeshes[k] = j;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.camera) {
|
||||
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
||||
}
|
||||
|
||||
return ainode;
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportNodes(glTF2::Asset& r)
|
||||
{
|
||||
if (!r.scene) return;
|
||||
|
||||
std::vector< Ref<Node> > rootNodes = r.scene->nodes;
|
||||
|
||||
// The root nodes
|
||||
unsigned int numRootNodes = unsigned(rootNodes.size());
|
||||
if (numRootNodes == 1) { // a single root node: use it
|
||||
mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
|
||||
}
|
||||
else if (numRootNodes > 1) { // more than one root node: create a fake root
|
||||
aiNode* root = new aiNode("ROOT");
|
||||
root->mChildren = new aiNode*[numRootNodes];
|
||||
for (unsigned int i = 0; i < numRootNodes; ++i) {
|
||||
aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
|
||||
node->mParent = root;
|
||||
root->mChildren[root->mNumChildren++] = node;
|
||||
}
|
||||
mScene->mRootNode = root;
|
||||
}
|
||||
|
||||
//if (!mScene->mRootNode) {
|
||||
// mScene->mRootNode = new aiNode("EMPTY");
|
||||
//}
|
||||
}
|
||||
|
||||
void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r)
|
||||
{
|
||||
embeddedTexIdxs.resize(r.images.Size(), -1);
|
||||
|
||||
int numEmbeddedTexs = 0;
|
||||
for (size_t i = 0; i < r.images.Size(); ++i) {
|
||||
if (r.images[i].HasData())
|
||||
numEmbeddedTexs += 1;
|
||||
}
|
||||
|
||||
if (numEmbeddedTexs == 0)
|
||||
return;
|
||||
|
||||
mScene->mTextures = new aiTexture*[numEmbeddedTexs];
|
||||
|
||||
// Add the embedded textures
|
||||
for (size_t i = 0; i < r.images.Size(); ++i) {
|
||||
Image img = r.images[i];
|
||||
if (!img.HasData()) continue;
|
||||
|
||||
int idx = mScene->mNumTextures++;
|
||||
embeddedTexIdxs[i] = idx;
|
||||
|
||||
aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
|
||||
|
||||
size_t length = img.GetDataLength();
|
||||
void* data = img.StealData();
|
||||
|
||||
tex->mWidth = static_cast<unsigned int>(length);
|
||||
tex->mHeight = 0;
|
||||
tex->pcData = reinterpret_cast<aiTexel*>(data);
|
||||
|
||||
if (!img.mimeType.empty()) {
|
||||
const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
|
||||
if (ext) {
|
||||
if (strcmp(ext, "jpeg") == 0) ext = "jpg";
|
||||
|
||||
size_t len = strlen(ext);
|
||||
if (len <= 3) {
|
||||
strcpy(tex->achFormatHint, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
||||
|
||||
this->mScene = pScene;
|
||||
|
||||
// read the asset file
|
||||
glTF2::Asset asset(pIOHandler);
|
||||
asset.Load(pFile);
|
||||
|
||||
//
|
||||
// Copy the data out
|
||||
//
|
||||
|
||||
ImportEmbeddedTextures(asset);
|
||||
ImportMaterials(asset);
|
||||
|
||||
ImportMeshes(asset);
|
||||
|
||||
ImportCameras(asset);
|
||||
|
||||
ImportNodes(asset);
|
||||
|
||||
// TODO: it does not split the loaded vertices, should it?
|
||||
//pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
||||
MakeVerboseFormatProcess process;
|
||||
process.Execute(pScene);
|
||||
|
||||
|
||||
if (pScene->mNumMeshes == 0) {
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2017, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef AI_GLTF2IMPORTER_H_INC
|
||||
#define AI_GLTF2IMPORTER_H_INC
|
||||
|
||||
#include "BaseImporter.h"
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
|
||||
struct aiNode;
|
||||
|
||||
|
||||
namespace glTF2
|
||||
{
|
||||
class Asset;
|
||||
}
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/**
|
||||
* Load the glTF2 format.
|
||||
* https://github.com/KhronosGroup/glTF/tree/master/specification
|
||||
*/
|
||||
class glTF2Importer : public BaseImporter{
|
||||
public:
|
||||
glTF2Importer();
|
||||
virtual ~glTF2Importer();
|
||||
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const;
|
||||
|
||||
protected:
|
||||
virtual const aiImporterDesc* GetInfo() const;
|
||||
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler );
|
||||
|
||||
private:
|
||||
|
||||
std::vector<unsigned int> meshOffsets;
|
||||
|
||||
std::vector<int> embeddedTexIdxs;
|
||||
|
||||
aiScene* mScene;
|
||||
|
||||
void ImportEmbeddedTextures(glTF2::Asset& a);
|
||||
void ImportMaterials(glTF2::Asset& a);
|
||||
void ImportMeshes(glTF2::Asset& a);
|
||||
void ImportCameras(glTF2::Asset& a);
|
||||
void ImportLights(glTF2::Asset& a);
|
||||
void ImportNodes(glTF2::Asset& a);
|
||||
|
||||
};
|
||||
|
||||
} // Namespace assimp
|
||||
|
||||
#endif // AI_GLTF2IMPORTER_H_INC
|
||||
|
|
@ -1058,13 +1058,13 @@ namespace glTF
|
|||
std::string version; //!< Specifies the target rendering API (default: "1.0.3")
|
||||
} profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
|
||||
|
||||
float version; //!< The glTF format version (should be 1.0)
|
||||
std::string version; //!< The glTF format version (should be 1.0)
|
||||
|
||||
void Read(Document& doc);
|
||||
|
||||
AssetMetadata()
|
||||
: premultipliedAlpha(false)
|
||||
, version(0)
|
||||
, version("")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -40,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include <iomanip>
|
||||
|
||||
// Header files, Assimp
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
@ -128,6 +129,12 @@ namespace {
|
|||
return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0;
|
||||
}
|
||||
|
||||
inline Value* FindNumber(Value& val, const char* id)
|
||||
{
|
||||
Value::MemberIterator it = val.FindMember(id);
|
||||
return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0;
|
||||
}
|
||||
|
||||
inline Value* FindArray(Value& val, const char* id)
|
||||
{
|
||||
Value::MemberIterator it = val.FindMember(id);
|
||||
|
@ -309,7 +316,9 @@ inline void Buffer::Read(Value& obj, Asset& r)
|
|||
}
|
||||
else { // Local file
|
||||
if (byteLength > 0) {
|
||||
IOStream* file = r.OpenFile(uri, "rb");
|
||||
std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : "";
|
||||
|
||||
IOStream* file = r.OpenFile(dir + uri, "rb");
|
||||
if (file) {
|
||||
bool ok = LoadFromStream(*file, byteLength);
|
||||
delete file;
|
||||
|
@ -1228,13 +1237,21 @@ inline void Scene::Read(Value& obj, Asset& r)
|
|||
inline void AssetMetadata::Read(Document& doc)
|
||||
{
|
||||
// read the version, etc.
|
||||
float statedVersion = 0;
|
||||
if (Value* obj = FindObject(doc, "asset")) {
|
||||
ReadMember(*obj, "copyright", copyright);
|
||||
ReadMember(*obj, "generator", generator);
|
||||
|
||||
premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false);
|
||||
statedVersion = MemberOrDefault(*obj, "version", 0);
|
||||
|
||||
if (Value* versionString = FindString(*obj, "version")) {
|
||||
version = versionString->GetString();
|
||||
} else if (Value* versionNumber = FindNumber (*obj, "version")) {
|
||||
char buf[4];
|
||||
|
||||
ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble());
|
||||
|
||||
version = buf;
|
||||
}
|
||||
|
||||
if (Value* profile = FindObject(*obj, "profile")) {
|
||||
ReadMember(*profile, "api", this->profile.api);
|
||||
|
@ -1242,16 +1259,8 @@ inline void AssetMetadata::Read(Document& doc)
|
|||
}
|
||||
}
|
||||
|
||||
version = std::max(statedVersion, version);
|
||||
if (version == 0) {
|
||||
// if missing version, we'll assume version 1...
|
||||
version = 1;
|
||||
}
|
||||
|
||||
if (version != 1) {
|
||||
char msg[128];
|
||||
ai_snprintf(msg, 128, "GLTF: Unsupported glTF version: %.0f", version);
|
||||
throw DeadlyImportError(msg);
|
||||
if (version.empty() || version[0] != '1') {
|
||||
throw DeadlyImportError("GLTF: Unsupported glTF version: " + version);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1273,7 +1282,7 @@ inline void Asset::ReadBinaryHeader(IOStream& stream)
|
|||
}
|
||||
|
||||
AI_SWAP4(header.version);
|
||||
asset.version = header.version;
|
||||
asset.version = std::to_string(header.version);
|
||||
if (header.version != 1) {
|
||||
throw DeadlyImportError("GLTF: Unsupported binary glTF version");
|
||||
}
|
||||
|
|
|
@ -606,13 +606,8 @@ namespace glTF {
|
|||
{
|
||||
Value asset;
|
||||
asset.SetObject();
|
||||
{
|
||||
char versionChar[10];
|
||||
ai_snprintf(versionChar, sizeof(versionChar), "%.0f", mAsset.asset.version);
|
||||
asset.AddMember("version", Value(versionChar, mAl).Move(), mAl);
|
||||
|
||||
asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
|
||||
}
|
||||
asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl);
|
||||
asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
|
||||
mDoc.AddMember("asset", asset, mAl);
|
||||
}
|
||||
|
||||
|
|
|
@ -100,24 +100,19 @@ const aiImporterDesc* glTFImporter::GetInfo() const
|
|||
|
||||
bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
|
||||
if (extension == "gltf" || extension == "glb")
|
||||
return true;
|
||||
if (extension != "gltf" && extension != "glb")
|
||||
return false;
|
||||
|
||||
if ((checkSig || !extension.length()) && pIOHandler) {
|
||||
char buffer[4];
|
||||
|
||||
std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
|
||||
if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) {
|
||||
if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) {
|
||||
return true; // Has GLB header
|
||||
}
|
||||
else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0
|
||||
|| memcmp(buffer, "{\n ", sizeof(buffer)) == 0) {
|
||||
// seems a JSON file, and we're the only format that can read them
|
||||
return true;
|
||||
}
|
||||
if (checkSig && pIOHandler) {
|
||||
glTF::Asset asset(pIOHandler);
|
||||
try {
|
||||
asset.Load(pFile, extension == "glb");
|
||||
std::string version = asset.asset.version;
|
||||
return !version.empty() && version[0] == '1';
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ SET( TEST_SRCS
|
|||
unit/ut3DSImportExport.cpp
|
||||
unit/utACImportExport.cpp
|
||||
unit/utAMFImportExport.cpp
|
||||
unit/utASEImportExport.cpp
|
||||
unit/utASEImportExport.cpp
|
||||
unit/utAnim.cpp
|
||||
unit/AssimpAPITest.cpp
|
||||
unit/utB3DImportExport.cpp
|
||||
|
@ -88,6 +88,7 @@ SET( TEST_SRCS
|
|||
unit/utFixInfacingNormals.cpp
|
||||
unit/utGenNormals.cpp
|
||||
unit/utglTFImportExport.cpp
|
||||
unit/utglTF2ImportExport.cpp
|
||||
unit/utHMPImportExport.cpp
|
||||
unit/utIFCImportExport.cpp
|
||||
unit/utImporter.cpp
|
||||
|
@ -146,7 +147,7 @@ add_executable( unit
|
|||
)
|
||||
|
||||
add_definitions(-DASSIMP_TEST_MODELS_DIR="${CMAKE_CURRENT_LIST_DIR}/models")
|
||||
|
||||
|
||||
SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} )
|
||||
|
||||
IF( WIN32 )
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,181 @@
|
|||
{
|
||||
"asset": {
|
||||
"generator": "COLLADA2GLTF",
|
||||
"version": "2.0"
|
||||
},
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 0,
|
||||
"mode": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "Mesh"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
23
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 288,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
6.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
},
|
||||
"name": "Texture"
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANMAAADTCAMAAAAs2dbrAAAAsVBMVEXc3Nz8/f3+//9chyf///+VsHP4+/thiy3Z29dyl0R8nlH09vJeiCqzxZ6ft4GLqWatwZXw9vyEpFynvYxmjjTS3cNrkjvu8urn8vre7fjY6ffL08K6yqbEz7XT183K4vTQ5fW62fC/zq3J17fn7d/g6NbC3fLb5c/l5eVsrd+wzOF/t+OWw+WGu+TE099vr+CmyON5tOJ0seG50OHL1t7S2d7Z29yOv+Wdx+emzuyx1O6AHuoWAAAIi0lEQVR4XuzUS3LEIAxF0WznIYk/xun9LyxDRqnqGANq4rODW4L39d88Ho/H43HkZPzJVYgoxhiIpDJ7k2z5wJpizSkBv4vCJn1OWTZMeE9gY/Xfx3DE30Q2WfGBvOAa8lZnEKFH0JZ1GEE/MnpGw54R93Cs41ip4k6SjuWPjnC3YJZWtaJdqhJhlJDWLINgJJm/FoUxGpfJ0xAxnvMTv1UWzEF21pG8wzT+2OZIjeTxScZhLmdGz13FfHXoAGbCCmHgVCSHNVwaleSxjh8z4Yxmj09VBGtRGbAOq1G+OSlgvZC3SwLijVE2Qodot7lS4+xGSS1quyS4O/5UIegSSm/SUaENHZ1NDH1qX5SHRmdPUoJOqWPyInS6Pn6HoNlkJxh68T6fqTFXkkrERPL9en0L3ueufKkf6uxmt1EYiAN4sP7i0pNPABeItEIdeV0vJMTA+z/YaqWo3WSS1gn2lP4ewFHEfNqexLi5hAIAvTgKZZ+4myQxpsSZUtomiD75yPM5Pqg8uDK5cbORZzT+p3JDgfxma16LK3WaceLUkxQPJjj6hnGbo2sHpkkxzB4didFgcgp23OJQ5BS4Pn6TeiM5PThYCva2vQmCHDgYCmZXfCbJfMpc9PXQk6QGTE0PMNv7TDSBmaM/IXqSVeKKdsSsy6gjCfMZLijWSVaXvomkzbiwRF/jR0fS3JThXTbTw8aAVVCcbXFW2wRv8oa+hVmaumoWS88YTgKFXNpBYHrd1GXfaaCfyI0CK7u0g0DoSfMCoSduTBF6Zto3bV033ewdiel/L/9+te3G6HOR35d4p/JmcjI9rVI4e9nd0z9XSStc08tAidkmw4cs6khuK3BK6ZlS6huFC6/xZj23z3BHbSiZOceVIto2aCrcp1N1BteByXe3DfQgq/EZNVMKQwUui5ROPscXFoqvL3HLa5R0sjkg/6eGEjcVMQajXuNraqK4XA3ufoey9AhXIURmUzyDhCbUya0/nFN6SHIbyK0vERMCqZZW4ikcXCQOcQ7nlgT1gVPFjvuz+vCXX4UCl/mEd+tAXhSsSDxT9rq/tJjbasJAFEWJm2QwF6NJVNra0hptoFVsERrp/39YXwTrbDWZOcf1GrLDhrMyF45elUMAVTjlR5NvrctNIsniFDB5HVzstJWEB+MUR/I5PdVRahtQcF3hSNxEkoMGhw+SAidmU1bqLjIFI5wwS670IwhPYvzHNCRweweZBiHOeBH8yik8KnBOtWal9GUqcc4T38D6h49gM0zoNLXTlqmGBQ/fXhDOhKyUskyrChYZ78ol4cyCpn+jKlMUw6bkTpJwxjgqJZ93jHgbIQt3Ukou0zOYkDv5rUw1rpDmtE9685VpYn91ZXp1OjiFs0xMpqXUa795z7mTRnjH0jvxuh77pXkP0a/TRh7erdSDh1ItybTERQruJA5nNJTia4+16dvp4C4Th+srxfOeDKHVaccyUTiRNnan6FNNpm6fvhTCmVlil3JTqh3wvDt1ksvE5PTeu5ZM3evTh0o4MxZcY+4eO2QSdeobzpgpK6UjU/d+b68TzszmvqvUhmRa4Aal05mwdQhnClbKU6bG4AYZn91dwv94t+MepYEgCuDTzhSudIFSgKIHKtwlaIBEe5cTv/8XM8ZEIrPtGxzw9zd5TcO83SbbgjKhSsnJXyZtRZfeHOFAmKut7fgF2siFdMyd1qQ0/nB7pZbN9WUacrcPpOwd4bev1B6USeuTdnA0FZqCF67h6Rae95y0r45wTO9SR0+ZtFCR9uIIx2agUv55H5H26gnHqp7906395W/TXWBkGD/7xOGiw/2VwvNeLxhaU8Qeh6eFCrd7ugxLjsbTrWTM2IPtTbeNIdxu9myr1EnNe8lYThFvL65wLAyilcLzPg+MZRTz6gzHRoaTgWYZKxNWUlRzZbi/UpKc4MNlUrHFI0Udrg73Vyo5oKP10pZseCexeR8J9ztXKvrNfvNR/nHeK2px3jC+T2zh/kql6ebPxnhcCph3VCett/zx7dfYHT6lINxTKWWy2aurqnnHdYqrRdLJu2UiAsId+s8S0XJVmbJNTm0+iwLCPZXC0jkbZdQqkRYq3CETq3rGRltqVUhUqsI9wlYAdbqFzB4IDp8O99Ln19iIHaMHhi/N+KbCohaDFZutqUPhWB9864RnP1yQAoav5NurCrjk9dlsRJ16KnzK9zAAN/XUZ7tH6nQ56cWY7yPvWiiSku3CgAD5yy7newmrRFrUFV9jSEAhZ8Uo8P2EQfyvSoYzVtDmZFwlihJku4VM31Vvm/N1pgQVv6PnWZ//g2pby1m6my5+cls3ubHCQBCASypZbiPbIGDYAF7wXpScYO5/tCxZBgb8g78btKpdbZ6kA/708/Vah35kKrbxy+v7/9frX9dOPE/hb2KYi+V5dsYBjk+icIjhc+gZhyz1xQRp+BQ6ALUF5XFYz2eYBIfNmo/gcILnEzQ4QwzLZ2ecstVTELuWpTOCk8LEwq04batm83Zvz5I1gg+IeczftY7L2+FDHUul8DFVzWPaSc8SjTMuCIblsRt2lfSEw0WLZVmsx2Wu5Mqro9FbwR0GlqMX3OLtyztM16n6RgJ8PYu36+qph52zzEwJ7rZoZjUggnViPtohitAwl2lFLIp5NAHxdDZTO8S0GqY2OkQmqp69220T07EDkggtU2lmpOLSRKUHJCTeMro2IK25Z1xmRXqLYTxjJ8jh7QzjGAdBLhJlKu0DcpLO8F7TEJDd1lrexjhBCd7Bj7yDVivKIe56WL/t2jEKwCAMheEsYirEBgNdohl6CO9/tM6FgrRdFPJNWX/I+BIbTMao/MhKYjAlo/3LE8bCChND5RLfLXxPhNl1wMYhxXHOtktDWInWHMr2mHakkEkRVoXaaiUWyVmEqTY1hOX1+z3mnHPOXX/B0DoXjBYdAAAAAElFTkSuQmCC"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9986,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 768,
|
||||
"byteLength": 72,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 576,
|
||||
"byteStride": 12,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 576,
|
||||
"byteLength": 192,
|
||||
"byteStride": 8,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 840,
|
||||
"uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
{
|
||||
"asset": {
|
||||
"generator": "COLLADA2GLTF",
|
||||
"version": "2.0"
|
||||
},
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 0,
|
||||
"mode": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "Mesh"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
23
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 288,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
6.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
},
|
||||
"extensions": {
|
||||
"KHR_materials_pbrSpecularGlossiness": {
|
||||
"diffuseTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"specularFactor": [
|
||||
0.20000000298023225,
|
||||
0.20000000298023225,
|
||||
0.20000000298023225
|
||||
],
|
||||
"glossinessFactor": 1.0
|
||||
}
|
||||
},
|
||||
"name": "Texture"
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "CesiumLogoFlat.png"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9986,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 768,
|
||||
"byteLength": 72,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 576,
|
||||
"byteStride": 12,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 576,
|
||||
"byteLength": 192,
|
||||
"byteStride": 8,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 840,
|
||||
"uri": "BoxTextured0.bin"
|
||||
}
|
||||
],
|
||||
"extensionsUsed": [
|
||||
"KHR_materials_pbrSpecularGlossiness"
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,282 @@
|
|||
{
|
||||
"asset": {
|
||||
"generator": "COLLADA2GLTF",
|
||||
"version": "2.0"
|
||||
},
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 0,
|
||||
"mode": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "Mesh"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
23
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 288,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
6.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"values": {
|
||||
"diffuse": [
|
||||
0
|
||||
],
|
||||
"specular": [
|
||||
0.20000000298023225,
|
||||
0.20000000298023225,
|
||||
0.20000000298023225,
|
||||
1.0
|
||||
],
|
||||
"shininess": [
|
||||
256.0
|
||||
],
|
||||
"transparency": [
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"technique": 0
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "CesiumLogoFlat.png"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9986,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"techniques": [
|
||||
{
|
||||
"attributes": {
|
||||
"a_normal": "normal",
|
||||
"a_position": "position",
|
||||
"a_texcoord0": "texcoord0"
|
||||
},
|
||||
"parameters": {
|
||||
"diffuse": {
|
||||
"type": 35678
|
||||
},
|
||||
"modelViewMatrix": {
|
||||
"semantic": "MODELVIEW",
|
||||
"type": 35676
|
||||
},
|
||||
"normal": {
|
||||
"semantic": "NORMAL",
|
||||
"type": 35665
|
||||
},
|
||||
"normalMatrix": {
|
||||
"semantic": "MODELVIEWINVERSETRANSPOSE",
|
||||
"type": 35675
|
||||
},
|
||||
"position": {
|
||||
"semantic": "POSITION",
|
||||
"type": 35665
|
||||
},
|
||||
"projectionMatrix": {
|
||||
"semantic": "PROJECTION",
|
||||
"type": 35676
|
||||
},
|
||||
"shininess": {
|
||||
"type": 5126
|
||||
},
|
||||
"specular": {
|
||||
"type": 35666
|
||||
},
|
||||
"texcoord0": {
|
||||
"semantic": "TEXCOORD_0",
|
||||
"type": 35665
|
||||
},
|
||||
"transparency": {
|
||||
"type": 5126
|
||||
}
|
||||
},
|
||||
"program": 0,
|
||||
"states": {
|
||||
"enable": [
|
||||
2884,
|
||||
2929
|
||||
]
|
||||
},
|
||||
"uniforms": {
|
||||
"u_diffuse": "diffuse",
|
||||
"u_modelViewMatrix": "modelViewMatrix",
|
||||
"u_normalMatrix": "normalMatrix",
|
||||
"u_projectionMatrix": "projectionMatrix",
|
||||
"u_shininess": "shininess",
|
||||
"u_specular": "specular",
|
||||
"u_transparency": "transparency"
|
||||
}
|
||||
}
|
||||
],
|
||||
"programs": [
|
||||
{
|
||||
"attributes": [
|
||||
"a_normal",
|
||||
"a_position",
|
||||
"a_texcoord0"
|
||||
],
|
||||
"fragmentShader": 1,
|
||||
"vertexShader": 0
|
||||
}
|
||||
],
|
||||
"shaders": [
|
||||
{
|
||||
"type": 35633,
|
||||
"uri": "BoxTextured0.vert"
|
||||
},
|
||||
{
|
||||
"type": 35632,
|
||||
"uri": "BoxTextured1.frag"
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 768,
|
||||
"byteLength": 72,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 576,
|
||||
"byteStride": 12,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 576,
|
||||
"byteLength": 192,
|
||||
"byteStride": 8,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 840,
|
||||
"uri": "BoxTextured0.bin"
|
||||
}
|
||||
],
|
||||
"extensionsRequired": [
|
||||
"KHR_technique_webgl"
|
||||
],
|
||||
"extensionsUsed": [
|
||||
"KHR_technique_webgl"
|
||||
]
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,17 @@
|
|||
precision highp float;
|
||||
uniform mat4 u_modelViewMatrix;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat3 u_normalMatrix;
|
||||
attribute vec3 a_position;
|
||||
varying vec3 v_position;
|
||||
attribute vec3 a_normal;
|
||||
varying vec3 v_normal;
|
||||
attribute vec2 a_texcoord0;
|
||||
varying vec2 v_texcoord0;
|
||||
void main(void) {
|
||||
vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
|
||||
v_position = pos.xyz;
|
||||
gl_Position = u_projectionMatrix * pos;
|
||||
v_normal = u_normalMatrix * a_normal;
|
||||
v_texcoord0 = a_texcoord0;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
precision highp float;
|
||||
uniform sampler2D u_diffuse;
|
||||
uniform vec4 u_specular;
|
||||
uniform float u_shininess;
|
||||
uniform float u_transparency;
|
||||
varying vec3 v_position;
|
||||
varying vec3 v_normal;
|
||||
varying vec2 v_texcoord0;
|
||||
void main(void) {
|
||||
vec3 normal = normalize(v_normal);
|
||||
vec4 diffuse = texture2D(u_diffuse, v_texcoord0);
|
||||
vec3 diffuseLight = vec3(0.0, 0.0, 0.0);
|
||||
vec3 specular = u_specular.rgb;
|
||||
vec3 specularLight = vec3(0.0, 0.0, 0.0);
|
||||
vec3 ambient = diffuse.rgb;
|
||||
vec3 viewDir = -normalize(v_position);
|
||||
vec3 ambientLight = vec3(0.0, 0.0, 0.0);
|
||||
ambientLight += vec3(0.2, 0.2, 0.2);
|
||||
vec3 l = vec3(0.0, 0.0, 1.0);
|
||||
diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal, l), 0.);
|
||||
vec3 reflectDir = reflect(-l, normal);
|
||||
float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));
|
||||
specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;
|
||||
vec3 color = vec3(0.0, 0.0, 0.0);
|
||||
color += diffuse.rgb * diffuseLight;
|
||||
color += specular * specularLight;
|
||||
color += ambient * ambientLight;
|
||||
gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,181 @@
|
|||
{
|
||||
"asset": {
|
||||
"generator": "COLLADA2GLTF",
|
||||
"version": "2.0"
|
||||
},
|
||||
"scene": 0,
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [
|
||||
0
|
||||
]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"children": [
|
||||
1
|
||||
],
|
||||
"matrix": [
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
-1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"NORMAL": 1,
|
||||
"POSITION": 2,
|
||||
"TEXCOORD_0": 3
|
||||
},
|
||||
"indices": 0,
|
||||
"mode": 4,
|
||||
"material": 0
|
||||
}
|
||||
],
|
||||
"name": "Mesh"
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 36,
|
||||
"max": [
|
||||
23
|
||||
],
|
||||
"min": [
|
||||
0
|
||||
],
|
||||
"type": "SCALAR"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
1.0,
|
||||
1.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
-1.0,
|
||||
-1.0,
|
||||
-1.0
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 288,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
"min": [
|
||||
-0.5,
|
||||
-0.5,
|
||||
-0.5
|
||||
],
|
||||
"type": "VEC3"
|
||||
},
|
||||
{
|
||||
"bufferView": 2,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 24,
|
||||
"max": [
|
||||
6.0,
|
||||
1.0
|
||||
],
|
||||
"min": [
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"type": "VEC2"
|
||||
}
|
||||
],
|
||||
"materials": [
|
||||
{
|
||||
"pbrMetallicRoughness": {
|
||||
"baseColorTexture": {
|
||||
"index": 0
|
||||
},
|
||||
"metallicFactor": 0.0
|
||||
},
|
||||
"name": "Texture"
|
||||
}
|
||||
],
|
||||
"textures": [
|
||||
{
|
||||
"sampler": 0,
|
||||
"source": 0
|
||||
}
|
||||
],
|
||||
"images": [
|
||||
{
|
||||
"uri": "CesiumLogoFlat.png"
|
||||
}
|
||||
],
|
||||
"samplers": [
|
||||
{
|
||||
"magFilter": 9729,
|
||||
"minFilter": 9986,
|
||||
"wrapS": 10497,
|
||||
"wrapT": 10497
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 768,
|
||||
"byteLength": 72,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 576,
|
||||
"byteStride": 12,
|
||||
"target": 34962
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 576,
|
||||
"byteLength": 192,
|
||||
"byteStride": 8,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"byteLength": 840,
|
||||
"uri": "BoxTextured0.bin"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2017, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
#include "UnitTestPCH.h"
|
||||
#include "AbstractImportExportBase.h"
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
class utglTF2ImportExport : public AbstractImportExportBase {
|
||||
public:
|
||||
virtual bool importerTest() {
|
||||
Assimp::Importer importer;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", 0);
|
||||
return nullptr != scene;
|
||||
}
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
virtual bool exporterTest() {
|
||||
Assimp::Importer importer;
|
||||
Assimp::Exporter exporter;
|
||||
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", 0 );
|
||||
EXPECT_NE( nullptr, scene );
|
||||
EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
||||
|
||||
};
|
||||
|
||||
TEST_F( utglTF2ImportExport, importglTF2FromFileTest ) {
|
||||
EXPECT_TRUE( importerTest() );
|
||||
}
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||
TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) {
|
||||
EXPECT_TRUE( exporterTest() );
|
||||
}
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -55,6 +55,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
TEST_F( utglTFImportExport, importglTFromFileTest ) {
|
||||
TEST_F( utglTFImportExport, importglTFFromFileTest ) {
|
||||
EXPECT_TRUE( importerTest() );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue