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-version.cmake
|
||||
|
||||
# MakeFile
|
||||
Makefile
|
||||
test/Makefile
|
||||
test/headercheck/Makefile
|
||||
tools/assimp_cmd/Makefile
|
||||
|
||||
# Tests
|
||||
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 Texture;
|
||||
struct Light;
|
||||
struct Skin;
|
||||
|
||||
|
||||
// Vec/matrix types, as raw float arrays
|
||||
|
@ -455,25 +456,6 @@ namespace glTF
|
|||
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.
|
||||
struct Buffer : public Object
|
||||
{
|
||||
|
@ -825,6 +807,10 @@ namespace glTF
|
|||
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.
|
||||
std::string jointName; //!< Name used when this node is a joint in a skin.
|
||||
|
||||
Node() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
@ -864,6 +850,11 @@ namespace glTF
|
|||
|
||||
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() {}
|
||||
void Read(Value& obj, Asset& r);
|
||||
};
|
||||
|
@ -934,6 +925,44 @@ namespace glTF
|
|||
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
|
||||
class LazyDictBase
|
||||
{
|
||||
|
@ -966,7 +995,7 @@ namespace glTF
|
|||
typedef typename std::gltf_unordered_map< std::string, unsigned int > Dict;
|
||||
|
||||
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* mExtId; //! ID of the extension defining the dictionary
|
||||
Value* mDict; //! JSON dictionary object
|
||||
|
@ -986,7 +1015,7 @@ namespace glTF
|
|||
|
||||
Ref<T> Get(const char* id);
|
||||
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 std::string& id)
|
||||
|
@ -1084,7 +1113,7 @@ namespace glTF
|
|||
LazyDict<Sampler> samplers;
|
||||
LazyDict<Scene> scenes;
|
||||
//LazyDict<Shader> shaders;
|
||||
//LazyDict<Skin> skins;
|
||||
LazyDict<Skin> skins;
|
||||
//LazyDict<Technique> techniques;
|
||||
LazyDict<Texture> textures;
|
||||
|
||||
|
@ -1109,7 +1138,7 @@ namespace glTF
|
|||
, samplers (*this, "samplers")
|
||||
, scenes (*this, "scenes")
|
||||
//, shaders (*this, "shaders")
|
||||
//, skins (*this, "skins")
|
||||
, skins (*this, "skins")
|
||||
//, techniques (*this, "techniques")
|
||||
, textures (*this, "textures")
|
||||
, lights (*this, "lights", "KHR_materials_common")
|
||||
|
|
|
@ -102,7 +102,65 @@ namespace glTF {
|
|||
|
||||
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)
|
||||
|
@ -327,6 +385,16 @@ namespace glTF {
|
|||
AddRefsVector(obj, "children", n.children, 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)
|
||||
|
@ -362,6 +430,24 @@ namespace glTF {
|
|||
|
||||
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
|
||||
void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||
{
|
||||
|
||||
// invoke the exporter
|
||||
glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
|
||||
}
|
||||
|
@ -126,26 +125,24 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc
|
|||
|
||||
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->mNumLights; ++i) {}
|
||||
|
||||
|
||||
ExportMaterials();
|
||||
|
||||
ExportMeshes();
|
||||
|
||||
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
||||
|
||||
|
||||
if (mScene->mRootNode) {
|
||||
ExportNode(mScene->mRootNode);
|
||||
}
|
||||
|
||||
ExportMeshes();
|
||||
|
||||
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
||||
|
||||
ExportScene();
|
||||
|
||||
ExportAnimations();
|
||||
|
||||
glTF::AssetWriter writer(*mAsset);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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()
|
||||
{
|
||||
// Not for
|
||||
|
@ -369,7 +446,7 @@ void glTFExporter::ExportMeshes()
|
|||
typedef unsigned short IndicesType;
|
||||
|
||||
// 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_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.
|
||||
|
@ -480,6 +557,12 @@ void glTFExporter::ExportMeshes()
|
|||
p.mode = PrimitiveMode_TRIANGLES;
|
||||
}
|
||||
|
||||
/*************** Skins ****************/
|
||||
///TODO: Fix skinning animation
|
||||
// if(aim->HasBones()) {
|
||||
// ExportSkin(*mAsset, aim, m, b);
|
||||
// }
|
||||
|
||||
/****************** Compression ******************/
|
||||
///TODO: animation: weights, joints.
|
||||
if(comp_allow)
|
||||
|
@ -571,7 +654,7 @@ void glTFExporter::ExportMeshes()
|
|||
m->Extension.push_back(ext);
|
||||
#endif
|
||||
}// 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)
|
||||
|
@ -622,10 +705,134 @@ void glTFExporter::ExportMetadata()
|
|||
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
|
||||
|
|
|
@ -59,7 +59,6 @@ struct aiMaterial;
|
|||
namespace glTF
|
||||
{
|
||||
class Asset;
|
||||
|
||||
struct TexProperty;
|
||||
}
|
||||
|
||||
|
@ -101,6 +100,7 @@ namespace Assimp
|
|||
void ExportMeshes();
|
||||
unsigned int ExportNode(const aiNode* node);
|
||||
void ExportScene();
|
||||
void ExportAnimations();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue