阶段性合并:动画重定向、碎裂共享库、第三人称玩法、编辑器面板与 vendored ufbx
- 动画:HumanoidRig 三层架构(standard 标准槽 / dialects 方言映射 / mapper 配对), 指/趾统一走世界增量两遍式烘焙;AnimationAttach 拆为纯算法 + facade;修正 HumanoidBasis 行走基朝向与跨骨架去重、根运动通道 - 物理:CharacterController 角色互碰撞 / shapeOffset / 接触事件;PhysicsWorld 接触合成与 字符冲量判定 - 渲染与材质:Model 多材质按材质拆子 mesh 与贴图路径解析、DDS 直传、GLB 内嵌纹理落盘、 不透明通道 alpha 固定 1.0、glTF FlipUVs 对齐;SceneSerializer 支持 meshIndex 与材质覆盖 - 脚本:FractureLib 抽为共享库(HostView 桥接)、WallFracture 参数直绑、新增 ThirdPersonCamera / Follower / WASDMove 玩法;移除 GameDirector / PlayerController / Target - 编辑器:新增 GamepadPanel、LogPanel(LogRing),改进 Inspector / 材质 / 统计 / 视口面板 - 依赖:vendored ufbx(FBX 5.x/6.x/7.x 全版本解析,替代 assimp 对 FBX 6.1 的拒读)
This commit is contained in:
@@ -176,6 +176,10 @@ namespace Engine {
|
||||
// 直接成员会先于 call_once 构造 → 函数指针未注册 → SIGSEGV at 0x0
|
||||
m_DebugDraw = CreateScope<PhysicsDebugDraw>();
|
||||
|
||||
// 角色间碰撞互查表(内部 Array 走 JPH 分配器,须在 call_once 之后)
|
||||
m_VsCharacterCollision =
|
||||
CreateScope<JPH::CharacterVsCharacterCollisionSimple>();
|
||||
|
||||
m_TempAllocator = CreateScope<JPH::TempAllocatorImpl>(16 * 1024 * 1024);
|
||||
const u32 threads = std::max(1u, std::thread::hardware_concurrency() - 1);
|
||||
m_JobSystem = CreateScope<JPH::JobSystemThreadPool>(
|
||||
@@ -208,6 +212,7 @@ namespace Engine {
|
||||
// 释放烘焙几何——必须先于 UnregisterTypes
|
||||
m_DebugDraw.reset();
|
||||
m_Bodies.clear();
|
||||
m_Characters.clear(); // 角色析构回 m_VsCharacterCollision 摘除,先于 Jolt 反注册
|
||||
m_ContactListener.reset(); // 监听器先于 system 析构(持 m_Owner 引用)
|
||||
m_System.reset();
|
||||
// 单世界假设:进程退出时统一反注册(多世界时改为引用计数)
|
||||
@@ -695,20 +700,24 @@ namespace Engine {
|
||||
p.mass = cc.mass;
|
||||
p.maxSlopeAngle = cc.maxSlopeAngle;
|
||||
p.stepHeight = cc.stepHeight;
|
||||
p.shapeOffset = cc.shapeOffset;
|
||||
|
||||
auto found = m_Characters.find(bits);
|
||||
if (found == m_Characters.end()) {
|
||||
CharacterEntry entry;
|
||||
entry.cc = std::make_unique<CharacterController>(
|
||||
*m_System, p, tr.GetWorldPosition());
|
||||
entry.cc->SetCharacterCollision(*m_VsCharacterCollision);
|
||||
entry.lastPos = tr.GetWorldPosition();
|
||||
m_Characters.emplace(bits, std::move(entry));
|
||||
continue;
|
||||
}
|
||||
if (found->second.cc->GetParams() != p) {
|
||||
// 参数变更 → 重建(位置沿用当前 Transform)
|
||||
// 参数变更 → 重建(位置沿用当前 Transform);旧实例析构
|
||||
// 自动摘除旧条目,新实例重新登记
|
||||
found->second.cc = std::make_unique<CharacterController>(
|
||||
*m_System, p, tr.GetWorldPosition());
|
||||
found->second.cc->SetCharacterCollision(*m_VsCharacterCollision);
|
||||
found->second.lastPos = tr.GetWorldPosition();
|
||||
continue;
|
||||
}
|
||||
@@ -742,6 +751,42 @@ namespace Engine {
|
||||
static_cast<entt::entity>(bits), p,
|
||||
tr->GetWorldRotationQuat(), tr->GetWorldScale());
|
||||
entry.lastPos = p;
|
||||
|
||||
// ---- 角色碰撞事件合成(Enter/Exit)----
|
||||
// CharacterVirtual 非刚体,Jolt 的 ContactListener 不会为角色
|
||||
// 回调——脚本因此收不到"玩家撞墙"。这里读角色本步活跃接触,
|
||||
// 与上一步集合对比出边沿,合成与刚体同款的 CollisionEvent
|
||||
// (a = 角色实体,b = 被撞实体)。只处理刚体接触(mBodyB 有效):
|
||||
// 角色↔角色由 CharacterVsCharacterCollision 的物理互查处理,
|
||||
// 不发脚本事件(对方是角色时 mBodyB 无效,天然跳过)
|
||||
std::unordered_set<u32> now;
|
||||
now.reserve(entry.contacts.size() + 4);
|
||||
for (const JPH::CharacterContact& c :
|
||||
entry.cc->GetActiveContacts()) {
|
||||
if (c.mBodyB.IsInvalid()) continue; // 对方非刚体(角色)
|
||||
if (c.mWasDiscarded) continue; // 被丢弃/传感器
|
||||
if (c.mDistance > 0.0f) continue; // >0 = 预测接触,未真相交
|
||||
u32 other = 0;
|
||||
if (!TryBitsByBodyId(c.mBodyB, other)) continue;
|
||||
now.insert(other);
|
||||
if (entry.contacts.count(other) == 0) {
|
||||
const glm::vec3 pt(
|
||||
static_cast<f32>(c.mPosition.GetX()),
|
||||
static_cast<f32>(c.mPosition.GetY()),
|
||||
static_cast<f32>(c.mPosition.GetZ()));
|
||||
const glm::vec3 n(c.mContactNormal.GetX(),
|
||||
c.mContactNormal.GetY(),
|
||||
c.mContactNormal.GetZ());
|
||||
QueueEvent({bits, other, CollisionEvent::Kind::Added, pt, n});
|
||||
}
|
||||
}
|
||||
for (const u32 prev : entry.contacts) {
|
||||
if (now.count(prev) == 0) {
|
||||
QueueEvent(
|
||||
{bits, prev, CollisionEvent::Kind::Removed, {}, {}});
|
||||
}
|
||||
}
|
||||
entry.contacts = std::move(now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1124,6 +1169,14 @@ namespace Engine {
|
||||
: glm::vec3{0.0f};
|
||||
}
|
||||
|
||||
glm::vec3
|
||||
PhysicsWorld::GetCharacterImpactVelocity(const u32 entityBits) const {
|
||||
const auto found = m_Characters.find(entityBits);
|
||||
return found != m_Characters.end()
|
||||
? found->second.cc->GetSweepVelocity()
|
||||
: glm::vec3{0.0f};
|
||||
}
|
||||
|
||||
// ---- 写回:动态体姿态 → Transform(标脏,帧循环统一 Compose)----
|
||||
|
||||
void PhysicsWorld::Writeback() {
|
||||
|
||||
Reference in New Issue
Block a user