Skip to content

Commit 578fc0c

Browse files
committed
correct bugs, save changes with tests, allow gizmos to controller cameras & adjust to changes - take reference frame with ::manipulate parameter; I need to inspect a few issues with reference events
1 parent 45a5762 commit 578fc0c

File tree

6 files changed

+192
-190
lines changed

6 files changed

+192
-190
lines changed

61_UI/main.cpp

Lines changed: 70 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication
12111211
projection.endInputProcessing();
12121212

12131213
if (vCount)
1214-
camera->manipulate({ virtualEvents.data(), vCount }, ICamera::Local);
1214+
camera->manipulate({ virtualEvents.data(), vCount });
12151215
}
12161216

12171217
m_ui.manager->update(params);
@@ -1350,7 +1350,6 @@ class UISampleApp final : public examples::SimpleWindowedApplication
13501350

13511351
const bool isCameraGimbalTarget = modelIx; // I assume scene demo model is 0th ix, left are planar cameras
13521352
ICamera* const targetGimbalManipulationCamera = isCameraGimbalTarget ? m_planarProjections[modelIx - 1u]->getCamera() : nullptr;
1353-
bool discard = isCameraGimbalTarget && mCurrentGizmoOperation != ImGuizmo::TRANSLATE; // discard WiP stuff
13541353

13551354
// if we try to manipulate a camera which appears to be the same camera we see scene from then obvsly it doesn't make sense to manipulate its gizmo so we skip it
13561355
// EDIT: it actually makes some sense if you assume render planar view is rendered with ortho projection, but we would need to add imguizmo controller virtual map
@@ -1373,98 +1372,94 @@ class UISampleApp final : public examples::SimpleWindowedApplication
13731372

