Merge pull request #1024 from ascandal/feature/glTF-animations
Export glTF node animationspull/1027/head
commit
d474c24753
|
@ -29,6 +29,12 @@ cmake_uninstall.cmake
|
||||||
assimp-config.cmake
|
assimp-config.cmake
|
||||||
assimp-config-version.cmake
|
assimp-config-version.cmake
|
||||||
|
|
||||||
|
# MakeFile
|
||||||
|
Makefile
|
||||||
|
test/Makefile
|
||||||
|
test/headercheck/Makefile
|
||||||
|
tools/assimp_cmd/Makefile
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
test/results
|
test/results
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -128,6 +128,7 @@ namespace glTF
|
||||||
struct BufferView; // here due to cross-reference
|
struct BufferView; // here due to cross-reference
|
||||||
struct Texture;
|
struct Texture;
|
||||||
struct Light;
|
struct Light;
|
||||||
|
struct Skin;
|
||||||
|
|
||||||
|
|
||||||
// Vec/matrix types, as raw float arrays
|
// Vec/matrix types, as raw float arrays
|
||||||
|
@ -455,25 +456,6 @@ namespace glTF
|
||||||
void Read(Value& obj, Asset& r);
|
void Read(Value& obj, Asset& r);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Animation : public Object
|
|
||||||
{
|
|
||||||
struct Channel
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Target
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Sampler
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
//! A buffer points to binary geometry, animation, or skins.
|
//! A buffer points to binary geometry, animation, or skins.
|
||||||
struct Buffer : public Object
|
struct Buffer : public Object
|
||||||
{
|
{
|
||||||
|
@ -825,6 +807,10 @@ namespace glTF
|
||||||
Ref<Camera> camera;
|
Ref<Camera> camera;
|
||||||
Ref<Light> light;
|
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.
|
||||||
|
std::string jointName; //!< Name used when this node is a joint in a skin.
|
||||||
|
|
||||||
Node() {}
|
Node() {}
|
||||||
void Read(Value& obj, Asset& r);
|
void Read(Value& obj, Asset& r);
|
||||||
};
|
};
|
||||||
|
@ -864,6 +850,11 @@ namespace glTF
|
||||||
|
|
||||||
struct Skin : public Object
|
struct Skin : public Object
|
||||||
{
|
{
|
||||||
|
Nullable<mat4> bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order.
|
||||||
|
Ref<Accessor> inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices.
|
||||||
|
std::vector<std::string/*Ref<Node>*/> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin.
|
||||||
|
std::string name; //!< The user-defined name of this object.
|
||||||
|
|
||||||
Skin() {}
|
Skin() {}
|
||||||
void Read(Value& obj, Asset& r);
|
void Read(Value& obj, Asset& r);
|
||||||
};
|
};
|
||||||
|
@ -934,6 +925,44 @@ namespace glTF
|
||||||
void SetDefaults();
|
void SetDefaults();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Animation : public Object
|
||||||
|
{
|
||||||
|
struct AnimSampler {
|
||||||
|
std::string id; //!< The ID of this sampler.
|
||||||
|
std::string input; //!< The ID of a parameter in this animation to use as key-frame input.
|
||||||
|
std::string interpolation; //!< Type of interpolation algorithm to use between key-frames.
|
||||||
|
std::string output; //!< The ID of a parameter in this animation to use as key-frame output.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimChannel {
|
||||||
|
std::string sampler; //!< The ID of one sampler present in the containing animation's samplers property.
|
||||||
|
|
||||||
|
struct AnimTarget {
|
||||||
|
Ref<Node> id; //!< The ID of the node to animate.
|
||||||
|
std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale").
|
||||||
|
} target;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AnimParameters {
|
||||||
|
Ref<Accessor> TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values.
|
||||||
|
Ref<Accessor> rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors.
|
||||||
|
Ref<Accessor> scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
|
||||||
|
Ref<Accessor> translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors.
|
||||||
|
};
|
||||||
|
|
||||||
|
// AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
|
||||||
|
// AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
|
||||||
|
// AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data.
|
||||||
|
|
||||||
|
std::vector<AnimChannel> Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy.
|
||||||
|
AnimParameters Parameters; //!< The samplers that interpolate between the key-frames.
|
||||||
|
std::vector<AnimSampler> Samplers; //!< The parameterized inputs representing the key-frame data.
|
||||||
|
|
||||||
|
Animation() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//! Base class for LazyDict that acts as an interface
|
//! Base class for LazyDict that acts as an interface
|
||||||
class LazyDictBase
|
class LazyDictBase
|
||||||
{
|
{
|
||||||
|
@ -966,7 +995,7 @@ namespace glTF
|
||||||
typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict;
|
typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict;
|
||||||
|
|
||||||
std::vector<T*> mObjs; //! The read objects
|
std::vector<T*> mObjs; //! The read objects
|
||||||
Dict mObjsById; //! The read objects accesible by id
|
Dict mObjsById; //! The read objects accessible by id
|
||||||
const char* mDictId; //! ID of the dictionary object
|
const char* mDictId; //! ID of the dictionary object
|
||||||
const char* mExtId; //! ID of the extension defining the dictionary
|
const char* mExtId; //! ID of the extension defining the dictionary
|
||||||
Value* mDict; //! JSON dictionary object
|
Value* mDict; //! JSON dictionary object
|
||||||
|
@ -986,7 +1015,7 @@ namespace glTF
|
||||||
|
|
||||||
Ref<T> Get(const char* id);
|
Ref<T> Get(const char* id);
|
||||||
Ref<T> Get(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 std::string& pID) { return Get(pID.c_str()); }
|
||||||
|
|
||||||
Ref<T> Create(const char* id);
|
Ref<T> Create(const char* id);
|
||||||
Ref<T> Create(const std::string& id)
|
Ref<T> Create(const std::string& id)
|
||||||
|
@ -1084,7 +1113,7 @@ namespace glTF
|
||||||
LazyDict<Sampler> samplers;
|
LazyDict<Sampler> samplers;
|
||||||
LazyDict<Scene> scenes;
|
LazyDict<Scene> scenes;
|
||||||
//LazyDict<Shader> shaders;
|
//LazyDict<Shader> shaders;
|
||||||
//LazyDict<Skin> skins;
|
LazyDict<Skin> skins;
|
||||||
//LazyDict<Technique> techniques;
|
//LazyDict<Technique> techniques;
|
||||||
LazyDict<Texture> textures;
|
LazyDict<Texture> textures;
|
||||||
|
|
||||||
|
@ -1109,7 +1138,7 @@ namespace glTF
|
||||||
, samplers (*this, "samplers")
|
, samplers (*this, "samplers")
|
||||||
, scenes (*this, "scenes")
|
, scenes (*this, "scenes")
|
||||||
//, shaders (*this, "shaders")
|
//, shaders (*this, "shaders")
|
||||||
//, skins (*this, "skins")
|
, skins (*this, "skins")
|
||||||
//, techniques (*this, "techniques")
|
//, techniques (*this, "techniques")
|
||||||
, textures (*this, "textures")
|
, textures (*this, "textures")
|
||||||
, lights (*this, "lights", "KHR_materials_common")
|
, lights (*this, "lights", "KHR_materials_common")
|
||||||
|
|
|
@ -102,7 +102,65 @@ namespace glTF {
|
||||||
|
|
||||||
inline void Write(Value& obj, Animation& a, AssetWriter& w)
|
inline void Write(Value& obj, Animation& a, AssetWriter& w)
|
||||||
{
|
{
|
||||||
|
/****************** Channels *******************/
|
||||||
|
Value channels;
|
||||||
|
channels.SetArray();
|
||||||
|
channels.Reserve(unsigned(a.Channels.size()), w.mAl);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < unsigned(a.Channels.size()); ++i) {
|
||||||
|
Animation::AnimChannel& c = a.Channels[i];
|
||||||
|
Value valChannel;
|
||||||
|
valChannel.SetObject();
|
||||||
|
{
|
||||||
|
valChannel.AddMember("sampler", c.sampler, w.mAl);
|
||||||
|
|
||||||
|
Value valTarget;
|
||||||
|
valTarget.SetObject();
|
||||||
|
{
|
||||||
|
valTarget.AddMember("id", StringRef(c.target.id->id), w.mAl);
|
||||||
|
valTarget.AddMember("path", c.target.path, w.mAl);
|
||||||
|
}
|
||||||
|
valChannel.AddMember("target", valTarget, w.mAl);
|
||||||
|
}
|
||||||
|
channels.PushBack(valChannel, w.mAl);
|
||||||
|
}
|
||||||
|
obj.AddMember("channels", channels, w.mAl);
|
||||||
|
|
||||||
|
/****************** Parameters *******************/
|
||||||
|
Value valParameters;
|
||||||
|
valParameters.SetObject();
|
||||||
|
{
|
||||||
|
if (a.Parameters.TIME) {
|
||||||
|
valParameters.AddMember("TIME", StringRef(a.Parameters.TIME->id), w.mAl);
|
||||||
|
}
|
||||||
|
if (a.Parameters.rotation) {
|
||||||
|
valParameters.AddMember("rotation", StringRef(a.Parameters.rotation->id), w.mAl);
|
||||||
|
}
|
||||||
|
if (a.Parameters.scale) {
|
||||||
|
valParameters.AddMember("scale", StringRef(a.Parameters.scale->id), w.mAl);
|
||||||
|
}
|
||||||
|
if (a.Parameters.translation) {
|
||||||
|
valParameters.AddMember("translation", StringRef(a.Parameters.translation->id), w.mAl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj.AddMember("parameters", valParameters, w.mAl);
|
||||||
|
|
||||||
|
/****************** Samplers *******************/
|
||||||
|
Value valSamplers;
|
||||||
|
valSamplers.SetObject();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) {
|
||||||
|
Animation::AnimSampler& s = a.Samplers[i];
|
||||||
|
Value valSampler;
|
||||||
|
valSampler.SetObject();
|
||||||
|
{
|
||||||
|
valSampler.AddMember("input", s.input, w.mAl);
|
||||||
|
valSampler.AddMember("interpolation", s.interpolation, w.mAl);
|
||||||
|
valSampler.AddMember("output", s.output, w.mAl);
|
||||||
|
}
|
||||||
|
valSamplers.AddMember(StringRef(s.id), valSampler, w.mAl);
|
||||||
|
}
|
||||||
|
obj.AddMember("samplers", valSamplers, w.mAl);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Write(Value& obj, Buffer& b, AssetWriter& w)
|
inline void Write(Value& obj, Buffer& b, AssetWriter& w)
|
||||||
|
@ -327,6 +385,16 @@ namespace glTF {
|
||||||
AddRefsVector(obj, "children", n.children, w.mAl);
|
AddRefsVector(obj, "children", n.children, w.mAl);
|
||||||
|
|
||||||
AddRefsVector(obj, "meshes", n.meshes, w.mAl);
|
AddRefsVector(obj, "meshes", n.meshes, w.mAl);
|
||||||
|
|
||||||
|
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||||
|
|
||||||
|
if (n.skin) {
|
||||||
|
obj.AddMember("skin", Value(n.skin->id, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!n.jointName.empty()) {
|
||||||
|
obj.AddMember("jointName", n.jointName, w.mAl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Write(Value& obj, Program& b, AssetWriter& w)
|
inline void Write(Value& obj, Program& b, AssetWriter& w)
|
||||||
|
@ -362,6 +430,24 @@ namespace glTF {
|
||||||
|
|
||||||
inline void Write(Value& obj, Skin& b, AssetWriter& w)
|
inline void Write(Value& obj, Skin& b, AssetWriter& w)
|
||||||
{
|
{
|
||||||
|
/****************** jointNames *******************/
|
||||||
|
Value vJointNames;
|
||||||
|
vJointNames.SetArray();
|
||||||
|
vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) {
|
||||||
|
vJointNames.PushBack(StringRef(b.jointNames[i]), w.mAl);
|
||||||
|
}
|
||||||
|
obj.AddMember("jointNames", vJointNames, w.mAl);
|
||||||
|
|
||||||
|
if (b.bindShapeMatrix.isPresent) {
|
||||||
|
Value val;
|
||||||
|
obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.inverseBindMatrices) {
|
||||||
|
obj.AddMember("inverseBindMatrices", Value(b.inverseBindMatrices->id, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,6 @@ namespace Assimp {
|
||||||
// Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp
|
// Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp
|
||||||
void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||||
{
|
{
|
||||||
|
|
||||||
// invoke the exporter
|
// invoke the exporter
|
||||||
glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
|
glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
|
||||||
}
|
}
|
||||||
|
@ -126,26 +125,24 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
|
||||||
|
|
||||||
ExportMetadata();
|
ExportMetadata();
|
||||||
|
|
||||||
//for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {}
|
|
||||||
|
|
||||||
//for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
|
//for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
|
||||||
|
|
||||||
//for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
|
//for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
|
||||||
|
|
||||||
|
|
||||||
ExportMaterials();
|
ExportMaterials();
|
||||||
|
|
||||||
ExportMeshes();
|
|
||||||
|
|
||||||
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
|
||||||
|
|
||||||
|
|
||||||
if (mScene->mRootNode) {
|
if (mScene->mRootNode) {
|
||||||
ExportNode(mScene->mRootNode);
|
ExportNode(mScene->mRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExportMeshes();
|
||||||
|
|
||||||
|
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
||||||
|
|
||||||
ExportScene();
|
ExportScene();
|
||||||
|
|
||||||
|
ExportAnimations();
|
||||||
|
|
||||||
glTF::AssetWriter writer(*mAsset);
|
glTF::AssetWriter writer(*mAsset);
|
||||||
|
|
||||||
if (isBinary) {
|
if (isBinary) {
|
||||||
|
@ -164,6 +161,14 @@ static void CopyValue(const aiMatrix4x4& v, glTF::mat4& o)
|
||||||
o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
|
o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void IdentityMatrix4(glTF::mat4& o)
|
||||||
|
{
|
||||||
|
o[ 0] = 1; o[ 1] = 0; o[ 2] = 0; o[ 3] = 0;
|
||||||
|
o[ 4] = 0; o[ 5] = 1; o[ 6] = 0; o[ 7] = 0;
|
||||||
|
o[ 8] = 0; o[ 9] = 0; o[10] = 1; o[11] = 0;
|
||||||
|
o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
|
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
|
||||||
unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
|
unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
|
||||||
{
|
{
|
||||||
|
@ -359,6 +364,78 @@ void glTFExporter::ExportMaterials()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExportSkin(Asset& mAsset, const aiMesh* aim, Ref<Mesh>& meshRef, Ref<Buffer>& bufferRef)
|
||||||
|
{
|
||||||
|
std::string skinName = aim->mName.C_Str();
|
||||||
|
skinName = mAsset.FindUniqueID(skinName, "skin");
|
||||||
|
Ref<Skin> skinRef = mAsset.skins.Create(skinName);
|
||||||
|
skinRef->name = skinName;
|
||||||
|
|
||||||
|
mat4* inverseBindMatricesData = new mat4[aim->mNumBones];
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Store the vertex joint and weight data.
|
||||||
|
vec4* vertexJointData = new vec4[aim->mNumVertices];
|
||||||
|
vec4* vertexWeightData = new vec4[aim->mNumVertices];
|
||||||
|
unsigned int* jointsPerVertex = new unsigned int[aim->mNumVertices];
|
||||||
|
for (size_t i = 0; i < aim->mNumVertices; ++i) {
|
||||||
|
jointsPerVertex[i] = 0;
|
||||||
|
for (size_t j = 0; j < 4; ++j) {
|
||||||
|
vertexJointData[i][j] = 0;
|
||||||
|
vertexWeightData[i][j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int idx_bone = 0; idx_bone < aim->mNumBones; ++idx_bone) {
|
||||||
|
const aiBone* aib = aim->mBones[idx_bone];
|
||||||
|
|
||||||
|
// aib->mName =====> skinRef->jointNames
|
||||||
|
// Find the node with id = mName.
|
||||||
|
Ref<Node> nodeRef = mAsset.nodes.Get(aib->mName.C_Str());
|
||||||
|
nodeRef->jointName = "joint_" + std::to_string(idx_bone);
|
||||||
|
skinRef->jointNames.push_back("joint_" + std::to_string(idx_bone));
|
||||||
|
|
||||||
|
// Identity Matrix =====> skinRef->bindShapeMatrix
|
||||||
|
// Temporary. Hard-coded identity matrix here
|
||||||
|
skinRef->bindShapeMatrix.isPresent = true;
|
||||||
|
IdentityMatrix4(skinRef->bindShapeMatrix.value);
|
||||||
|
|
||||||
|
// aib->mOffsetMatrix =====> skinRef->inverseBindMatrices
|
||||||
|
CopyValue(aib->mOffsetMatrix, inverseBindMatricesData[idx_bone]);
|
||||||
|
|
||||||
|
// aib->mWeights =====> vertexWeightData
|
||||||
|
for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) {
|
||||||
|
aiVertexWeight tmpVertWeight = aib->mWeights[idx_weights];
|
||||||
|
vertexJointData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = idx_bone;
|
||||||
|
vertexWeightData[tmpVertWeight.mVertexId][jointsPerVertex[tmpVertWeight.mVertexId]] = tmpVertWeight.mWeight;
|
||||||
|
|
||||||
|
jointsPerVertex[tmpVertWeight.mVertexId] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End: for-loop mNumMeshes
|
||||||
|
|
||||||
|
// Create the Accessor for skinRef->inverseBindMatrices
|
||||||
|
Ref<Accessor> invBindMatrixAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumBones, inverseBindMatricesData, AttribType::MAT4, AttribType::MAT4, ComponentType_FLOAT);
|
||||||
|
if (invBindMatrixAccessor) skinRef->inverseBindMatrices = invBindMatrixAccessor;
|
||||||
|
|
||||||
|
|
||||||
|
Mesh::Primitive& p = meshRef->primitives.back();
|
||||||
|
Ref<Accessor> vertexJointAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||||
|
if (vertexJointAccessor) p.attributes.joint.push_back(vertexJointAccessor);
|
||||||
|
|
||||||
|
Ref<Accessor> vertexWeightAccessor = ExportData(mAsset, skinName, bufferRef, aim->mNumVertices, vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||||
|
if (vertexWeightAccessor) p.attributes.weight.push_back(vertexWeightAccessor);
|
||||||
|
|
||||||
|
|
||||||
|
// Create the skinned mesh instance node.
|
||||||
|
Ref<Node> node = mAsset.nodes.Create(mAsset.FindUniqueID(skinName, "node"));
|
||||||
|
// Ref<Node> node = mAsset.nodes.Get(aim->mBones[0]->mName.C_Str());
|
||||||
|
node->meshes.push_back(meshRef);
|
||||||
|
node->name = node->id;
|
||||||
|
node->skeletons.push_back(mAsset.nodes.Get(aim->mBones[0]->mName.C_Str()));
|
||||||
|
node->skin = skinRef;
|
||||||
|
}
|
||||||
|
|
||||||
void glTFExporter::ExportMeshes()
|
void glTFExporter::ExportMeshes()
|
||||||
{
|
{
|
||||||
// Not for
|
// Not for
|
||||||
|
@ -369,7 +446,7 @@ void glTFExporter::ExportMeshes()
|
||||||
typedef unsigned short IndicesType;
|
typedef unsigned short IndicesType;
|
||||||
|
|
||||||
// Variables needed for compression. BEGIN.
|
// Variables needed for compression. BEGIN.
|
||||||
// Indices, not pointers - because pointer to buffer is changin while writing to it.
|
// 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_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.
|
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.
|
std::vector<size_t> idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer.
|
||||||
|
@ -480,6 +557,12 @@ void glTFExporter::ExportMeshes()
|
||||||
p.mode = PrimitiveMode_TRIANGLES;
|
p.mode = PrimitiveMode_TRIANGLES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************** Skins ****************/
|
||||||
|
///TODO: Fix skinning animation
|
||||||
|
// if(aim->HasBones()) {
|
||||||
|
// ExportSkin(*mAsset, aim, m, b);
|
||||||
|
// }
|
||||||
|
|
||||||
/****************** Compression ******************/
|
/****************** Compression ******************/
|
||||||
///TODO: animation: weights, joints.
|
///TODO: animation: weights, joints.
|
||||||
if(comp_allow)
|
if(comp_allow)
|
||||||
|
@ -571,7 +654,7 @@ void glTFExporter::ExportMeshes()
|
||||||
m->Extension.push_back(ext);
|
m->Extension.push_back(ext);
|
||||||
#endif
|
#endif
|
||||||
}// if(comp_allow)
|
}// if(comp_allow)
|
||||||
}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
|
}// for (unsigned int i = 0; i < mScene->mNumMeshes; ++i)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int glTFExporter::ExportNode(const aiNode* n)
|
unsigned int glTFExporter::ExportNode(const aiNode* n)
|
||||||
|
@ -622,10 +705,134 @@ void glTFExporter::ExportMetadata()
|
||||||
asset.generator = buffer;
|
asset.generator = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref<Animation>& animRef, Ref<Buffer>& buffer, const aiNodeAnim* nodeChannel)
|
||||||
|
{
|
||||||
|
// Loop over the data and check to see if it exactly matches an existing buffer.
|
||||||
|
// If yes, then reference the existing corresponding accessor.
|
||||||
|
// Otherwise, add to the buffer and create a new accessor.
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Extract TIME parameter data.
|
||||||
|
// Check if the timeStamps are the same for mPositionKeys, mRotationKeys, and mScalingKeys.
|
||||||
|
if(nodeChannel->mNumPositionKeys > 0) {
|
||||||
|
typedef float TimeType;
|
||||||
|
std::vector<TimeType> timeData;
|
||||||
|
timeData.resize(nodeChannel->mNumPositionKeys);
|
||||||
|
for (size_t i = 0; i < nodeChannel->mNumPositionKeys; ++i) {
|
||||||
|
timeData[i] = nodeChannel->mPositionKeys[i].mTime; // Check if we have to cast type here. e.g. uint16_t()
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> timeAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumPositionKeys, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT);
|
||||||
|
if (timeAccessor) animRef->Parameters.TIME = timeAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Extract translation parameter data
|
||||||
|
if(nodeChannel->mNumPositionKeys > 0) {
|
||||||
|
C_STRUCT aiVector3D* translationData = new aiVector3D[nodeChannel->mNumPositionKeys];
|
||||||
|
for (size_t i = 0; i < nodeChannel->mNumPositionKeys; ++i) {
|
||||||
|
translationData[i] = nodeChannel->mPositionKeys[i].mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> tranAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumPositionKeys, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||||
|
if (tranAccessor) animRef->Parameters.translation = tranAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Extract scale parameter data
|
||||||
|
if(nodeChannel->mNumScalingKeys > 0) {
|
||||||
|
C_STRUCT aiVector3D* scaleData = new aiVector3D[nodeChannel->mNumScalingKeys];
|
||||||
|
for (size_t i = 0; i < nodeChannel->mNumScalingKeys; ++i) {
|
||||||
|
scaleData[i] = nodeChannel->mScalingKeys[i].mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> scaleAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumScalingKeys, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||||
|
if (scaleAccessor) animRef->Parameters.scale = scaleAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------
|
||||||
|
// Extract rotation parameter data
|
||||||
|
if(nodeChannel->mNumRotationKeys > 0) {
|
||||||
|
C_STRUCT aiQuaternion* rotationData = new aiQuaternion[nodeChannel->mNumRotationKeys];
|
||||||
|
for (size_t i = 0; i < nodeChannel->mNumRotationKeys; ++i) {
|
||||||
|
rotationData[i] = nodeChannel->mRotationKeys[i].mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> rotAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumRotationKeys, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT);
|
||||||
|
if (rotAccessor) animRef->Parameters.rotation = rotAccessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFExporter::ExportAnimations()
|
||||||
|
{
|
||||||
|
Ref<Buffer> bufferRef = mAsset->buffers.Get(unsigned (0));
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mScene->mNumAnimations; ++i) {
|
||||||
|
const aiAnimation* anim = mScene->mAnimations[i];
|
||||||
|
|
||||||
|
std::string nameAnim = "anim";
|
||||||
|
if (anim->mName.length > 0) {
|
||||||
|
nameAnim = anim->mName.C_Str();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int channelIndex = 0; channelIndex < anim->mNumChannels; ++channelIndex) {
|
||||||
|
const aiNodeAnim* nodeChannel = anim->mChannels[channelIndex];
|
||||||
|
|
||||||
|
// It appears that assimp stores this type of animation as multiple animations.
|
||||||
|
// where each aiNodeAnim in mChannels animates a specific node.
|
||||||
|
std::string name = nameAnim + "_" + std::to_string(channelIndex);
|
||||||
|
name = mAsset->FindUniqueID(name, "animation");
|
||||||
|
Ref<Animation> animRef = mAsset->animations.Create(name);
|
||||||
|
|
||||||
|
/******************* Parameters ********************/
|
||||||
|
ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel);
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
|
std::string channelType;
|
||||||
|
int channelSize;
|
||||||
|
switch (j) {
|
||||||
|
case 0:
|
||||||
|
channelType = "rotation";
|
||||||
|
channelSize = nodeChannel->mNumRotationKeys;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
channelType = "scale";
|
||||||
|
channelSize = nodeChannel->mNumScalingKeys;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
channelType = "translation";
|
||||||
|
channelSize = nodeChannel->mNumPositionKeys;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelSize < 1) { continue; }
|
||||||
|
|
||||||
|
Animation::AnimChannel tmpAnimChannel;
|
||||||
|
Animation::AnimSampler tmpAnimSampler;
|
||||||
|
|
||||||
|
tmpAnimChannel.sampler = name + "_" + channelType;
|
||||||
|
tmpAnimChannel.target.path = channelType;
|
||||||
|
tmpAnimSampler.output = channelType;
|
||||||
|
tmpAnimSampler.id = name + "_" + channelType;
|
||||||
|
|
||||||
|
tmpAnimChannel.target.id = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str());
|
||||||
|
|
||||||
|
tmpAnimSampler.input = "TIME";
|
||||||
|
tmpAnimSampler.interpolation = "LINEAR";
|
||||||
|
|
||||||
|
animRef->Channels.push_back(tmpAnimChannel);
|
||||||
|
animRef->Samplers.push_back(tmpAnimSampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assimp documentation staes this is not used (not implemented)
|
||||||
|
// for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) {
|
||||||
|
// const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex];
|
||||||
|
// }
|
||||||
|
|
||||||
|
} // End: for-loop mNumAnimations
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER
|
#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||||
|
|
|
@ -59,7 +59,6 @@ struct aiMaterial;
|
||||||
namespace glTF
|
namespace glTF
|
||||||
{
|
{
|
||||||
class Asset;
|
class Asset;
|
||||||
|
|
||||||
struct TexProperty;
|
struct TexProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +100,7 @@ namespace Assimp
|
||||||
void ExportMeshes();
|
void ExportMeshes();
|
||||||
unsigned int ExportNode(const aiNode* node);
|
unsigned int ExportNode(const aiNode* node);
|
||||||
void ExportScene();
|
void ExportScene();
|
||||||
|
void ExportAnimations();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue