@@ -0,0 +1,456 @@
// ReSharper disable CppDeclaratorNeverUsed
// ReSharper disable CppDFAUnreachableFunctionCall
# include "../include/zassimp/importer.h"
# include <assimp/scene.h>
# include <assimp/Importer.hpp>
# include <assimp/postprocess.h>
# include <Windows.h>
# include <iostream>
# include <span>
# include <utility>
namespace {
std : : string GetAiMatrixPrint ( const aiMatrix4x4 & am ) {
std : : stringstream ss ;
ss < < am . a1 < < " " < < am . a2 < < " " < < am . a3 < < " " < < am . a4 < < ' \n ' < <
am . b1 < < " " < < am . b2 < < " " < < am . b3 < < " " < < am . b4 < < ' \n ' < <
am . c1 < < " " < < am . c2 < < " " < < am . c3 < < " " < < am . c4 < < ' \n ' < <
am . d1 < < " " < < am . d2 < < " " < < am . d3 < < " " < < am . d4 < < std : : endl ;
return ss . str ( ) ;
}
void PrintAiBoneInfo ( const aiBone * bone ) {
std : : cout < < " Print Bone Info " < < std : : endl ;
std : : cout < < " Name: " < < bone - > mName . C_Str ( ) < <
// mArmature 是 “bone armature node”,用于 skeleton conversion,
// 并且必须启用 aiProcess_PopulateArmatureData 才会填充;
// 默认构造时它就是 nullptr
// "\nArmatureName: " << bone->mArmature->mName.C_Str() <<
// 这个东西是 DCC 场景图/transform hierarchy 的一部分。
// "\nNode->Name: " << bone->mNode->mName.C_Str() <<
" \n NumWeights: " < < bone - > mNumWeights < <
" \n Weights[0].VertexID: " < < bone - > mWeights - > mVertexId < <
" \n Weights[0].Weight: " < < bone - > mWeights - > mWeight < <
std : : endl ;
}
void PrintAiMeshInfo ( const aiMesh * am ) {
std : : cout < < " ======== Print AiMesh Info ======== " < < std : : endl ;
std : : cout < < " Name: " < < am - > mName . C_Str ( ) < <
" \n HasBones: " < < std : : boolalpha < < am - > HasBones ( ) < <
" \n NumBones: " < < am - > mNumBones < <
" \n HasFaces: " < < std : : boolalpha < < am - > HasFaces ( ) < <
" \n NumFaces: " < < am - > mNumFaces < <
" \n MinAABB: " < < am - > mAABB . mMin . x < < am - > mAABB . mMin . y < < am - > mAABB . mMin . z < <
" \n MaxAABB: " < < am - > mAABB . mMax . x < < am - > mAABB . mMax . y < < am - > mAABB . mMax . z < <
" \n HasNormals: " < < std : : boolalpha < < am - > HasNormals ( ) < <
" \n HasPositions: " < < std : : boolalpha < < am - > HasPositions ( ) < <
" \n HasVertexColors[0]: " < < std : : boolalpha < < am - > HasVertexColors ( 0 ) < <
" \n HasVertexColors[1]: " < < std : : boolalpha < < am - > HasVertexColors ( 1 ) < <
" \n GetNumColorChannels: " < < am - > GetNumColorChannels ( ) < <
" \n MaterialIndex: " < < am - > mMaterialIndex < <
" \n NumAnimMeshes: " < < am - > mNumAnimMeshes < <
std : : endl ;
for ( size_t i = 0 ; i < am - > mNumBones ; + + i ) {
PrintAiBoneInfo ( am - > mBones [ i ] ) ;
}
}
int curNodeLevel = 0 ;
void RecursePrintAiNodeInfo ( const aiNode * node ) {
curNodeLevel + + ;
std : : cout < < " ++++++++ recurse print node LEVEL= " < < curNodeLevel < < " ++++++++ " < <
" \n name: " < < node - > mName . C_Str ( ) < <
" \n TsfMatrix: \n " < < GetAiMatrixPrint ( node - > mTransformation ) < <
" NumMeshes: " < < node - > mNumMeshes < <
" \n MeshIds: " ;
for ( unsigned int meshid : std : : span ( node - > mMeshes , node - > mNumMeshes ) ) {
std : : cout < < meshid < < ' ' ;
}
std : : cout < < " \n SubNodeCount: " < < node - > mNumChildren < < std : : endl ;
for ( auto * subnode : std : : span ( node - > mChildren , node - > mNumChildren ) ) {
RecursePrintAiNodeInfo ( subnode ) ;
}
curNodeLevel - - ;
}
constexpr unsigned int GetFlag_Simple ( ) {
return aiProcess_Triangulate | aiProcess_FlipUVs ;
}
constexpr unsigned int GetFlag_Smooth ( ) {
return aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_GenSmoothNormals |
aiProcess_CalcTangentSpace |
aiProcess_ImproveCacheLocality |
aiProcess_OptimizeMeshes |
aiProcess_SortByPType |
aiProcess_FindInvalidData |
aiProcess_FindDegenerates |
aiProcess_MakeLeftHanded |
aiProcess_FlipUVs |
aiProcess_FlipWindingOrder |
aiProcess_ConvertToLeftHanded ;
}
constexpr unsigned int GetFlag_NoSmoothNormal ( ) {
return aiProcess_Triangulate |
aiProcess_JoinIdenticalVertices |
aiProcess_CalcTangentSpace |
aiProcess_ImproveCacheLocality |
aiProcess_OptimizeMeshes |
aiProcess_SortByPType |
aiProcess_FindInvalidData |
aiProcess_FindDegenerates |
aiProcess_MakeLeftHanded |
aiProcess_FlipUVs |
aiProcess_FlipWindingOrder |
aiProcess_ConvertToLeftHanded ;
}
// DirectX::XMFLOAT4X4 AiToFloat4x4(const aiMatrix4x4 &ai) {
// return {
// ai.a1, ai.a2, ai.a3, ai.a4,
// ai.b1, ai.b2, ai.b3, ai.b4,
// ai.c1, ai.c2, ai.c3, ai.c4,
// ai.d1, ai.d2, ai.d3, ai.d4
// };
// }
DirectX : : XMFLOAT4X4 AiToRowMajorFloat4x4 ( const aiMatrix4x4 & m ) {
return {
m . a1 , m . b1 , m . c1 , m . d1 ,
m . a2 , m . b2 , m . c2 , m . d2 ,
m . a3 , m . b3 , m . c3 , m . d3 ,
m . a4 , m . b4 , m . c4 , m . d4
} ;
}
DirectX : : XMFLOAT4X4 InverseFloat4x4 ( const DirectX : : XMFLOAT4X4 & origin ) {
using namespace DirectX ;
XMMATRIX m = XMLoadFloat4x4 ( & origin ) ;
m = XMMatrixInverse ( nullptr , m ) ;
XMFLOAT4X4 result { } ;
XMStoreFloat4x4 ( & result , m ) ;
return result ;
}
class Processor {
public :
explicit Processor ( std : : filesystem : : path path ,
const aiScene * scene ) : modelPath ( std : : move ( path ) ) ,
m_scene ( scene ) { }
Z : : Model * ProcessAiScene ( ) {
m_model = new Z : : Model { } ;
// m_model->name = m_scene->mName.C_Str();
// m_model->name = modelPath.string();
std : : u8string u8 = modelPath . u8string ( ) ;
m_model - > name = { reinterpret_cast < const char * > ( u8 . c_str ( ) ) , u8 . size ( ) } ;
m_model - > path = modelPath ;
// 创建MeshData,顺序映射 aiScene->mMeshes 数组
m_model - > ar_meshDatas . reserve ( m_scene - > mNumMeshes ) ;
int _i = 0 ;
for ( const aiMesh * am : std : : span ( m_scene - > mMeshes , m_scene - > mNumMeshes ) ) {
m_model - > ar_meshDatas . push_back ( CreateMeshData ( am , _i ) ) ;
_i + + ;
}
// 处理NodeTree
m_model - > skeletonData . rootNode = BuildBoneNodeTree ( m_scene - > mRootNode ) ;
m_model - > skeletonData . gInvTsf =
InverseFloat4x4 ( AiToRowMajorFloat4x4 ( m_scene - > mRootNode - > mTransformation ) ) ;
// 填充 AnimationClip
if ( m_scene - > HasAnimations ( ) ) {
m_model - > ar_animationClips . reserve ( m_scene - > mNumAnimations ) ;
for ( const auto * aiAnim : std : : span ( m_scene - > mAnimations , m_scene - > mNumAnimations ) ) {
m_model - > ar_animationClips . emplace_back ( FillAnimClip ( aiAnim ) ) ;
}
}
return m_model ;
}
private :
//region 创建MeshData,建立Bone的索引表,递归创建skeleten data
Z : : Mesh CreateMeshData ( const aiMesh * am , int index ) const {
Z : : Mesh mesh { } ;
mesh . index = index ;
mesh . name = am - > mName . C_Str ( ) ;
//装填material data
// mesh.material = LoadMaterialData(am);
// mesh.material=nullptr;
//装填vertex data
const uint32_t c_vert = am - > mNumVertices ;
mesh . ar_vertices . reserve ( c_vert ) ;
for ( uint32_t i = 0 ; i < c_vert ; + + i ) {
Z : : VertexData vert { } ;
vert . ar_boneIndex . fill ( - 1 ) ;
vert . pos = { am - > mVertices [ i ] . x , am - > mVertices [ i ] . y , am - > mVertices [ i ] . z } ;
if ( am - > HasNormals ( ) ) {
vert . normal = { am - > mNormals [ i ] . x , am - > mNormals [ i ] . y , am - > mNormals [ i ] . z } ;
}
if ( am - > HasTangentsAndBitangents ( ) ) {
vert . tangent = { am - > mTangents [ i ] . x , am - > mTangents [ i ] . y , am - > mTangents [ i ] . z } ;
}
if ( am - > HasTextureCoords ( 0 ) ) {
vert . uv0 = { am - > mTextureCoords [ 0 ] [ i ] . x , am - > mTextureCoords [ 0 ] [ i ] . y } ;
}
if ( am - > HasTextureCoords ( 1 ) ) {
vert . uv1 = { am - > mTextureCoords [ 1 ] [ i ] . x , am - > mTextureCoords [ 1 ] [ i ] . y } ;
}
if ( am - > HasVertexColors ( 0 ) ) {
vert . color = {
am - > mColors [ 0 ] [ i ] . r , am - > mColors [ 0 ] [ i ] . g ,
am - > mColors [ 0 ] [ i ] . b , am - > mColors [ 0 ] [ i ] . a
} ;
}
mesh . ar_vertices . push_back ( vert ) ;
}
// 构建bone name <-> IDX 表,并填写每个Vertex的骨骼ID,对应权重
for ( auto * bone : std : : span ( am - > mBones , am - > mNumBones ) ) {
if ( bone - > mNumWeights > 0 ) {
mesh . hasSkin = true ;
UINT boneID = GetOrCreateBoneID ( bone ) ;
std : : cout < < " = = = = 创建Mesh阶段读取aiMesh->mBones[],aiBone->name= " < <
bone - > mName . C_Str ( ) < < " BoneNumWeights= " < < bone - > mNumWeights < <
" 当前BoneID= " < < boneID < < std : : endl ;
for ( aiVertexWeight & vWeight : std : : span ( bone - > mWeights , bone - > mNumWeights ) ) {
auto & vert = mesh . ar_vertices [ vWeight . mVertexId ] ;
for ( int i = 0 ; i < Z : : MAX_BONES_PER_VERT ; + + i ) {
if ( vert . ar_boneIndex [ i ] = = - 1 ) {
vert . ar_boneIndex [ i ] = static_cast < int > ( boneID ) ;
vert . ar_boneWeights [ i ] = vWeight . mWeight ;
break ;
}
}
}
}
}
//装填 INDICES DATA
mesh . ar_indices . reserve ( am - > mNumFaces * 3 ) ;
for ( const auto & face : std : : span ( am - > mFaces , am - > mNumFaces ) ) {
if ( face . mNumIndices ! = 3 ) continue ;
mesh . ar_indices . push_back ( face . mIndices [ 0 ] ) ;
mesh . ar_indices . push_back ( face . mIndices [ 1 ] ) ;
mesh . ar_indices . push_back ( face . mIndices [ 2 ] ) ;
}
return mesh ;
}
// Z::MaterialData LoadMaterialData(const aiMesh *am) const {
// Z::MaterialData out{};
// if (!am || am->mMaterialIndex >= m_scene->mNumMaterials) return out;
//
// aiMaterial *mat = m_scene->mMaterials[am->mMaterialIndex];
//
// out.name = mat->GetName().C_Str();
//
// // // baseColor: PBR 优先
// // aiColor4D base{};
// // if (mat->Get(AI_MATKEY_BASE_COLOR, base) == AI_SUCCESS) {
// // out.baseColor = {base.r, base.g, base.b, base.a};
// // } else {
// // // fallback: 老式 diffuse
// // aiColor3D diff{};
// // if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, diff) == AI_SUCCESS) {
// // out.baseColor = {diff.r, diff.g, diff.b, 1.0f};
// // }
// // }
//
// auto LoadTextures = [&](aiTextureType type) {
// const unsigned int n = mat->GetTextureCount(type);
//
// for (unsigned int i = 0; i < n; ++i) {
// aiString path;
// if (mat->GetTexture(type, i, &path) != AI_SUCCESS) continue;
//
// Z::TextureData tex{};
// tex.path = path.C_Str();
// tex.type = static_cast<Z::TextureType>(type);
//
// out.ar_textures.push_back(std::move(tex));
// }
// };
//
// // 常用纹理
// LoadTextures(aiTextureType_BASE_COLOR); // PBR base color / albedo
// LoadTextures(aiTextureType_DIFFUSE); // 传统 diffuse
// LoadTextures(aiTextureType_NORMALS); // normal
// LoadTextures(aiTextureType_HEIGHT); // 有些格式把 normal 放这里
// LoadTextures(aiTextureType_SPECULAR); // specular
// LoadTextures(aiTextureType_METALNESS); // metallic
// LoadTextures(aiTextureType_DIFFUSE_ROUGHNESS); // roughness
// LoadTextures(aiTextureType_AMBIENT_OCCLUSION); // ao
// LoadTextures(aiTextureType_EMISSIVE); // emissive
//
// return out;
// }
UINT GetOrCreateBoneID ( const aiBone * bone ) const {
auto * name = bone - > mName . C_Str ( ) ;
auto idx = 0 ;
auto & arr = m_model - > skeletonData . ar_boneInfo ;
for ( auto it = arr . begin ( ) ; it ! = arr . end ( ) ; + + it ) {
if ( it - > name = = name ) {
return idx ;
}
idx + + ;
}
arr . push_back ( { name , AiToRowMajorFloat4x4 ( bone - > mOffsetMatrix ) } ) ;
idx = static_cast < int > ( arr . size ( ) - 1 ) ;
m_model - > skeletonData . map_boneName_idx . emplace ( name , idx ) ;
return idx ;
}
// 处理skeleton[0] 的 NodeTree
Z : : Node BuildBoneNodeTree ( const aiNode * an ) {
Z : : Node node { } ;
node . name = an - > mName . C_Str ( ) ;
std : : cout < < " + + + + 正在递归处理NodeTree,当前node.name= " < < node . name < < std : : endl ;
node . localTsf = AiToRowMajorFloat4x4 ( an - > mTransformation ) ;
// 处理mesh
for ( UINT meshIdx : std : : span ( an - > mMeshes , an - > mNumMeshes ) ) {
Z : : Mesh * meshData = & m_model - > ar_meshDatas [ meshIdx ] ;
std : : cout < < " + + Node中处理Mesh, meshIdx= " < < meshIdx < <
" , MeshData.Name= " < < meshData - > name < < std : : endl ;
meshData - > localTsf = AiToRowMajorFloat4x4 ( an - > mTransformation ) ; //非骨骼模型的统一偏移矩阵
}
int cc = static_cast < int > ( an - > mNumChildren ) ;
node . ar_child . reserve ( cc ) ;
for ( int i = 0 ; i < cc ; + + i ) {
node . ar_child . push_back ( BuildBoneNodeTree ( an - > mChildren [ i ] ) ) ;
}
return node ;
}
//endregion
//region 填充 AnimationClip
static DirectX : : XMFLOAT3 AiVector3ToXMFloat3 ( const aiVector3D & vec3 ) {
return { vec3 . x , vec3 . y , vec3 . z } ;
}
static DirectX : : XMFLOAT4 AiVector4ToXMFloat4 ( const aiQuaternion & vec4 ) {
return { vec4 . x , vec4 . y , vec4 . z , vec4 . w } ;
}
static Z : : AnimationClip FillAnimClip ( const aiAnimation * ai ) {
Z : : AnimationClip anim { } ;
anim . name = ai - > mName . C_Str ( ) ;
anim . durationTicks = ai - > mDuration ;
anim . tickPerSec = ai - > mTicksPerSecond ;
anim . map_channels . reserve ( ai - > mNumChannels ) ;
for ( int i = 0 ; i < ai - > mNumChannels ; + + i ) {
aiNodeAnim * c = ai - > mChannels [ i ] ;
Z : : NodeAnimation nodeAnim { } ;
nodeAnim . name = ai - > mName . C_Str ( ) ;
nodeAnim . ar_posKeys . reserve ( c - > mNumPositionKeys ) ;
for ( int j = 0 ; j < c - > mNumPositionKeys ; + + j ) {
nodeAnim . ar_posKeys . emplace_back (
c - > mPositionKeys [ j ] . mTime , AiVector3ToXMFloat3 ( c - > mPositionKeys [ j ] . mValue ) ) ;
}
nodeAnim . ar_rotationKeys . reserve ( c - > mNumRotationKeys ) ;
for ( int j = 0 ; j < c - > mNumRotationKeys ; + + j ) {
nodeAnim . ar_rotationKeys . emplace_back (
c - > mRotationKeys [ j ] . mTime , AiVector4ToXMFloat4 ( c - > mRotationKeys [ j ] . mValue ) ) ;
}
nodeAnim . ar_scaleKeys . reserve ( c - > mNumScalingKeys ) ;
for ( int j = 0 ; j < c - > mNumScalingKeys ; + + j ) {
nodeAnim . ar_scaleKeys . emplace_back (
c - > mScalingKeys [ j ] . mTime , AiVector3ToXMFloat3 ( c - > mScalingKeys [ j ] . mValue ) ) ;
}
anim . map_channels . emplace ( std : : string { c - > mNodeName . C_Str ( ) } , std : : move ( nodeAnim ) ) ;
}
return anim ;
}
//endregion
private :
const std : : filesystem : : path modelPath ;
const aiScene * const m_scene ;
Z : : Model * m_model { } ;
} ;
}
bool Importer : : ImportFromFile ( const std : : filesystem : : path & path , Z : : Model * * out ) const {
// 导入器
Assimp : : Importer importer ;
// 导入前配置选项
// 打开FBX单位从 cm->m 的转换开关
importer . SetPropertyBool ( AI_CONFIG_FBX_CONVERT_TO_M , true ) ;
// 设置全局缩放因子
// importer.SetPropertyFloat(AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 0.01f);
// 导入文件,初步处理
const aiScene * scene = importer . ReadFile (
reinterpret_cast < const char * > ( path . u8string ( ) . c_str ( ) ) ,
GetFlag_NoSmoothNormal ( ) | aiProcess_GlobalScale ) ;
// 导入后验证
if ( ! scene | | scene - > mFlags & AI_SCENE_FLAGS_INCOMPLETE | | ! scene - > mRootNode ) {
MessageBox ( nullptr , L " Error " , L " Assimp ReadFile Error " , MB_OK ) ;
return false ;
}
// for (auto *am: std::span(scene->mMeshes, scene->mNumMeshes)) {
// for (int i = 0; i < am->mNumBones; ++i) {
// aiBone *bone = am->mBones[i];
// std::cout << "BoneName = " << bone->mName.C_Str() <<
// "\nNumWeights = " << bone->mNumWeights << std::endl;
// }
// }
// RecursePrintAiNodeInfo(scene->mRootNode);
Processor pro ( path , scene ) ;
* out = pro . ProcessAiScene ( ) ;
return true ;
}
void Importer : : ReleaseLoadedModel ( const Z : : Model * model ) const {
delete model ;
}
//