13741373
imguizmoModel.outTRS = imguizmoModel.inTRS;
13751374
{
1376-
const bool success = ImGuizmo::Manipulate(&imguizmoPlanar.view[0][0], &imguizmoPlanar.projection[0][0], mCurrentGizmoOperation, mCurrentGizmoMode, &imguizmoModel.outTRS[0][0], &imguizmoModel.outDeltaTRS[0][0], useSnap ? &snap[0] : nullptr);
1375+
const bool success = ImGuizmo::Manipulate(&imguizmoPlanar.view[0][0], &imguizmoPlanar.projection[0][0], ImGuizmo::OPERATION::UNIVERSAL, mCurrentGizmoMode, &imguizmoModel.outTRS[0][0], &imguizmoModel.outDeltaTRS[0][0], useSnap ? &snap[0] : nullptr);
13771376

13781377
if (success)
13791378
{
1380-
++manipulationCounter;
1381-
discard |= manipulationCounter > 1;
1382-
1383-
/*
1384-
1385-
NOTE to self & TODO: I must be killing ImGuizmo last invocation cache or something with my delta events (or at least I dont
1386-
see now where I'm *maybe* using its API incorrectly, the problem is I get translation parts in delta matrix when doing
1387-
rotations hence it glitches my cameras -> on the other hand I can see it kinda correctly outputs the delta matrix when
1388-
gc model is bound
1389-
1390-
auto postprocessDeltaManipulation = [](const float32_t4x4& inDeltaMatrix, float32_t4x4& outDeltaMatrix, ImGuizmo::OPERATION operation) -> void
1379+
if (targetGimbalManipulationCamera)
13911380
{
1392-
struct
1393-
{
1394-
float32_t3 dTranslation, dRotation, dScale;
1395-
} world;
1381+
boundCameraToManipulate = smart_refctd_ptr<ICamera>(targetGimbalManipulationCamera);
1382+
boundPlanarCameraIxToManipulate = modelIx - 1u;
13961383

1397-
ImGuizmo::DecomposeMatrixToComponents(&inDeltaMatrix[0][0], &world.dTranslation[0], &world.dRotation[0], &world.dScale[0]);
1384+
auto& gimbal = (ICamera::CGimbal&)targetGimbalManipulationCamera->getGimbal();
13981385

1399-
if (operation == ImGuizmo::TRANSLATE)
1400-
{
1401-
world.dRotation = float32_t3(0, 0, 0);
1402-
}
1403-
else if (operation == ImGuizmo::ROTATE)
1386+
struct
14041387
{
1405-
world.dTranslation = float32_t3(0, 0, 0);
1406-
}
1407-
1408-
ImGuizmo::RecomposeMatrixFromComponents(&world.dTranslation[0], &world.dRotation[0], &world.dScale[0], &outDeltaMatrix[0][0]);
1409-
};
1410-
1411-
postprocessDeltaManipulation(imguizmoModel.outDeltaTRS, imguizmoModel.outDeltaTRS, mCurrentGizmoOperation);
1412-
*/
1388+
float32_t3 t, r, s;
1389+
} out, delta;
14131390

1414-
if (!discard)
1415-
{
1416-
if (targetGimbalManipulationCamera)
1391+
ImGuizmo::DecomposeMatrixToComponents(&imguizmoModel.outTRS[0][0], &out.t[0], &out.r[0], &out.s[0]);
1392+
ImGuizmo::DecomposeMatrixToComponents(&imguizmoModel.outDeltaTRS[0][0], &delta.t[0], &delta.r[0], &delta.s[0]);
14171393
{
1418-
boundCameraToManipulate = smart_refctd_ptr<ICamera>(targetGimbalManipulationCamera);
1419-
boundPlanarCameraIxToManipulate = modelIx - 1u;
1420-
1421-
/*
1422-
testing imguizmo controller for target camera, we use delta world imguizmo TRS matrix to generate virtual events
1423-
*/
1424-
1394+
std::vector<CVirtualGimbalEvent> virtualEvents;
1395+
1396+
auto requestMagnitudeUpdateWithScalar = [&](float signPivot, float dScalar, float dMagnitude, auto positive, auto negative)
14251397
{
1426-
static std::vector<CVirtualGimbalEvent> virtualEvents(0x45);
1427-
uint32_t vCount = {};
1428-
1429-
targetGimbalManipulationCamera->beginInputProcessing(m_nextPresentationTimestamp);
1398+
if (dScalar != signPivot)
14301399
{
1431-
targetGimbalManipulationCamera->process(nullptr, vCount);
1432-
1433-
if (virtualEvents.size() < vCount)
1434-
virtualEvents.resize(vCount);
1400+
auto& ev = virtualEvents.emplace_back();
1401+
auto code = (dScalar > signPivot) ? positive : negative;
14351402

1436-
IGimbalController::SUpdateParameters params;
1437-
params.imguizmoEvents = { { imguizmoModel.outDeltaTRS } };
1438-
targetGimbalManipulationCamera->process(virtualEvents.data(), vCount, params);
1403+
ev.type = code;
1404+
ev.magnitude += dMagnitude;
14391405
}
1440-
targetGimbalManipulationCamera->endInputProcessing();
1406+
};
1407+
1408+
// Delta translation impulse
1409+
requestMagnitudeUpdateWithScalar(0.f, delta.t[0], std::abs(delta.t[0]), CVirtualGimbalEvent::VirtualEventType::MoveRight, CVirtualGimbalEvent::VirtualEventType::MoveLeft);
1410+
requestMagnitudeUpdateWithScalar(0.f, delta.t[1], std::abs(delta.t[1]), CVirtualGimbalEvent::VirtualEventType::MoveUp, CVirtualGimbalEvent::VirtualEventType::MoveDown);
1411+
requestMagnitudeUpdateWithScalar(0.f, delta.t[2], std::abs(delta.t[2]), CVirtualGimbalEvent::VirtualEventType::MoveForward, CVirtualGimbalEvent::VirtualEventType::MoveBackward);
1412+
1413+
// Delta rotation impulse
1414+
requestMagnitudeUpdateWithScalar(0.f, delta.r[0], std::abs(delta.r[0]), CVirtualGimbalEvent::VirtualEventType::TiltUp, CVirtualGimbalEvent::VirtualEventType::TiltDown);
1415+
requestMagnitudeUpdateWithScalar(0.f, delta.r[1], std::abs(delta.r[1]), CVirtualGimbalEvent::VirtualEventType::PanRight, CVirtualGimbalEvent::VirtualEventType::PanLeft);
1416+
requestMagnitudeUpdateWithScalar(0.f, delta.r[2], std::abs(delta.r[2]), CVirtualGimbalEvent::VirtualEventType::RollRight, CVirtualGimbalEvent::VirtualEventType::RollLeft);
1417+
1418+
// Delta scale impulse
1419+
requestMagnitudeUpdateWithScalar(1.f, delta.s[0], std::abs(delta.s[0]), CVirtualGimbalEvent::VirtualEventType::ScaleXInc, CVirtualGimbalEvent::VirtualEventType::ScaleXDec);
1420+
requestMagnitudeUpdateWithScalar(1.f, delta.s[1], std::abs(delta.s[1]), CVirtualGimbalEvent::VirtualEventType::ScaleYInc, CVirtualGimbalEvent::VirtualEventType::ScaleYDec);
1421+
requestMagnitudeUpdateWithScalar(1.f, delta.s[2], std::abs(delta.s[2]), CVirtualGimbalEvent::VirtualEventType::ScaleZInc, CVirtualGimbalEvent::VirtualEventType::ScaleZDec);
1422+
1423+
constexpr auto TESSTTSS = CVirtualGimbalEvent::All;
1424+
const auto impulse = gimbal.accumulate<TESSTTSS>(virtualEvents);
1425+
1426+
assert(impulse.dVirtualTranslate == float64_t3(delta.t));
1427+
assert(impulse.dVirtualRotation == float64_t3(delta.r));
1428+
assert(impulse.dVirtualScale == float64_t3(delta.s));
14411429

1442-
if (vCount)
1443-
{
1444-
const float pMoveSpeed = targetGimbalManipulationCamera->getMoveSpeedScale();
1445-
const float pRotationSpeed = targetGimbalManipulationCamera->getRotationSpeedScale();
1430+
const auto vCount = virtualEvents.size();
14461431

1447-
// I start to think controller should be able to set sensitivity to scale magnitudes of generated events
1448-
// in order for camera to not keep any magnitude scalars like move or rotation speed scales
1432+
if (vCount)
1433+
{
1434+
const float pMoveSpeed = targetGimbalManipulationCamera->getMoveSpeedScale();
1435+
const float pRotationSpeed = targetGimbalManipulationCamera->getRotationSpeedScale();
14491436

1450-
targetGimbalManipulationCamera->setMoveSpeedScale(1);
1451-
targetGimbalManipulationCamera->setRotationSpeedScale(1);
1437+
// I start to think controller should be able to set sensitivity to scale magnitudes of generated events
1438+
// in order for camera to not keep any magnitude scalars like move or rotation speed scales
14521439

1453-
// NOTE: generated events from ImGuizmo controller are always in world space!
1454-
targetGimbalManipulationCamera->manipulate({ virtualEvents.data(), vCount }, ICamera::World);
1440+
targetGimbalManipulationCamera->setMoveSpeedScale(1);
1441+
targetGimbalManipulationCamera->setRotationSpeedScale(1);
14551442

1456-
targetGimbalManipulationCamera->setMoveSpeedScale(pMoveSpeed);
1457-
targetGimbalManipulationCamera->setRotationSpeedScale(pRotationSpeed);
1458-
}
1443+
/*
1444+
new = old * delta
1445+
delta^(-1) * new = old
1446+
*/
1447+
1448+
const auto referenceFrame = getCastedMatrix<float64_t>(mul(inverse(imguizmoModel.outDeltaTRS), imguizmoModel.outTRS));
1449+
targetGimbalManipulationCamera->manipulate({ virtualEvents.data(), vCount }, &referenceFrame);
1450+
1451+
targetGimbalManipulationCamera->setMoveSpeedScale(pMoveSpeed);
1452+
targetGimbalManipulationCamera->setRotationSpeedScale(pRotationSpeed);
14591453
}
1454+
14601455
}
1461-
else
1462-
{
1463-
// again, for scene demo model full affine transformation without limits is assumed
1464-
m_model = float32_t3x4(hlsl::transpose(imguizmoModel.outTRS));
1465-
boundCameraToManipulate = nullptr;
1466-
boundPlanarCameraIxToManipulate = std::nullopt;
1467-
}
1456+
}
1457+
else
1458+
{
1459+
// again, for scene demo model full affine transformation without limits is assumed
1460+
m_model = float32_t3x4(hlsl::transpose(imguizmoModel.outTRS));
1461+
boundCameraToManipulate = nullptr;
1462+
boundPlanarCameraIxToManipulate = std::nullopt;
14681463
}
14691464
}
14701465

