Add animation controller system, material assets and skeleton visualization

- .animctrl state machine asset (params/transitions/blend trees, 1D+2D
  directional blending) with Unity Animator-style editor panel: state
  list, transitions, params, directional pad preview driving live
  CrossFade on the selected entity
- Split animation evaluation out of SceneRenderer into
  AnimationSystem/AnimationEvaluator; skin palettes with rest-pose
  fallback and blend-weight epsilon filtering
- MaterialAsset (.material) with reload-safe preview tile pool
  (DropMaterial clears dirty refs before instance destruction)
- EditorGizmoPass skeleton wires + viewport joint overlay; camera
  projection rework (baked Vulkan Y-flip, ortho support)
- Editor/game build split via HELLOVULKAN_EDITOR option
This commit is contained in:
2026-10-07 01:50:04 +08:00
parent a941207ae3
commit cc837bc605
71 changed files with 8198 additions and 548 deletions
+55 -8
View File
@@ -3,6 +3,8 @@
//
#include "AssetBrowserPanel.h"
#include "MaterialEditorPanel.h" // kMaterialDragPayload + 双击打开材质编辑器
#include "ControllerEditorPanel.h" // kControllerDragPayload + 双击打开控制器编辑器
#include <Engine/Core/Log.h>
@@ -23,11 +25,12 @@ namespace {
constexpr const char* kRootPaths[] = {"assets", "scenes"};
// 类型过滤(下标即身份):0 = All
constexpr const char* kTypeNames[] = {"All", "Models", "Textures",
"Scenes"};
constexpr const char* kTypeNames[] = {"All", "Models",
"Textures", "Scenes",
"Materials", "Controllers"};
// 资产类别:按扩展名分派(过滤用)
enum class Kind { Model, Texture, Scene, Other };
enum class Kind { Model, Texture, Scene, Material, AnimClip, Other };
Kind KindOf(const std::filesystem::path& p)
{
@@ -48,6 +51,14 @@ namespace {
{
return Kind::Scene;
}
if (ext == ".material")
{
return Kind::Material;
}
if (ext == ".animctrl")
{
return Kind::AnimClip;
}
return Kind::Other;
}
@@ -58,6 +69,8 @@ namespace {
case 1: return kind == Kind::Model;
case 2: return kind == Kind::Texture;
case 3: return kind == Kind::Scene;
case 4: return kind == Kind::Material;
case 5: return kind == Kind::AnimClip;
default: return true;
}
}
@@ -70,6 +83,8 @@ namespace {
case Kind::Model: return "[M]";
case Kind::Texture: return "[T]";
case Kind::Scene: return "[S]";
case Kind::Material: return "[Ma]";
case Kind::AnimClip: return "[An]";
default: return "[ ]";
}
}
@@ -106,7 +121,7 @@ void AssetBrowserPanel::Draw(const EditorContext& ctx)
}
ImGui::SameLine();
ImGui::SetNextItemWidth(110.0f);
ImGui::Combo("##type", &m_TypeFilter, kTypeNames, 4);
ImGui::Combo("##type", &m_TypeFilter, kTypeNames, 6);
ImGui::SameLine();
ImGui::SetNextItemWidth(140.0f);
ImGui::InputTextWithHint("##name", "filter", m_NameFilter,
@@ -262,12 +277,41 @@ void AssetBrowserPanel::DrawFileList(const EditorContext& ctx,
ImGui::SameLine();
ImGui::Selectable(name.c_str());
// 双击预热:model/HDR 进缓存(路径去重,重复双击零成本);
// 场景加载含环境恢复/选中清理流程,提示走 File 菜单
// .material 拖拽源:拖到 Details 材质槽球上指派(kMaterialDragPayload)
if (item.kind == Kind::Material && ImGui::BeginDragDropSource())
{
ImGui::SetDragDropPayload(kMaterialDragPayload,
assetPath.c_str(), assetPath.size() + 1);
ImGui::TextUnformatted(name.c_str());
ImGui::EndDragDropSource();
}
// .animctrl 拖拽源:拖到 Details Controller 槽指派
//(kControllerDragPayload,对齐材质槽交互)
if (item.kind == Kind::AnimClip && ImGui::BeginDragDropSource())
{
ImGui::SetDragDropPayload(kControllerDragPayload,
assetPath.c_str(), assetPath.size() + 1);
ImGui::TextUnformatted(name.c_str());
ImGui::EndDragDropSource();
}
// 双击:.material 打开 Material Editor;.animctrl 打开
// Controller Editor;model/HDR 进缓存预热(路径去重,重复
// 双击零成本);场景加载含环境恢复/选中清理流程,提示走
// File 菜单
if (ImGui::IsItemHovered() &&
ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
if (item.kind == Kind::Model && ctx.assets)
if (item.kind == Kind::Material && ctx.materialEditor)
{
ctx.materialEditor->OpenAsset(assetPath);
}
else if (item.kind == Kind::AnimClip && ctx.controllerEditor)
{
ctx.controllerEditor->Open(assetPath);
}
else if (item.kind == Kind::Model && ctx.assets)
{
const auto ref = ctx.assets->LoadModel(assetPath);
ENGINE_INFO("AssetBrowser: model '{}' loaded (valid={})",
@@ -292,8 +336,11 @@ void AssetBrowserPanel::DrawFileList(const EditorContext& ctx,
ImGui::BeginTooltip();
ImGui::TextUnformatted(name.c_str());
ImGui::Separator();
// 与 Kind 枚举逐位对齐(Kind::Other = 5)——漏项 = tooltip
// 数组越界读
static const char* kKindNames[] = {"Model", "Texture/Environment",
"Scene", "File"};
"Scene", "Material",
"Controller", "File"};
ImGui::Text("type: %s", kKindNames[static_cast<int>(item.kind)]);
namespace fs = std::filesystem;
std::error_code ec;