Init commit

This commit is contained in:
2026-08-17 06:31:43 +09:00
commit 348d9275f6
428 changed files with 61806 additions and 0 deletions
+456
View File
@@ -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() <<
"\nNumWeights: " << bone->mNumWeights <<
"\nWeights[0].VertexID: " << bone->mWeights->mVertexId <<
"\nWeights[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() <<
"\nHasBones: " << std::boolalpha << am->HasBones() <<
"\nNumBones: " << am->mNumBones <<
"\nHasFaces: " << std::boolalpha << am->HasFaces() <<
"\nNumFaces: " << am->mNumFaces <<
"\nMinAABB:" << am->mAABB.mMin.x << am->mAABB.mMin.y << am->mAABB.mMin.z <<
"\nMaxAABB: " << am->mAABB.mMax.x << am->mAABB.mMax.y << am->mAABB.mMax.z <<
"\nHasNormals: " << std::boolalpha << am->HasNormals() <<
"\nHasPositions: " << std::boolalpha << am->HasPositions() <<
"\nHasVertexColors[0]: " << std::boolalpha << am->HasVertexColors(0) <<
"\nHasVertexColors[1]: " << std::boolalpha << am->HasVertexColors(1) <<
"\nGetNumColorChannels: " << am->GetNumColorChannels() <<
"\nMaterialIndex: " << am->mMaterialIndex <<
"\nNumAnimMeshes: " << 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 << " ++++++++" <<
"\nname: " << node->mName.C_Str() <<
"\nTsfMatrix:\n" << GetAiMatrixPrint(node->mTransformation) <<
"NumMeshes: " << node->mNumMeshes <<
"\nMeshIds: ";
for (unsigned int meshid: std::span(node->mMeshes, node->mNumMeshes)) {
std::cout << meshid << ' ';
}
std::cout << "\nSubNodeCount: " << 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中处理MeshmeshIdx=" << 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;
}
//