@@ -2102,8 +2097,7 @@ class UISampleApp final : public examples::SimpleWindowedApplication
21022097
boundCameraToManipulate->setMoveSpeedScale(1);
21032098
boundCameraToManipulate->setRotationSpeedScale(1);
21042099

2105-
// NOTE: generated events from ImGuizmo controller are always in world space!
2106-
boundCameraToManipulate->manipulate({ virtualEvents.data(), vCount }, ICamera::World);
2100+
boundCameraToManipulate->manipulate({ virtualEvents.data(), vCount });
21072101

21082102
boundCameraToManipulate->setMoveSpeedScale(pmSpeed);
21092103
boundCameraToManipulate->setRotationSpeedScale(prSpeed);

common/include/camera/CFPSCamera.hpp

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
1+
// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O.
22
// This file is part of the "Nabla Engine".
33
// For conditions of distribution and use, see copyright notice in nabla.h
44

@@ -17,7 +17,24 @@ class CFPSCamera final : public ICamera
1717
using base_t = ICamera;
1818

1919
CFPSCamera(const float64_t3& position, const glm::quat& orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f))
20-
: base_t(), m_gimbal({ .position = position, .orientation = orientation }) {}
20+
: base_t(), m_gimbal({ .position = position, .orientation = orientation })
21+
{
22+
m_gimbal.begin();
23+
{
24+
const auto& gForward = m_gimbal.getZAxis();
25+
const float gPitch = atan2(glm::length(glm::vec2(gForward.x, gForward.z)), gForward.y) - glm::half_pi<float>(), gYaw = atan2(gForward.x, gForward.z);
26+
27+
28+
29+
30+
auto test = glm::quat(glm::vec3(gPitch, gYaw, 0.0f));
31+
32+
glm::vec3 euler = glm::eulerAngles(test);
33+
34+
m_gimbal.setOrientation(test);
35+
}
36+
m_gimbal.end();
37+
}
2138
~CFPSCamera() = default;
2239

