refactor: align scene view camera controls with unity
This commit is contained in:
@@ -35,6 +35,7 @@ struct SceneViewportInput {
|
||||
float mouseWheel = 0.0f;
|
||||
bool hovered = false;
|
||||
bool focused = false;
|
||||
bool looking = false;
|
||||
bool orbiting = false;
|
||||
bool panning = false;
|
||||
bool focusSelectionRequested = false;
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace XCEngine {
|
||||
namespace Editor {
|
||||
|
||||
struct SceneViewportCameraInputState {
|
||||
float lookDeltaX = 0.0f;
|
||||
float lookDeltaY = 0.0f;
|
||||
float orbitDeltaX = 0.0f;
|
||||
float orbitDeltaY = 0.0f;
|
||||
float panDeltaX = 0.0f;
|
||||
@@ -27,6 +29,7 @@ public:
|
||||
m_distance = 6.0f;
|
||||
m_yawDegrees = -35.0f;
|
||||
m_pitchDegrees = -20.0f;
|
||||
UpdatePositionFromFocalPoint();
|
||||
}
|
||||
|
||||
const Math::Vector3& GetFocalPoint() const {
|
||||
@@ -56,11 +59,12 @@ public:
|
||||
}
|
||||
|
||||
Math::Vector3 GetPosition() const {
|
||||
return m_focalPoint - GetForward() * m_distance;
|
||||
return m_position;
|
||||
}
|
||||
|
||||
void Focus(const Math::Vector3& point) {
|
||||
m_focalPoint = point;
|
||||
UpdatePositionFromFocalPoint();
|
||||
}
|
||||
|
||||
void ApplyInput(const SceneViewportCameraInputState& input) {
|
||||
@@ -68,28 +72,31 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::abs(input.zoomDelta) > Math::EPSILON) {
|
||||
const float zoomFactor = std::pow(0.85f, input.zoomDelta);
|
||||
m_distance = std::clamp(m_distance * zoomFactor, 0.5f, 500.0f);
|
||||
if (std::abs(input.lookDeltaX) > Math::EPSILON ||
|
||||
std::abs(input.lookDeltaY) > Math::EPSILON) {
|
||||
ApplyRotationDelta(input.lookDeltaX, input.lookDeltaY);
|
||||
UpdateFocalPointFromPosition();
|
||||
}
|
||||
|
||||
if (std::abs(input.orbitDeltaX) > Math::EPSILON ||
|
||||
std::abs(input.orbitDeltaY) > Math::EPSILON) {
|
||||
m_yawDegrees += input.orbitDeltaX * 0.30f;
|
||||
m_pitchDegrees = std::clamp(m_pitchDegrees - input.orbitDeltaY * 0.20f, -89.0f, 89.0f);
|
||||
ApplyRotationDelta(input.orbitDeltaX, input.orbitDeltaY);
|
||||
UpdatePositionFromFocalPoint();
|
||||
}
|
||||
|
||||
if (std::abs(input.panDeltaX) > Math::EPSILON ||
|
||||
std::abs(input.panDeltaY) > Math::EPSILON) {
|
||||
const Math::Vector3 forward = GetForward();
|
||||
const Math::Vector3 right = Math::Vector3::Normalize(
|
||||
Math::Vector3::Cross(Math::Vector3::Up(), forward));
|
||||
const Math::Vector3 up = Math::Vector3::Normalize(
|
||||
Math::Vector3::Cross(forward, right));
|
||||
|
||||
const float worldUnitsPerPixel =
|
||||
2.0f * m_distance * std::tan(60.0f * Math::DEG_TO_RAD * 0.5f) / input.viewportHeight;
|
||||
const Math::Vector3 right = GetRight();
|
||||
const Math::Vector3 up = GetUp();
|
||||
const float worldUnitsPerPixel = ComputeWorldUnitsPerPixel(input.viewportHeight);
|
||||
m_focalPoint += ((right * -input.panDeltaX) + (up * input.panDeltaY)) * worldUnitsPerPixel;
|
||||
m_position += ((right * -input.panDeltaX) + (up * input.panDeltaY)) * worldUnitsPerPixel;
|
||||
}
|
||||
|
||||
if (std::abs(input.zoomDelta) > Math::EPSILON) {
|
||||
const float zoomFactor = std::pow(0.85f, input.zoomDelta);
|
||||
m_distance = std::clamp(m_distance * zoomFactor, 0.5f, 500.0f);
|
||||
UpdatePositionFromFocalPoint();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +109,37 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void ApplyRotationDelta(float deltaX, float deltaY) {
|
||||
m_yawDegrees += deltaX * 0.30f;
|
||||
m_pitchDegrees = std::clamp(m_pitchDegrees - deltaY * 0.20f, -89.0f, 89.0f);
|
||||
}
|
||||
|
||||
Math::Vector3 GetRight() const {
|
||||
const Math::Vector3 right = Math::Vector3::Cross(Math::Vector3::Up(), GetForward());
|
||||
if (right.SqrMagnitude() <= Math::EPSILON) {
|
||||
return Math::Vector3::Right();
|
||||
}
|
||||
return Math::Vector3::Normalize(right);
|
||||
}
|
||||
|
||||
Math::Vector3 GetUp() const {
|
||||
return Math::Vector3::Normalize(Math::Vector3::Cross(GetForward(), GetRight()));
|
||||
}
|
||||
|
||||
float ComputeWorldUnitsPerPixel(float viewportHeight) const {
|
||||
return 2.0f * m_distance * std::tan(60.0f * Math::DEG_TO_RAD * 0.5f) / viewportHeight;
|
||||
}
|
||||
|
||||
void UpdatePositionFromFocalPoint() {
|
||||
m_position = m_focalPoint - GetForward() * m_distance;
|
||||
}
|
||||
|
||||
void UpdateFocalPointFromPosition() {
|
||||
m_focalPoint = m_position + GetForward() * m_distance;
|
||||
}
|
||||
|
||||
private:
|
||||
Math::Vector3 m_position = Math::Vector3::Zero();
|
||||
Math::Vector3 m_focalPoint = Math::Vector3::Zero();
|
||||
float m_distance = 6.0f;
|
||||
float m_yawDegrees = -35.0f;
|
||||
|
||||
@@ -92,6 +92,11 @@ public:
|
||||
controllerInput.viewportHeight = input.viewportSize.y;
|
||||
controllerInput.zoomDelta = input.hovered ? input.mouseWheel : 0.0f;
|
||||
|
||||
if (input.looking) {
|
||||
controllerInput.lookDeltaX = input.mouseDelta.x;
|
||||
controllerInput.lookDeltaY = input.mouseDelta.y;
|
||||
}
|
||||
|
||||
if (input.orbiting) {
|
||||
controllerInput.orbitDeltaX = input.mouseDelta.x;
|
||||
controllerInput.orbitDeltaY = input.mouseDelta.y;
|
||||
|
||||
@@ -239,14 +239,22 @@ void SceneViewPanel::Render() {
|
||||
const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
|
||||
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
|
||||
const ImGuiIO& io = ImGui::GetIO();
|
||||
if (!m_orbitDragging && content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||
const bool altDown = io.KeyAlt;
|
||||
|
||||
if (!m_lookDragging && content.hovered && !altDown && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||
m_lookDragging = true;
|
||||
}
|
||||
if (!m_orbitDragging && content.hovered && altDown && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
m_orbitDragging = true;
|
||||
}
|
||||
if (!m_panDragging && content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Middle)) {
|
||||
m_panDragging = true;
|
||||
}
|
||||
|
||||
if (m_orbitDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Right)) {
|
||||
if (m_lookDragging && (!ImGui::IsMouseDown(ImGuiMouseButton_Right) || altDown)) {
|
||||
m_lookDragging = false;
|
||||
}
|
||||
if (m_orbitDragging && (!ImGui::IsMouseDown(ImGuiMouseButton_Left) || !altDown)) {
|
||||
m_orbitDragging = false;
|
||||
}
|
||||
if (m_panDragging && !ImGui::IsMouseDown(ImGuiMouseButton_Middle)) {
|
||||
@@ -258,12 +266,13 @@ void SceneViewPanel::Render() {
|
||||
input.hovered = content.hovered;
|
||||
input.focused = content.focused;
|
||||
input.mouseWheel = content.hovered ? io.MouseWheel : 0.0f;
|
||||
input.looking = m_lookDragging;
|
||||
input.orbiting = m_orbitDragging;
|
||||
input.panning = m_panDragging;
|
||||
input.focusSelectionRequested =
|
||||
content.focused && !io.WantTextInput && ImGui::IsKeyPressed(ImGuiKey_F, false);
|
||||
|
||||
if (m_orbitDragging || m_panDragging) {
|
||||
if (m_lookDragging || m_orbitDragging || m_panDragging) {
|
||||
input.mouseDelta = io.MouseDelta;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ public:
|
||||
void Render() override;
|
||||
|
||||
private:
|
||||
bool m_lookDragging = false;
|
||||
bool m_orbitDragging = false;
|
||||
bool m_panDragging = false;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user