Skip to content

Commit 4d0afae

Browse files
author
Adrien GIVRY
committed
Translation, rotation and scale works fine now
1 parent e2f59b6 commit 4d0afae

4 files changed

Lines changed: 222 additions & 30 deletions

File tree

Sources/Overload/OvEditor/include/OvEditor/Core/GuizmoOperations.h

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,41 @@ namespace OvEditor::Core
1414
class GuizmoOperations
1515
{
1616
public:
17+
enum class EOperation
18+
{
19+
TRANSLATION,
20+
ROTATION,
21+
SCALE
22+
};
23+
24+
enum class EDirection
25+
{
26+
X,
27+
Y,
28+
Z
29+
};
30+
1731
/**
1832
* Starts the guizmo picking behaviour for the given target in the given direction
1933
* @param p_actor
20-
* @param p_direction
2134
* @param p_cameraPosition
35+
* @param p_operation
36+
* @param p_direction
2237
*/
23-
void StartPicking(OvCore::ECS::Actor& p_target, const OvMaths::FVector3& p_direction, const OvMaths::FVector3& p_cameraPosition);
38+
void StartPicking(OvCore::ECS::Actor& p_target, const OvMaths::FVector3& p_cameraPosition, EOperation p_operation, EDirection p_direction);
2439

2540
/**
2641
* Stops the guizmo picking behaviour
2742
*/
2843
void StopPicking();
2944

3045
/**
31-
* Handle the translation behaviour
46+
* Handle the current behaviour
3247
* @param p_viewMatrix
3348
* @param p_projectionMatrix
3449
* @param p_viewSize
3550
*/
36-
void ApplyTranslation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const;
51+
void ApplyOperation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize);
3752

3853
/**
3954
* Set the given mouse position as the current mouse position and update the previous mouse position
@@ -46,12 +61,59 @@ namespace OvEditor::Core
4661
*/
4762
bool IsPicking() const;
4863

64+
private:
65+
/**
66+
* Returns the global direction matching with the current m_direction
67+
*/
68+
OvMaths::FVector3 GetFakeDirection() const;
69+
70+
/**
71+
* Returns the actual direction of the target matching with the current m_direction
72+
* @param p_relative (If true, the direction depends on hierarchy)
73+
*/
74+
OvMaths::FVector3 GetRealDirection(bool p_relative = false) const;
75+
76+
/**
77+
* Returns the 3D vector of the arrow projected to the screen
78+
* @param p_viewMatrix
79+
* @param p_projectionMatrix
80+
* @param p_viewSize
81+
*/
82+
OvMaths::FVector2 GetScreenDirection(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const;
83+
84+
/**
85+
* Handle the translation behaviour
86+
* @param p_viewMatrix
87+
* @param p_projectionMatrix
88+
* @param p_viewSize
89+
*/
90+
void ApplyTranslation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const;
91+
92+
/**
93+
* Handle the rotation behaviour
94+
* @param p_viewMatrix
95+
* @param p_projectionMatrix
96+
* @param p_viewSize
97+
*/
98+
void ApplyRotation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const;
99+
100+
/**
101+
* Handle the scale behaviour
102+
* @param p_viewMatrix
103+
* @param p_projectionMatrix
104+
* @param p_viewSize
105+
*/
106+
void ApplyScale(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const;
107+
49108
private:
50109
bool m_firstMouse = true;
51110
float m_distanceToActor = 0.0f;
52111
OvCore::ECS::Actor* m_target;
53-
OvMaths::FVector3 m_direction;
54-
OvMaths::FVector2 m_previousMouse;
112+
EOperation m_currentOperation;
113+
EDirection m_direction;
114+
OvMaths::FTransform m_originalTransform;
115+
OvMaths::FVector2 m_originMouse;
55116
OvMaths::FVector2 m_currentMouse;
117+
OvMaths::FVector2 m_screenDirection;
56118
};
57119
}

Sources/Overload/OvEditor/include/OvEditor/Panels/SceneView.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ namespace OvEditor::Panels
2727
const OvUI::Settings::PanelWindowSettings& p_windowSettings
2828
);
2929

30+
/**
31+
* Update the scene view
32+
*/
33+
virtual void Update(float p_deltaTime) override;
34+
3035
/**
3136
* Custom implementation of the render method
3237
*/
@@ -52,5 +57,6 @@ namespace OvEditor::Panels
5257
OvCore::SceneSystem::SceneManager& m_sceneManager;
5358
OvRendering::Buffers::Framebuffer m_actorPickingFramebuffer;
5459
OvEditor::Core::GuizmoOperations m_guizmoOperations;
60+
OvEditor::Core::GuizmoOperations::EOperation m_currentOperation = OvEditor::Core::GuizmoOperations::EOperation::TRANSLATION;
5561
};
5662
}