2340
const base_t::keyboard_to_virtual_events_t getKeyboardMappingPreset() const override { return m_keyboard_to_virtual_events_preset; }
@@ -29,51 +46,55 @@ class CFPSCamera final : public ICamera
2946
return m_gimbal;
3047
}
3148

32-
virtual bool manipulate(std::span<const CVirtualGimbalEvent> virtualEvents, base_t::ManipulationMode mode) override
49+
virtual bool manipulate(std::span<const CVirtualGimbalEvent> virtualEvents, const float64_t4x4 const* referenceFrame = nullptr) override
3350
{
34-
constexpr double MaxVerticalAngle = glm::radians(88.0f), MinVerticalAngle = -MaxVerticalAngle;
35-
3651
if (!virtualEvents.size())
3752
return false;
3853

39-
const auto& gForward = m_gimbal.getZAxis();
40-
const float gPitch = atan2(glm::length(glm::vec2(gForward.x, gForward.z)), gForward.y) - glm::half_pi<float>(), gYaw = atan2(gForward.x, gForward.z);
41-
42-
glm::quat newOrientation; float64_t3 newPosition;
54+
//! true if virtual events are with respect to the moving gimbal frame, otherwise it is assumed deltas are generated for fixed reference frame
55+
const bool isMovingReference = not referenceFrame;
4356

44-
// TODO: I make assumption what world base is now (at least temporary), I need to think of this but maybe each ITransformObject should know what its world is
45-
// in ideal scenario we would define this crazy enum with all possible standard bases
46-
const auto impulse = mode == base_t::Local ? m_gimbal.accumulate<AllowedLocalVirtualEvents>(virtualEvents)
47-
: m_gimbal.accumulate<AllowedWorldVirtualEvents>(virtualEvents, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 });
57+
CReferenceTransform reference;
58+
if (not m_gimbal.extractReferenceTransform(&reference, referenceFrame))
59+
return false;
4860

