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:
@@ -14,19 +14,6 @@
|
||||
|
||||
namespace Engine {
|
||||
|
||||
namespace {
|
||||
// 欧拉(度)→ 旋转矩阵:应用序 Y→X,与 TransformComponent::
|
||||
// Compose 一致(roll 不参与 FPS/编辑器相机)
|
||||
glm::mat3 EulerRotMat(const glm::vec3& rotDeg)
|
||||
{
|
||||
return static_cast<glm::mat3>(
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotDeg.y),
|
||||
glm::vec3(0, 1, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(rotDeg.x),
|
||||
glm::vec3(1, 0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::Update(ECS::TransformComponent& transform,
|
||||
const f32 deltaTime, const bool flyRequiresRMB)
|
||||
{
|
||||
@@ -51,57 +38,66 @@ namespace Engine {
|
||||
|
||||
if (mouseDX != 0 || mouseDY != 0)
|
||||
{
|
||||
glm::vec3 rot = transform.GetRotation();
|
||||
// GetRotation 是 0-360 显示域(UE Details 约定);pitch 的
|
||||
// clamp 需要连续域,wrap 回 [-180,180)(yaw 同步处理,
|
||||
// 跨 ±180 继续累减不打折返)
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
rot[i] = std::fmod(rot[i], 360.0f);
|
||||
if (rot[i] >= 180.0f) rot[i] -= 360.0f;
|
||||
if (rot[i] < -180.0f) rot[i] += 360.0f;
|
||||
}
|
||||
// 右手系绕 Y 正角度 = 向左转,鼠标右移(DX>0)应看向右
|
||||
// → yaw 取负。pitch 正角度 = 抬头,鼠标下移(DY>0)低头
|
||||
// → rot.x 直接用负号,两者符号已核对一致
|
||||
rot.y -= mouseDX * m_MouseSensitivity;
|
||||
rot.x = glm::clamp(
|
||||
rot.x - mouseDY * m_MouseSensitivity, -89.0f, 89.0f);
|
||||
transform.SetRotation(rot);
|
||||
|
||||
if (wantOrbit)
|
||||
if (wantLook)
|
||||
{
|
||||
if (Input::IsKeyDown(Input::Key::LeftShift))
|
||||
// ---- 6DOF 真自由视角:pitch/yaw 各绕本地轴右乘增量
|
||||
// 四元数(q = q·Δyaw·Δpitch),无欧拉读改写、无
|
||||
// ±89° 钳制——可过顶/翻滚,存储层本就是四元数,
|
||||
// 不存在万向锁。符号沿用旧约定:鼠标右移向右看
|
||||
// (右手系绕 Y 正角向左 → yaw 取负)、鼠标下移
|
||||
// 低头(绕 X 正角抬头 → pitch 取负)----
|
||||
const glm::quat dyaw = glm::angleAxis(
|
||||
glm::radians(-mouseDX * m_MouseSensitivity),
|
||||
glm::vec3(0, 1, 0));
|
||||
const glm::quat dpitch = glm::angleAxis(
|
||||
glm::radians(-mouseDY * m_MouseSensitivity),
|
||||
glm::vec3(1, 0, 0));
|
||||
transform.SetRotationQuat(
|
||||
transform.GetRotationQuat() * dyaw * dpitch);
|
||||
}
|
||||
else if (Input::IsKeyDown(Input::Key::LeftShift))
|
||||
{
|
||||
// ---- 屏幕平面平移:内容跟手(拖右 → 相机左移、
|
||||
// 拖下 → 相机上移),pivot 同步平移保持环绕点的
|
||||
// 屏幕相对位置 ----
|
||||
const glm::mat3 r(transform.GetRotationQuat());
|
||||
const glm::vec3 delta =
|
||||
(-r * glm::vec3(1, 0, 0)) * mouseDX +
|
||||
(r * glm::vec3(0, 1, 0)) * mouseDY;
|
||||
const f32 k = m_OrbitDistance * 0.002f; // m/px
|
||||
transform.SetPosition(transform.GetPosition() + delta * k);
|
||||
if (m_HasPivot) m_OrbitPivot += delta * k;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ---- 焦点环绕:世界系左乘增量(yaw 绕世界 Y、pitch
|
||||
// 绕相机右轴),roll 保持不变;位置绕 pivot 同
|
||||
// 角度刚体旋转 → 到 pivot 距离恒定。首次环绕无
|
||||
// pivot:取当前视线上 m_OrbitDistance 处 ----
|
||||
if (!m_HasPivot)
|
||||
{
|
||||
// ---- 屏幕平面平移:内容跟手(拖右 → 相机左移、
|
||||
// 拖下 → 相机上移),pivot 同步平移保持环绕点的
|
||||
// 屏幕相对位置 ----
|
||||
const glm::mat3 r = EulerRotMat(rot);
|
||||
const glm::vec3 delta =
|
||||
(-r * glm::vec3(1, 0, 0)) * mouseDX +
|
||||
(r * glm::vec3(0, 1, 0)) * mouseDY;
|
||||
const f32 k = m_OrbitDistance * 0.002f; // m/px
|
||||
transform.SetPosition(transform.GetPosition() + delta * k);
|
||||
if (m_HasPivot) m_OrbitPivot += delta * k;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ---- 焦点环绕:转向后保持到 pivot 的距离。首次
|
||||
// 环绕无 pivot:取当前视线上 m_OrbitDistance 处
|
||||
if (!m_HasPivot)
|
||||
{
|
||||
m_OrbitPivot = transform.GetPosition() +
|
||||
EulerRotMat(transform.GetRotation()) *
|
||||
glm::vec3(0, 0, -1) *
|
||||
m_OrbitDistance;
|
||||
m_HasPivot = true;
|
||||
}
|
||||
m_OrbitDistance = glm::length(
|
||||
transform.GetPosition() - m_OrbitPivot);
|
||||
const glm::vec3 orbitFwd =
|
||||
EulerRotMat(rot) * glm::vec3(0, 0, -1);
|
||||
transform.SetPosition(m_OrbitPivot -
|
||||
orbitFwd * m_OrbitDistance);
|
||||
const glm::mat3 r(transform.GetRotationQuat());
|
||||
m_OrbitPivot = transform.GetPosition() +
|
||||
(r * glm::vec3(0, 0, -1)) *
|
||||
m_OrbitDistance;
|
||||
m_HasPivot = true;
|
||||
}
|
||||
const glm::vec3 offset =
|
||||
transform.GetPosition() - m_OrbitPivot;
|
||||
m_OrbitDistance = glm::length(offset);
|
||||
const glm::vec3 camRight =
|
||||
glm::mat3(transform.GetRotationQuat()) *
|
||||
glm::vec3(1, 0, 0);
|
||||
const glm::quat dq =
|
||||
glm::angleAxis(
|
||||
glm::radians(-mouseDX * m_MouseSensitivity),
|
||||
glm::vec3(0, 1, 0)) *
|
||||
glm::angleAxis(
|
||||
glm::radians(-mouseDY * m_MouseSensitivity),
|
||||
camRight);
|
||||
// 朝向与位置共用同一 dq:视线始终精确穿过 pivot
|
||||
transform.SetRotationQuat(dq * transform.GetRotationQuat());
|
||||
transform.SetPosition(m_OrbitPivot + dq * offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +107,7 @@ namespace Engine {
|
||||
}
|
||||
|
||||
// 基向量由(可能已更新的)实体旋转决定(本地 -Z 为视线方向)
|
||||
const glm::mat3 r = EulerRotMat(transform.GetRotation());
|
||||
const glm::mat3 r(transform.GetRotationQuat());
|
||||
const glm::vec3 forward = r * glm::vec3(0, 0, -1);
|
||||
const glm::vec3 right = r * glm::vec3(1, 0, 0);
|
||||
|
||||
@@ -150,7 +146,7 @@ namespace Engine {
|
||||
void Camera::FocusOn(ECS::TransformComponent& transform, const glm::vec3& point)
|
||||
{
|
||||
const glm::vec3 fwd =
|
||||
EulerRotMat(transform.GetRotation()) * glm::vec3(0, 0, -1);
|
||||
glm::mat3(transform.GetRotationQuat()) * glm::vec3(0, 0, -1);
|
||||
m_OrbitPivot = point;
|
||||
m_HasPivot = true;
|
||||
transform.SetPosition(point - fwd * m_OrbitDistance);
|
||||
@@ -162,16 +158,34 @@ namespace Engine {
|
||||
return glm::inverse(t.World());
|
||||
}
|
||||
|
||||
glm::mat4 Camera::GetProjection(const f32 aspect, const f32 nearZ, const f32 farZ) const
|
||||
glm::mat4 Camera::GetProjection(const f32 aspect) const
|
||||
{
|
||||
auto proj = glm::perspective(glm::radians(45.0f), aspect, nearZ, farZ);
|
||||
proj[1][1] *= -1.0f; // Vulkan Y 翻转
|
||||
glm::mat4 proj;
|
||||
if (m_ProjectionMode == ProjectionMode::Perspective)
|
||||
{
|
||||
proj = glm::perspective(glm::radians(m_FovDeg), aspect,
|
||||
m_NearZ, m_FarZ);
|
||||
proj[1][1] *= -1.0f; // Vulkan Y 翻转
|
||||
|
||||
// Vulkan clip 深度 [0,1]:z' = 0.5*z_clip + 0.5*w_clip。
|
||||
// perspective 的 w_clip = -z_eye,偏移折算进 z 系数
|
||||
//(注意:与 ortho 的公式不同,ortho 的 w=1 才能直接加到 [3][2])
|
||||
proj[2][2] = proj[2][2] * 0.5f - 0.5f;
|
||||
proj[3][2] *= 0.5f;
|
||||
// Vulkan clip 深度 [0,1]:z' = 0.5*z_clip + 0.5*w_clip。
|
||||
// perspective 的 w_clip = -z_eye,偏移折算进 z 系数
|
||||
proj[2][2] = proj[2][2] * 0.5f - 0.5f;
|
||||
proj[3][2] *= 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正交(Unity orthographic size 语义 = 半垂直高度):全宽由
|
||||
// 视口 aspect 推导,长宽比跟随视口永不变形
|
||||
const f32 halfH = m_OrthoSize;
|
||||
const f32 halfW = halfH * aspect;
|
||||
proj = glm::ortho(-halfW, halfW, -halfH, halfH, m_NearZ, m_FarZ);
|
||||
proj[1][1] *= -1.0f; // Vulkan Y 翻转(与透视同款)
|
||||
|
||||
// ortho 的 w_clip = 1:偏移直接加进平移分量
|
||||
//(与 ComputeCascades 光源正交投影同一公式)
|
||||
proj[2][2] *= 0.5f;
|
||||
proj[3][2] = proj[3][2] * 0.5f + 0.5f;
|
||||
}
|
||||
return proj;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user