diff --git a/Engine/include/Engine/ECS/Components.h b/Engine/include/Engine/ECS/Components.h index e1ba268..1ede9e8 100644 --- a/Engine/include/Engine/ECS/Components.h +++ b/Engine/include/Engine/ECS/Components.h @@ -70,19 +70,28 @@ namespace Engine::ECS { // 90 → 89.98)。贴锁区改走组合角 atan2(分子分母同源缩放, // 比值稳定)→ 手输 90.0 显示 90.0。落入该窄区(±0.00057°) // 的真实 yaw/roll 被归并为组合角,UI 输入不可达,可接受 - if (std::abs(sp) < 1.0f - 1e-6f) { - return glm::degrees(glm::vec3( + glm::vec3 euler = std::abs(sp) < 1.0f - 1e-6f + ? glm::degrees(glm::vec3( std::asin(sp), std::atan2(R[2][0], R[2][2]), - std::atan2(R[0][1], R[1][1]))); + std::atan2(R[0][1], R[1][1]))) + : (sp > 0.0f + ? glm::vec3(90.0f, + glm::degrees(std::atan2(-R[0][2], R[1][2])), + 0.0f) + : glm::vec3(-90.0f, + glm::degrees(std::atan2(-R[0][2], -R[1][2])), + 0.0f)); + // 显示约定 = UE Details 的 0-360(-90 → 270)。逐轴 fmod wrap + // 与 [-180,180] 数学严格等价(每轴旋转周期 360°),矩阵重建类 + // 消费端(Camera::EulerRotMat 等)不受影响;需要连续域做 + // clamp/lerp 的调用方自行 wrap 回 [-180,180](如自由视角) + for (int i = 0; i < 3; ++i) { + euler[i] = std::fmod(euler[i], 360.0f); + if (euler[i] < 0.0f) euler[i] += 360.0f; + if (euler[i] >= 360.0f) euler[i] = 0.0f; // 浮点边界 } - // ±90° 万向锁:yaw/roll 只剩组合角,约定 roll=0(UE 同策略) - // 归入 yaw;两支组合角符号不同 - return sp > 0.0f - ? glm::vec3(90.0f, - glm::degrees(std::atan2(-R[0][2], R[1][2])), 0.0f) - : glm::vec3(-90.0f, - glm::degrees(std::atan2(-R[0][2], -R[1][2])), 0.0f); + return euler; } // ---- 写入(标脏,脏实体由 UpdateTransforms 重算)---- diff --git a/Engine/src/Renderer/Camera.cpp b/Engine/src/Renderer/Camera.cpp index 464df56..02d5052 100644 --- a/Engine/src/Renderer/Camera.cpp +++ b/Engine/src/Renderer/Camera.cpp @@ -52,6 +52,14 @@ 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 直接用负号,两者符号已核对一致