49-
const auto newPitch = std::clamp(gPitch + impulse.dVirtualRotation.x * m_rotationSpeedScale, MinVerticalAngle, MaxVerticalAngle), newYaw = gYaw + impulse.dVirtualRotation.y * m_rotationSpeedScale;
50-
newOrientation = glm::quat(glm::vec3(newPitch, newYaw, 0.0f)); newPosition = m_gimbal.getPosition() + impulse.dVirtualTranslate * m_moveSpeedScale;
61+
auto impulse = m_gimbal.accumulate<AllowedVirtualEvents>(virtualEvents);
5162

5263
bool manipulated = true;
5364

5465
m_gimbal.begin();
5566
{
56-
m_gimbal.setOrientation(newOrientation);
57-
m_gimbal.setPosition(newPosition);
67+
if (isMovingReference)
68+
{
69+
const auto& gForward = m_gimbal.getZAxis();
70+
const float gPitch = atan2(glm::length(glm::vec2(gForward.x, gForward.z)), gForward.y) - glm::half_pi<float>(), gYaw = atan2(gForward.x, gForward.z);
71+
const float newPitch = std::clamp<float>(gPitch + impulse.dVirtualRotation.x * m_rotationSpeedScale, MinVerticalAngle, MaxVerticalAngle), newYaw = gYaw + impulse.dVirtualRotation.y * m_rotationSpeedScale;
72+
73+
m_gimbal.setOrientation(glm::quat(glm::vec3(newPitch, newYaw, 0.0f)));
74+
m_gimbal.setPosition(m_gimbal.getPosition() + mul(impulse.dVirtualTranslate * m_moveSpeedScale, m_gimbal.getOrthonornalMatrix()));
75+
}
76+
else
77+
{
78+
// TODO: I need to think of this, the problem is that since reference frame may not be aligned with world nicely it means events must be transformed
79+
// what FPS camera really does is:
80+
// tilt around FIXED world (0,1,0) vector
81+
// pitch around REFERENCE right vector
82+
m_gimbal.transform(reference, impulse);
83+
}
5884
}
5985
m_gimbal.end();
6086

6187
manipulated &= bool(m_gimbal.getManipulationCounter());
6288

63-
if(manipulated)
89+
if (manipulated)
6490
m_gimbal.updateView();
6591

6692
return manipulated;
6793
}
6894

69-
virtual const uint32_t getAllowedVirtualEvents(base_t::ManipulationMode mode) override
95+
virtual const uint32_t getAllowedVirtualEvents() override
7096
{
71-
switch (mode)
72-
{
73-
case base_t::Local: return AllowedLocalVirtualEvents;
74-
case base_t::World: return AllowedWorldVirtualEvents;
75-
default: return CVirtualGimbalEvent::None;
76-
}
97+
return AllowedVirtualEvents;
7798
}
7899

79100
virtual const std::string_view getIdentifier() override
@@ -82,10 +103,11 @@ class CFPSCamera final : public ICamera
82103
}
83104

84105
private:
106+
85107
typename base_t::CGimbal m_gimbal;
86108

87-
static inline constexpr auto AllowedLocalVirtualEvents = CVirtualGimbalEvent::Translate | CVirtualGimbalEvent::TiltUp | CVirtualGimbalEvent::TiltDown | CVirtualGimbalEvent::PanRight | CVirtualGimbalEvent::PanLeft;
88-
static inline constexpr auto AllowedWorldVirtualEvents = AllowedLocalVirtualEvents;
109+
static inline constexpr auto AllowedVirtualEvents = CVirtualGimbalEvent::Translate | CVirtualGimbalEvent::Rotate;
110+
static inline constexpr float MaxVerticalAngle = glm::radians(88.0f), MinVerticalAngle = -MaxVerticalAngle;
89111

90112
static inline const auto m_keyboard_to_virtual_events_preset = []()
91113
{

0 commit comments

Comments
 (0)