First concepts

kimkulling/create_skeleton_data_issue_4015
Kim Kulling 2022-04-05 20:07:22 +02:00
parent 7aa87a9765
commit e5747dad9b
8 changed files with 182 additions and 69 deletions

View File

@ -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,

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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,8 +195,9 @@ 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]);
}
}
// ------------------------------------------------------------------------------------------------

View File

@ -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
*

View File

@ -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,14 +319,27 @@ struct aiBone {
#endif
mWeights(nullptr),
mOffsetMatrix(other.mOffsetMatrix) {
if (other.mWeights && other.mNumWeights) {
mWeights = new aiVertexWeight[mNumWeights];
::memcpy(mWeights, other.mWeights, mNumWeights * sizeof(aiVertexWeight));
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) {
aiBone &operator = (const aiBone &other) {
if (this == &other) {
return *this;
}
@ -334,21 +347,13 @@ 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;
}
bool operator==(const aiBone &rhs) const {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights) {
if (mName != rhs.mName || mNumWeights != rhs.mNumWeights ) {
return false;
}
@ -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
};

View File

@ -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, '/');