Sources/Overload/OvEditor/src/OvEditor/Core/GuizmoOperations.cpp

Lines changed: 122 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,71 +6,173 @@
66

77
#include "OvEditor/Core/GuizmoOperations.h"
88

9-
void OvEditor::Core::GuizmoOperations::StartPicking(OvCore::ECS::Actor& p_target, const OvMaths::FVector3& p_direction, const OvMaths::FVector3& p_cameraPosition)
9+
void OvEditor::Core::GuizmoOperations::StartPicking(OvCore::ECS::Actor& p_target, const OvMaths::FVector3& p_cameraPosition, EOperation p_operation, EDirection p_direction)
1010
{
1111
m_target = &p_target;
12-
m_direction = p_direction;
1312
m_firstMouse = true;
13+
m_originalTransform = p_target.transform.GetFTransform();
1414
m_distanceToActor = OvMaths::FVector3::Distance(p_cameraPosition, m_target->transform.GetWorldPosition());
15-
15+
m_currentOperation = p_operation;
16+
m_direction = p_direction;
1617
}
1718

1819
void OvEditor::Core::GuizmoOperations::StopPicking()
1920
{
2021
m_target = nullptr;
2122
}
2223

23-
void OvEditor::Core::GuizmoOperations::ApplyTranslation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const
24+
OvMaths::FVector3 OvEditor::Core::GuizmoOperations::GetFakeDirection() const
2425
{
25-
float unitsPerPixel = 0.001f;
26+
auto result = OvMaths::FVector3();
27+
28+
switch (m_direction)
29+
{
30+
case OvEditor::Core::GuizmoOperations::EDirection::X:
31+
result = OvMaths::FVector3::Right;
32+
break;
33+
case OvEditor::Core::GuizmoOperations::EDirection::Y:
34+
result = OvMaths::FVector3::Up;
35+
break;
36+
case OvEditor::Core::GuizmoOperations::EDirection::Z:
37+
result = OvMaths::FVector3::Forward;
38+
break;
39+
}
2640

41+
return result;
42+
}
43+
44+
OvMaths::FVector3 OvEditor::Core::GuizmoOperations::GetRealDirection(bool p_relative) const
45+
{
46+
auto result = OvMaths::FVector3();
47+
48+
switch (m_direction)
49+
{
50+
case OvEditor::Core::GuizmoOperations::EDirection::X:
51+
result = p_relative ? m_originalTransform.GetWorldRight() : m_originalTransform.GetLocalRight();
52+
break;
53+
case OvEditor::Core::GuizmoOperations::EDirection::Y:
54+
result = p_relative ? m_originalTransform.GetWorldUp() : m_originalTransform.GetLocalUp();
55+
break;
56+
case OvEditor::Core::GuizmoOperations::EDirection::Z:
57+
result = p_relative ? m_originalTransform.GetWorldForward() : m_originalTransform.GetLocalForward();
58+
break;
59+
}
60+
61+
return result;
62+
}
63+
64+
OvMaths::FVector2 OvEditor::Core::GuizmoOperations::GetScreenDirection(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const
65+
{
2766
auto start = m_target->transform.GetWorldPosition();
28-
auto end = m_target->transform.GetWorldPosition() + m_direction;
29-
auto result = OvMaths::FVector2();
67+
auto end = m_target->transform.GetWorldPosition() + GetRealDirection(true);
3068

69+
auto start2D = OvMaths::FVector2();
3170
{
32-
auto clipSpacePos = p_projectionMatrix * (p_viewMatrix * OvMaths::FVector4{ end.x, end.y, end.z, 1.0f });
71+
auto clipSpacePos = p_projectionMatrix * (p_viewMatrix * OvMaths::FVector4{ start.x, start.y, start.z, 1.0f });
3372
auto ndcSpacePos = OvMaths::FVector3{ clipSpacePos.x, clipSpacePos.y, clipSpacePos.z } / clipSpacePos.w;
3473
auto windowSpacePos = ((OvMaths::FVector2{ ndcSpacePos.x, ndcSpacePos.y } +1.0) / 2.0);
3574
windowSpacePos.x *= p_viewSize.x;
3675
windowSpacePos.y *= p_viewSize.y;
37-
result = windowSpacePos;
76+
start2D = windowSpacePos;
3877
}
3978

79+
auto end2D = OvMaths::FVector2();
4080
{
41-
auto clipSpacePos = p_projectionMatrix * (p_viewMatrix * OvMaths::FVector4{ start.x, start.y, start.z, 1.0f });
81+
auto clipSpacePos = p_projectionMatrix * (p_viewMatrix * OvMaths::FVector4{ end.x, end.y, end.z, 1.0f });
4282
auto ndcSpacePos = OvMaths::FVector3{ clipSpacePos.x, clipSpacePos.y, clipSpacePos.z } / clipSpacePos.w;
4383
auto windowSpacePos = ((OvMaths::FVector2{ ndcSpacePos.x, ndcSpacePos.y } +1.0) / 2.0);
4484
windowSpacePos.x *= p_viewSize.x;
4585
windowSpacePos.y *= p_viewSize.y;
46-
result -= windowSpacePos;
86+
end2D = windowSpacePos;
4787
}
4888

49-
result.y *= -1;
50-
result = OvMaths::FVector2::Normalize(result);
89+
auto result = end2D - start2D;
90+
91+
result.y *= -1; // Screen coordinates are reversed, so we inverse the Y
92+
93+
return OvMaths::FVector2::Normalize(result);
94+
}
95+
96+
void OvEditor::Core::GuizmoOperations::ApplyTranslation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const
97+
{
98+
auto unitsPerPixel = 0.001f * m_distanceToActor;
99+
auto originPosition = m_originalTransform.GetLocalPosition();
51100

52-
auto displacement = m_currentMouse - m_previousMouse;
101+
auto screenDirection = GetScreenDirection(p_viewMatrix, p_projectionMatrix, p_viewSize);
53102

54-
auto translationUnit = OvMaths::FVector2::Dot(displacement, result);
55-
56-
m_target->transform.TranslateLocal(m_direction * translationUnit * unitsPerPixel * m_distanceToActor);
103+
auto totalDisplacement = m_currentMouse - m_originMouse;
104+
auto translationCoefficient = OvMaths::FVector2::Dot(totalDisplacement, screenDirection);
105+
106+
m_target->transform.SetLocalPosition(originPosition + GetRealDirection() * translationCoefficient * unitsPerPixel);
107+
}
108+
109+
void OvEditor::Core::GuizmoOperations::ApplyRotation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const
110+
{
111+
auto unitsPerPixel = 0.2f;
112+
auto originRotation = m_originalTransform.GetLocalRotation();
113+
114+
auto screenDirection = GetScreenDirection(p_viewMatrix, p_projectionMatrix, p_viewSize);
115+
screenDirection = OvMaths::FVector2(-screenDirection.y, screenDirection.x);
116+
117+
auto totalDisplacement = m_currentMouse - m_originMouse;
118+
auto rotationCoefficient = OvMaths::FVector2::Dot(totalDisplacement, screenDirection);
119+
120+
auto rotationToApply = OvMaths::FQuaternion(OvMaths::FVector3(GetFakeDirection() * rotationCoefficient * unitsPerPixel));
121+
m_target->transform.SetLocalRotation(originRotation * rotationToApply);
122+
}
123+
124+
void OvEditor::Core::GuizmoOperations::ApplyScale(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize) const
125+
{
126+
auto unitsPerPixel = 0.005f;
127+
auto originScale = m_originalTransform.GetLocalScale();
128+
129+
auto screenDirection = GetScreenDirection(p_viewMatrix, p_projectionMatrix, p_viewSize);
130+
131+
auto totalDisplacement = m_currentMouse - m_originMouse;
132+
auto scaleCoefficient = OvMaths::FVector2::Dot(totalDisplacement, screenDirection);
133+
134+
auto newScale = originScale + GetFakeDirection() * scaleCoefficient * unitsPerPixel;
135+
136+
/* Prevent scale from being negative*/
137+
newScale.x = std::max(newScale.x, 0.0001f);
138+
newScale.y = std::max(newScale.y, 0.0001f);
139+
newScale.z = std::max(newScale.z, 0.0001f);
140+
141+
m_target->transform.SetLocalScale(newScale);
142+
}
143+
144+
void OvEditor::Core::GuizmoOperations::ApplyOperation(const OvMaths::FMatrix4& p_viewMatrix, const OvMaths::FMatrix4& p_projectionMatrix, const OvMaths::FVector2& p_viewSize)
145+
{
146+
switch (m_currentOperation)
147+
{
148+
case EOperation::TRANSLATION:
149+
ApplyTranslation(p_viewMatrix, p_projectionMatrix, p_viewSize);
150+
break;
151+
152+
case EOperation::ROTATION:
153+
ApplyRotation(p_viewMatrix, p_projectionMatrix, p_viewSize);
154+
break;
155+
156+
case EOperation::SCALE:
157+
ApplyScale(p_viewMatrix, p_projectionMatrix, p_viewSize);
158+
break;
159+
}
57160
}
58161

59162
void OvEditor::Core::GuizmoOperations::SetCurrentMouse(const OvMaths::FVector2& p_mousePosition)
60163
{
61164
if (m_firstMouse)
62165
{
63-
m_currentMouse = m_previousMouse = p_mousePosition;
166+
m_currentMouse = m_originMouse = p_mousePosition;
64167
m_firstMouse = false;
65168
}
66169
else
67170
{
68-
m_previousMouse = m_currentMouse;
69171
m_currentMouse = p_mousePosition;
70172
}
71173
}
72174

73175
bool OvEditor::Core::GuizmoOperations::IsPicking() const
74176
{
75177
return m_target;
76-
}
178+
}

