First concepts
parent
7aa87a9765
commit
e5747dad9b
|
@ -1435,6 +1435,16 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
|
|||
return static_cast<unsigned int>(mMeshes.size() - 1);
|
||||
}
|
||||
|
||||
void ConvertWeightsToSkeleton(const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
|
||||
std::vector<unsigned int> *outputVertStartIndices) {
|
||||
ai_assert(geo.DeformerSkin() != nullptr);
|
||||
|
||||
const Skin &sk = *geo.DeformerSkin();
|
||||
for (auto &cluster : sk.Clusters()) {
|
||||
cluster->Transform();
|
||||
}
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
|
||||
const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, unsigned int materialIndex,
|
||||
|
@ -1529,12 +1539,6 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
|
|||
}
|
||||
}
|
||||
|
||||
const aiNode *GetNodeByName(aiNode *current_node) {
|
||||
aiNode *iter = current_node;
|
||||
//printf("Child count: %d", iter->mNumChildren);
|
||||
return iter;
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
|
||||
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
|
||||
|
|
|
@ -60,6 +60,7 @@ struct ImportSettings {
|
|||
readLights(true),
|
||||
readAnimations(true),
|
||||
readWeights(true),
|
||||
useSkeleton(false),
|
||||
preservePivots(true),
|
||||
optimizeEmptyAnimationCurves(true),
|
||||
useLegacyEmbeddedTextureNaming(false),
|
||||
|
@ -112,6 +113,11 @@ struct ImportSettings {
|
|||
* Default value is true. */
|
||||
bool readWeights;
|
||||
|
||||
/** will convert all animation data into a skeleton (experimental)
|
||||
* Default value is false.
|
||||
*/
|
||||
bool useSkeleton;
|
||||
|
||||
/** preserve transformation pivots and offsets. Since these can
|
||||
* not directly be represented in assimp, additional dummy
|
||||
* nodes will be generated. Note that settings this to false
|
||||
|
|
|
@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by #Importer
|
||||
FBXImporter::FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FBXImporter::~FBXImporter() {
|
||||
FBXImporter::FBXImporter() :
|
||||
mSettings() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the loader
|
||||
void FBXImporter::SetupProperties(const Importer *pImp) {
|
||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||
mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||
mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||
mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||
mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||
mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
|
||||
mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||
mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||
mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||
mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||
mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||
mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||
mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
contents[contents.size() - 1] = 0;
|
||||
const char *const begin = &*contents.begin();
|
||||
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// broad-phase tokenized pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
TokenList tokens;
|
||||
try {
|
||||
|
@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
|
|||
Parser parser(tokens, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser, settings);
|
||||
Document doc(parser, mSettings);
|
||||
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
|
||||
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
if (size_relative_to_cm == 0.0)
|
||||
{
|
||||
if (size_relative_to_cm == 0.0) {
|
||||
// BaseImporter later asserts that fileScale is non-zero.
|
||||
ThrowException("The UnitScaleFactor must be non-zero");
|
||||
}
|
||||
|
|
|
@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
|
|||
// -------------------------------------------------------------------------------------------
|
||||
class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
|
||||
public:
|
||||
/// @brief The class constructor.
|
||||
FBXImporter();
|
||||
~FBXImporter() override;
|
||||
|
||||
// --------------------
|
||||
bool CanRead(const std::string &pFile,
|
||||
IOSystem *pIOHandler,
|
||||
bool checkSig) const override;
|
||||
/// @brief The class destructor, default implementation.
|
||||
~FBXImporter() override = default;
|
||||
|
||||
/// @brief Will check the file for readability.
|
||||
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
// --------------------
|
||||
|
@ -90,7 +91,7 @@ protected:
|
|||
IOSystem *pIOHandler) override;
|
||||
|
||||
private:
|
||||
FBX::ImportSettings settings;
|
||||
FBX::ImportSettings mSettings;
|
||||
}; // !class FBXImporter
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
|
|||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
|||
const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
|
||||
aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
|
||||
ai_real distanceToChild = childpos.Length();
|
||||
if (distanceToChild < 0.0001)
|
||||
if (distanceToChild < ai_epsilon) {
|
||||
continue;
|
||||
}
|
||||
aiVector3D up = aiVector3D(childpos).Normalize();
|
||||
|
||||
aiVector3D orth(1.0, 0.0, 0.0);
|
||||
if (std::fabs(orth * up) > 0.99)
|
||||
if (std::fabs(orth * up) > 0.99) {
|
||||
orth.Set(0.0, 1.0, 0.0);
|
||||
}
|
||||
|
||||
aiVector3D front = (up ^ orth).Normalize();
|
||||
aiVector3D side = (front ^ up).Normalize();
|
||||
|
@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
|||
// add all the vertices to the bone's influences
|
||||
bone->mNumWeights = numVertices;
|
||||
bone->mWeights = new aiVertexWeight[numVertices];
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
for (unsigned int a = 0; a < numVertices; ++a) {
|
||||
bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
|
||||
}
|
||||
|
||||
// HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
|
||||
// them to the array, but I'm tired now and I'm annoyed.
|
||||
|
@ -194,9 +195,10 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
|
|||
}
|
||||
|
||||
// and finally recurse into the children list
|
||||
for (unsigned int a = 0; a < pNode->mNumChildren; a++)
|
||||
for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
|
||||
CreateGeometry(pNode->mChildren[a]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Creates the mesh from the internally accumulated stuff and returns it.
|
||||
|
|
|
@ -691,6 +691,15 @@ enum aiComponent
|
|||
#define AI_CONFIG_FBX_CONVERT_TO_M \
|
||||
"AI_CONFIG_FBX_CONVERT_TO_M"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Will enable the skeleton structo to store bone data.
|
||||
*
|
||||
* This will decouple the bone coupling to the mesh. This feature is
|
||||
* experimental.
|
||||
*/
|
||||
#define AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER \
|
||||
"AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Set the vertex animation keyframe to be imported
|
||||
*
|
||||
|
|
|
@ -120,7 +120,7 @@ extern "C" {
|
|||
* primitive are actually present in a mesh. The #aiProcess_SortByPType flag
|
||||
* executes a special post-processing algorithm which splits meshes with
|
||||
* *different* primitive types mixed up (e.g. lines and triangles) in several
|
||||
* 'clean' submeshes. Furthermore there is a configuration option (
|
||||
* 'clean' sub-meshes. Furthermore there is a configuration option (
|
||||
* #AI_CONFIG_PP_SBP_REMOVE) to force #aiProcess_SortByPType to remove
|
||||
* specific kinds of primitives from the imported scene, completely and forever.
|
||||
* In many cases you'll probably want to set this setting to
|
||||
|
@ -269,12 +269,12 @@ struct aiBone {
|
|||
unsigned int mNumWeights;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
// The bone armature node - used for skeleton conversion
|
||||
// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
/// The bone armature node - used for skeleton conversion
|
||||
/// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode *mArmature;
|
||||
|
||||
// The bone node in the scene - used for skeleton conversion
|
||||
// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
/// The bone node in the scene - used for skeleton conversion
|
||||
/// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode *mNode;
|
||||
|
||||
#endif
|
||||
|
@ -296,7 +296,7 @@ struct aiBone {
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//! Default constructor
|
||||
/// @brief Default constructor
|
||||
aiBone() AI_NO_EXCEPT
|
||||
: mName(),
|
||||
mNumWeights(0),
|
||||
|
@ -309,7 +309,7 @@ struct aiBone {
|
|||
// empty
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
/// @brief Copy constructor
|
||||
aiBone(const aiBone &other) :
|
||||
mName(other.mName),
|
||||
mNumWeights(other.mNumWeights),
|
||||
|
@ -319,11 +319,24 @@ struct aiBone {
|
|||
#endif
|
||||
mWeights(nullptr),
|
||||
mOffsetMatrix(other.mOffsetMatrix) {
|
||||
if (other.mWeights && other.mNumWeights) {
|
||||
copyVertexWeights(other);
|
||||
}
|
||||
|
||||
void copyVertexWeights( const aiBone &other ) {
|
||||
if (other.mWeights == nullptr || other.mNumWeights == 0) {
|
||||
mWeights = nullptr;
|
||||
mNumWeights = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mNumWeights = other.mNumWeights;
|
||||
if (mWeights) {
|
||||
delete[] mWeights;
|
||||
}
|
||||
|
||||
mWeights = new aiVertexWeight[mNumWeights];
|
||||
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
|
||||
}
|
||||
}
|
||||
|
||||
//! Assignment operator
|
||||
aiBone &operator = (const aiBone &other) {
|
||||
|
@ -334,15 +347,7 @@ struct aiBone {
|
|||
mName = other.mName;
|
||||
mNumWeights = other.mNumWeights;
|
||||
mOffsetMatrix = other.mOffsetMatrix;
|
||||
|
||||
if (other.mWeights && other.mNumWeights) {
|
||||
if (mWeights) {
|
||||
delete[] mWeights;
|
||||
}
|
||||
|
||||
mWeights = new aiVertexWeight[mNumWeights];
|
||||
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
|
||||
}
|
||||
copyVertexWeights(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -937,17 +942,92 @@ struct aiMesh {
|
|||
#endif // __cplusplus
|
||||
};
|
||||
|
||||
struct aiSkeleton {
|
||||
C_STRUCT aiString mName;
|
||||
unsigned int mNumWeights;
|
||||
struct aiSkeletonBone {
|
||||
/// The parent bone index, is -1 one if this bone represents the root bone.
|
||||
int mParent;
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
/// The bone armature node - used for skeleton conversion
|
||||
/// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode *mArmature;
|
||||
|
||||
/// The bone node in the scene - used for skeleton conversion
|
||||
/// you must enable aiProcess_PopulateArmatureData to populate this
|
||||
C_STRUCT aiNode *mNode;
|
||||
|
||||
#endif
|
||||
/// @brief The number of weights
|
||||
unsigned int mNumnWeights;
|
||||
|
||||
/// The influence weights of this bone, by vertex index.
|
||||
C_STRUCT aiVertexWeight *mWeights;
|
||||
|
||||
/** Matrix that transforms from bone space to mesh space in bind pose.
|
||||
*
|
||||
* This matrix describes the position of the mesh
|
||||
* in the local space of this bone when the skeleton was bound.
|
||||
* Thus it can be used directly to determine a desired vertex position,
|
||||
* given the world-space transform of the bone when animated,
|
||||
* and the position of the vertex in mesh space.
|
||||
*
|
||||
* It is sometimes called an inverse-bind matrix,
|
||||
* or inverse bind pose matrix.
|
||||
*/
|
||||
C_STRUCT aiMatrix4x4 mOffsetMatrix;
|
||||
|
||||
/// Matrix that transforms the locale bone in bind pose.
|
||||
C_STRUCT aiMatrix4x4 mLocalMatrix;
|
||||
|
||||
#ifdef __cplusplus
|
||||
aiSkeleton() AI_NO_EXCEPT : mName(), mNumWeights(0), mWeights(nullptr) {
|
||||
aiSkeletonBone() :
|
||||
mParent(-1),
|
||||
mArmature(nullptr),
|
||||
mNode(nullptr),
|
||||
mNumnWeights(0),
|
||||
mWeights(nullptr),
|
||||
mOffsetMatrix(),
|
||||
mLocalMatrix() {
|
||||
// empty
|
||||
}
|
||||
~aiSkeleton() {
|
||||
|
||||
~aiSkeletonBone() {
|
||||
delete[] mWeights;
|
||||
mWeights = nullptr;
|
||||
}
|
||||
#endif // __cplusplus
|
||||
};
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
struct aiSkeleton {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
C_STRUCT aiString mName;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
unsigned int mNumBones;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
C_STRUCT aiSkeletonBone *mBones;
|
||||
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
*
|
||||
*/
|
||||
aiSkeleton() AI_NO_EXCEPT : mName(), mNumBones(0), mBones(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
~aiSkeleton() {
|
||||
delete[] mBones;
|
||||
}
|
||||
#endif // __cplusplus
|
||||
};
|
||||
|
|
|
@ -343,6 +343,16 @@ struct aiScene
|
|||
*/
|
||||
C_STRUCT aiString mName;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
unsigned int mNumSkeletons;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
C_STRUCT aiSkeleton **mSkeletons;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
//! Default constructor - set everything to 0/nullptr
|
||||
|
@ -383,6 +393,10 @@ struct aiScene
|
|||
return mAnimations != nullptr && mNumAnimations > 0;
|
||||
}
|
||||
|
||||
bool hasSkeletons() const {
|
||||
return mSkeletons != nullptr && mNumSkeletons > 0;
|
||||
}
|
||||
|
||||
//! Returns a short filename from a full path
|
||||
static const char* GetShortFilename(const char* filename) {
|
||||
const char* lastSlash = strrchr(filename, '/');
|
||||
|
|
Loading…
Reference in New Issue