Sources/Overload/OvEditor/src/OvEditor/Panels/SceneView.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,28 @@ OvEditor::Panels::SceneView::SceneView
3232
};
3333
}
3434

35+
void OvEditor::Panels::SceneView::Update(float p_deltaTime)
36+
{
37+
AViewControllable::Update(p_deltaTime);
38+
39+
using namespace OvWindowing::Inputs;
40+
41+
if (EDITOR_CONTEXT(inputManager)->IsKeyPressed(EKey::KEY_Z))
42+
{
43+
m_currentOperation = OvEditor::Core::GuizmoOperations::EOperation::TRANSLATION;
44+
}
45+
46+
if (EDITOR_CONTEXT(inputManager)->IsKeyPressed(EKey::KEY_X))
47+
{
48+
m_currentOperation = OvEditor::Core::GuizmoOperations::EOperation::ROTATION;
49+
}
50+
51+
if (EDITOR_CONTEXT(inputManager)->IsKeyPressed(EKey::KEY_C))
52+
{
53+
m_currentOperation = OvEditor::Core::GuizmoOperations::EOperation::SCALE;
54+
}
55+
}
56+
3557
void OvEditor::Panels::SceneView::_Render_Impl()
3658
{
3759
auto& baseRenderer = *EDITOR_CONTEXT(renderer).get();
@@ -151,17 +173,17 @@ void OvEditor::Panels::SceneView::HandleActorPicking()
151173
{
152174
/* Guizmo X */
153175
case 253:
154-
m_guizmoOperations.StartPicking(actor, actor.transform.GetLocalRight(), m_cameraPosition);
176+
m_guizmoOperations.StartPicking(actor, m_cameraPosition, m_currentOperation, OvEditor::Core::GuizmoOperations::EDirection::X);
155177
break;
156178

157179
/* Guizmo Y */
158180
case 252:
159-
m_guizmoOperations.StartPicking(actor, actor.transform.GetLocalUp(), m_cameraPosition);
181+
m_guizmoOperations.StartPicking(actor, m_cameraPosition, m_currentOperation, OvEditor::Core::GuizmoOperations::EDirection::Y);
160182
break;
161183

162184
/* Guizmo Z */
163185
case 254:
164-
m_guizmoOperations.StartPicking(actor, actor.transform.GetLocalForward(), m_cameraPosition);
186+
m_guizmoOperations.StartPicking(actor, m_cameraPosition, m_currentOperation, OvEditor::Core::GuizmoOperations::EDirection::Z);
165187
break;
166188
}
167189
}
@@ -192,6 +214,6 @@ void OvEditor::Panels::SceneView::HandleActorPicking()
192214
auto view = m_camera.GetViewMatrix(m_cameraPosition);
193215

194216
m_guizmoOperations.SetCurrentMouse({ static_cast<float>(mousePosition.first), static_cast<float>(mousePosition.second) });
195-
m_guizmoOperations.ApplyTranslation(view, projection, { static_cast<float>(winWidth), static_cast<float>(winHeight) });
217+
m_guizmoOperations.ApplyOperation(view, projection, { static_cast<float>(winWidth), static_cast<float>(winHeight) });
196218
}
197219
}

0 commit comments

Comments
 (0)