K4AViewer: change point cloud viewer to arcball controls (#222)
Change the point cloud viewer controls from first person game-style WASD keyboard/mouse controls to modeling software-style arcball mouse controls
This commit is contained in:
Родитель
a84aad2c7a
Коммит
e751370be7
|
@ -115,5 +115,17 @@ void K4AVText(const char *s)
|
|||
ImGui::Text("%s", vLabel.c_str());
|
||||
}
|
||||
|
||||
void K4AShowTooltip(const char *msg)
|
||||
{
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||
ImGui::TextUnformatted(msg);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ImGuiExtensions
|
||||
} // namespace k4aviewer
|
||||
|
|
|
@ -255,6 +255,10 @@ bool K4AVSliderFloat(const char *name, ImVec2 size, float *value, float minValue
|
|||
//
|
||||
void K4AVText(const char *str);
|
||||
|
||||
// Shows a tooltip if the most recently-drawn control was hovered
|
||||
//
|
||||
void K4AShowTooltip(const char *msg);
|
||||
|
||||
} // namespace ImGuiExtensions
|
||||
} // namespace k4aviewer
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
// System headers
|
||||
//
|
||||
#include <algorithm>
|
||||
|
||||
// Library headers
|
||||
//
|
||||
|
@ -26,160 +27,199 @@ inline float Radians(const float angle)
|
|||
}
|
||||
|
||||
// Default camera values
|
||||
const float DefaultSpeed = 2.5f;
|
||||
const float DefaultSensitivity = 0.1f;
|
||||
const float DefaultZoom = 65.0f;
|
||||
//
|
||||
constexpr float MinZoom = 1.0f;
|
||||
constexpr float MaxZoom = 120.0f;
|
||||
constexpr float DefaultZoom = 65.0f;
|
||||
constexpr float ZoomSensitivity = 3.f;
|
||||
constexpr float TranslationSensitivity = 0.01f;
|
||||
|
||||
// clang-format off
|
||||
const ViewParameters DefaultView(0.15f, 0.f, -1.25f, // Position
|
||||
0.f, 1.f, 0.f, // WorldUp
|
||||
-268.f, 0.f); // Yaw and Pitch
|
||||
// clang-format on
|
||||
// Default point cloud position, chosen such that the entire point cloud
|
||||
// should be in the field of view
|
||||
//
|
||||
const vec3 DefaultPointCloudPosition{ 0.f, 0.f, -8.0f };
|
||||
|
||||
// Approximate midpoint of a point cloud. We need to translate
|
||||
// the point cloud by this much before we start applying rotations to the
|
||||
// point cloud in order to to get the rotation to be around the point
|
||||
// cloud's midpoint instead of its origin.
|
||||
//
|
||||
const vec3 PointCloudMidpoint{ 0.f, 1.f, -3.0f };
|
||||
|
||||
// Version of mat4x4_mul that doesn't modify its non-result inputs (i.e. a, b)
|
||||
//
|
||||
void MatrixMultiply(mat4x4 out, mat4x4 a, mat4x4 b)
|
||||
{
|
||||
mat4x4 atmp;
|
||||
mat4x4 btmp;
|
||||
mat4x4_dup(atmp, a);
|
||||
mat4x4_dup(btmp, b);
|
||||
mat4x4_mul(out, a, b);
|
||||
}
|
||||
|
||||
// Map XY coordinates to a virtual sphere, which we use for rotation calculations
|
||||
//
|
||||
void MapToArcball(vec3 out, const vec2 displayDimensions, const vec2 mousePos)
|
||||
{
|
||||
// Scale coords to (-1, 1) to simplify some of the math
|
||||
//
|
||||
vec2 scaledMousePos;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
scaledMousePos[i] = mousePos[i] * (1.0f / ((displayDimensions[i] - 1.0f) * 0.5f)) - 1.0f;
|
||||
}
|
||||
|
||||
float lenSquared = scaledMousePos[0] * scaledMousePos[0] + scaledMousePos[1] * scaledMousePos[1];
|
||||
|
||||
// If the point is 'outside' our virtual sphere, we need to normalize to the sphere
|
||||
// This works because our sphere is of radius 1
|
||||
//
|
||||
if (lenSquared > 1.f)
|
||||
{
|
||||
const float normalizationFactor = 1.f / std::sqrt(lenSquared);
|
||||
|
||||
// Return a point on the edge of the sphere
|
||||
//
|
||||
out[0] = scaledMousePos[0] * normalizationFactor;
|
||||
out[1] = scaledMousePos[1] * normalizationFactor;
|
||||
out[2] = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return a point inside the sphere
|
||||
//
|
||||
out[0] = scaledMousePos[0];
|
||||
out[1] = scaledMousePos[1];
|
||||
out[2] = std::sqrt(1.f - lenSquared);
|
||||
}
|
||||
}
|
||||
|
||||
// Imagine a virtual sphere of displayDimensions size were drawn on the screen.
|
||||
// Returns a quaternion representing the rotation that sphere would undergo if you took the point
|
||||
// on that sphere at startPos and rotated it to endPos (i.e. an "arcball" camera).
|
||||
//
|
||||
void GetArcballRotation(quat rotation, const vec2 displayDimensions, const vec2 startPos, const vec2 endPos)
|
||||
{
|
||||
vec3 startVector;
|
||||
MapToArcball(startVector, displayDimensions, startPos);
|
||||
|
||||
vec3 endVector;
|
||||
MapToArcball(endVector, displayDimensions, endPos);
|
||||
|
||||
vec3 cross;
|
||||
vec3_mul_cross(cross, startVector, endVector);
|
||||
|
||||
constexpr float epsilon = 0.001f;
|
||||
if (vec3_len(cross) < epsilon)
|
||||
{
|
||||
// Smooth out floating point error if the user didn't move the mouse
|
||||
// enough that it should register
|
||||
//
|
||||
quat_identity(rotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The first 3 elements of the quaternion are the unit vector perpendicular
|
||||
// to the rotation (i.e. the cross product); the last element is the magnitude
|
||||
// of the rotation
|
||||
//
|
||||
vec3_copy(rotation, cross);
|
||||
vec3_norm(cross, cross);
|
||||
rotation[3] = vec3_mul_inner(startVector, endVector);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ViewParameters::ViewParameters(const float posX,
|
||||
const float posY,
|
||||
const float posZ,
|
||||
const float upX,
|
||||
const float upY,
|
||||
const float upZ,
|
||||
const float yaw,
|
||||
const float pitch)
|
||||
{
|
||||
vec3_set(Front, 0.f, 0.f, -1.f);
|
||||
vec3_set(Position, posX, posY, posZ);
|
||||
vec3_set(WorldUp, upX, upY, upZ);
|
||||
Yaw = yaw;
|
||||
Pitch = pitch;
|
||||
UpdateRotationVectors();
|
||||
}
|
||||
|
||||
// Update the rotation vectors based on the updated yaw and pitch values
|
||||
// It needs to be called every time after updating the yaw and pitch value
|
||||
void ViewParameters::UpdateRotationVectors()
|
||||
{
|
||||
// Calculate the new m_viewParams.front vector
|
||||
vec3 frontTemp;
|
||||
frontTemp[0] = static_cast<float>(std::cos(Radians(Yaw)) * std::cos(Radians(Pitch)));
|
||||
frontTemp[1] = static_cast<float>(std::sin(Radians(Pitch)));
|
||||
frontTemp[2] = static_cast<float>(std::sin(Radians(Yaw)) * std::cos(Radians(Pitch)));
|
||||
vec3_norm(Front, frontTemp);
|
||||
|
||||
// Also re-calculate the Right and Up vector
|
||||
vec3 rightTemp;
|
||||
vec3_mul_cross(rightTemp, Front, WorldUp);
|
||||
vec3_norm(Right, rightTemp); // Normalize the vectors, because their length gets closer to 0 the more you look up or
|
||||
// down which results in slower movement.
|
||||
|
||||
vec3 upTemp;
|
||||
vec3_mul_cross(upTemp, Right, Front);
|
||||
vec3_norm(Up, upTemp);
|
||||
}
|
||||
|
||||
ViewControl::ViewControl() :
|
||||
m_viewParams(DefaultView),
|
||||
m_movementSpeed(DefaultSpeed),
|
||||
m_mouseSensitivity(DefaultSensitivity),
|
||||
m_zoom(DefaultZoom)
|
||||
ViewControl::ViewControl() : m_zoom(DefaultZoom)
|
||||
{
|
||||
ResetPosition();
|
||||
}
|
||||
|
||||
// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
|
||||
void ViewControl::GetViewMatrix(mat4x4 viewMatrix)
|
||||
{
|
||||
vec3 temp;
|
||||
vec3_add(temp, m_viewParams.Position, m_viewParams.Front);
|
||||
mat4x4_look_at(viewMatrix, m_viewParams.Position, temp, m_viewParams.Up);
|
||||
mat4x4_identity(viewMatrix);
|
||||
|
||||
// Move the center of the point cloud to (0, 0, 0) so we can rotate it
|
||||
//
|
||||
mat4x4 pointCloudMidpointTranslation;
|
||||
mat4x4_translate(pointCloudMidpointTranslation,
|
||||
PointCloudMidpoint[0],
|
||||
PointCloudMidpoint[1],
|
||||
PointCloudMidpoint[2]);
|
||||
|
||||
// Move the point cloud to a point in front of the field of view
|
||||
//
|
||||
mat4x4 pointCloudFinalTranslation;
|
||||
mat4x4_translate(pointCloudFinalTranslation,
|
||||
m_pointCloudPosition[0],
|
||||
m_pointCloudPosition[1],
|
||||
m_pointCloudPosition[2]);
|
||||
|
||||
// Rotate 180 degrees about the Y axis so the scene starts out facing toward the user
|
||||
//
|
||||
quat rotateQuat;
|
||||
vec3 rotateAxis{ 0.f, 1.f, 0.f };
|
||||
mat4x4 rotateMatrix;
|
||||
quat_rotate(rotateQuat, Radians(180), rotateAxis);
|
||||
mat4x4_from_quat(rotateMatrix, rotateQuat);
|
||||
|
||||
// Multiplication order is reversed because we're moving the scene, not the camera
|
||||
//
|
||||
|
||||
// Move the point cloud into the field of view
|
||||
//
|
||||
MatrixMultiply(viewMatrix, viewMatrix, pointCloudFinalTranslation);
|
||||
|
||||
// Set up the point cloud
|
||||
//
|
||||
MatrixMultiply(viewMatrix, viewMatrix, m_userRotations);
|
||||
MatrixMultiply(viewMatrix, viewMatrix, rotateMatrix);
|
||||
MatrixMultiply(viewMatrix, viewMatrix, pointCloudMidpointTranslation);
|
||||
}
|
||||
|
||||
void ViewControl::GetPerspectiveMatrix(mat4x4 perspectiveMatrix, const int windowWidth, const int windowHeight) const
|
||||
void ViewControl::GetPerspectiveMatrix(mat4x4 perspectiveMatrix, const vec2 renderDimensions) const
|
||||
{
|
||||
mat4x4_perspective(perspectiveMatrix, Radians(m_zoom), windowWidth / static_cast<float>(windowHeight), 0.1f, 100.f);
|
||||
mat4x4_perspective(perspectiveMatrix, Radians(m_zoom), renderDimensions[0] / renderDimensions[1], 0.1f, 100.f);
|
||||
}
|
||||
|
||||
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined
|
||||
// ENUM (to abstract it from windowing systems)
|
||||
void ViewControl::ProcessPositionalMovement(const ViewMovement direction, const float deltaTime)
|
||||
void ViewControl::ProcessMouseMovement(const vec2 displayDimensions,
|
||||
const vec2 mousePos,
|
||||
const vec2 mouseDelta,
|
||||
MouseMovementType movementType)
|
||||
{
|
||||
const float velocity = m_movementSpeed * deltaTime;
|
||||
vec3 temp;
|
||||
switch (direction)
|
||||
if (movementType == MouseMovementType::Rotation)
|
||||
{
|
||||
case ViewMovement::Forward:
|
||||
vec3_scale(temp, m_viewParams.Front, velocity);
|
||||
vec3_add(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
case ViewMovement::Backward:
|
||||
vec3_scale(temp, m_viewParams.Front, velocity);
|
||||
vec3_sub(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
case ViewMovement::Left:
|
||||
vec3_scale(temp, m_viewParams.Right, velocity);
|
||||
vec3_sub(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
case ViewMovement::Right:
|
||||
vec3_scale(temp, m_viewParams.Right, velocity);
|
||||
vec3_add(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
case ViewMovement::Up:
|
||||
vec3_scale(temp, m_viewParams.Up, velocity);
|
||||
vec3_add(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
case ViewMovement::Down:
|
||||
vec3_scale(temp, m_viewParams.Up, velocity);
|
||||
vec3_sub(m_viewParams.Position, m_viewParams.Position, temp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
vec2 lastMousePos;
|
||||
vec2_copy(lastMousePos, mousePos);
|
||||
vec2_sub(lastMousePos, mousePos, mouseDelta);
|
||||
|
||||
quat newRotationQuat;
|
||||
GetArcballRotation(newRotationQuat, displayDimensions, lastMousePos, mousePos);
|
||||
|
||||
mat4x4 newRotationMtx;
|
||||
mat4x4_from_quat(newRotationMtx, newRotationQuat);
|
||||
|
||||
MatrixMultiply(m_userRotations, newRotationMtx, m_userRotations);
|
||||
}
|
||||
else if (movementType == MouseMovementType::Translation)
|
||||
{
|
||||
m_pointCloudPosition[0] += mouseDelta[0] * TranslationSensitivity;
|
||||
m_pointCloudPosition[1] += mouseDelta[1] * TranslationSensitivity;
|
||||
}
|
||||
}
|
||||
|
||||
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
|
||||
void ViewControl::ProcessMouseMovement(float xoffset, float yoffset, const GLboolean constrainPitch)
|
||||
{
|
||||
xoffset *= m_mouseSensitivity;
|
||||
yoffset *= m_mouseSensitivity;
|
||||
|
||||
m_viewParams.Yaw += xoffset;
|
||||
m_viewParams.Pitch += yoffset;
|
||||
|
||||
// Make sure that when pitch is out of bounds, screen doesn't get flipped
|
||||
if (constrainPitch)
|
||||
{
|
||||
if (m_viewParams.Pitch > 89.0f)
|
||||
{
|
||||
m_viewParams.Pitch = 89.0f;
|
||||
}
|
||||
if (m_viewParams.Pitch < -89.0f)
|
||||
{
|
||||
m_viewParams.Pitch = -89.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update m_viewParams.front, right and up Vectors using the updated Euler angles
|
||||
m_viewParams.UpdateRotationVectors();
|
||||
}
|
||||
|
||||
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
|
||||
void ViewControl::ProcessMouseScroll(const float yoffset)
|
||||
{
|
||||
if (m_zoom >= 1.0f && m_zoom <= 120.0f)
|
||||
if (m_zoom >= MinZoom && m_zoom <= MaxZoom)
|
||||
{
|
||||
m_zoom -= yoffset;
|
||||
}
|
||||
if (m_zoom <= 1.0f)
|
||||
{
|
||||
m_zoom = 1.0f;
|
||||
}
|
||||
if (m_zoom >= 120.0f)
|
||||
{
|
||||
m_zoom = 120.0f;
|
||||
m_zoom -= yoffset * ZoomSensitivity;
|
||||
m_zoom = std::min(MaxZoom, std::max(MinZoom, m_zoom));
|
||||
}
|
||||
}
|
||||
|
||||
void ViewControl::ResetPosition()
|
||||
{
|
||||
m_viewParams = DefaultView;
|
||||
vec3_copy(m_pointCloudPosition, DefaultPointCloudPosition);
|
||||
m_zoom = DefaultZoom;
|
||||
mat4x4_identity(m_userRotations);
|
||||
}
|
||||
|
|
|
@ -17,74 +17,51 @@
|
|||
|
||||
namespace k4aviewer
|
||||
{
|
||||
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific
|
||||
// input methods
|
||||
enum class ViewMovement
|
||||
|
||||
// The type of movement that a mouse movement should be interpreted as (if any)
|
||||
//
|
||||
enum class MouseMovementType
|
||||
{
|
||||
Forward,
|
||||
Backward,
|
||||
Left,
|
||||
Right,
|
||||
Up,
|
||||
Down
|
||||
None,
|
||||
Rotation,
|
||||
Translation
|
||||
};
|
||||
|
||||
struct ViewParameters
|
||||
{
|
||||
ViewParameters(const ViewParameters &v) = default;
|
||||
ViewParameters &operator=(const ViewParameters &v) = default;
|
||||
|
||||
ViewParameters(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);
|
||||
|
||||
// Update the rotation vectors based on the updated yaw and pitch values
|
||||
// It needs to be called every time after updating the yaw and pitch value
|
||||
void UpdateRotationVectors();
|
||||
|
||||
// Camera Attributes
|
||||
linmath::vec3 Position;
|
||||
linmath::vec3 Front;
|
||||
linmath::vec3 Up;
|
||||
linmath::vec3 Right;
|
||||
linmath::vec3 WorldUp;
|
||||
|
||||
// Euler Angles
|
||||
float Yaw;
|
||||
float Pitch;
|
||||
};
|
||||
|
||||
// An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for
|
||||
// use in OpenGL
|
||||
// A camera class that processes input and calculates the view matrices for use in OpenGL
|
||||
//
|
||||
class ViewControl
|
||||
{
|
||||
public:
|
||||
// Constructor with scalar values
|
||||
ViewControl();
|
||||
|
||||
// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
|
||||
// Returns the view matrix calculated using an arcball camera
|
||||
//
|
||||
void GetViewMatrix(linmath::mat4x4 viewMatrix);
|
||||
|
||||
void GetPerspectiveMatrix(linmath::mat4x4 perspectiveMatrix, int windowWidth, int windowHeight) const;
|
||||
// Gets a matrix representing the perspective transformation
|
||||
//
|
||||
void GetPerspectiveMatrix(linmath::mat4x4 perspectiveMatrix, const linmath::vec2 renderDimensions) const;
|
||||
|
||||
// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera
|
||||
// defined ENUM (to abstract it from windowing systems)
|
||||
void ProcessPositionalMovement(ViewMovement direction, float deltaTime);
|
||||
|
||||
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
|
||||
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);
|
||||
// Processes input received from a mouse input system.
|
||||
// Mouse position is relative to the start of the point cloud display, not the window.
|
||||
//
|
||||
void ProcessMouseMovement(const linmath::vec2 displayDimensions,
|
||||
const linmath::vec2 mousePos,
|
||||
const linmath::vec2 mouseDelta,
|
||||
MouseMovementType movementType);
|
||||
|
||||
// Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
|
||||
//
|
||||
void ProcessMouseScroll(float yoffset);
|
||||
|
||||
// Reset camera view back to default position
|
||||
//
|
||||
void ResetPosition();
|
||||
|
||||
private:
|
||||
ViewParameters m_viewParams;
|
||||
|
||||
// Camera options
|
||||
float m_movementSpeed;
|
||||
float m_mouseSensitivity;
|
||||
float m_zoom;
|
||||
linmath::mat4x4 m_userRotations;
|
||||
linmath::vec3 m_pointCloudPosition;
|
||||
};
|
||||
} // namespace k4aviewer
|
||||
|
||||
|
|
|
@ -76,7 +76,9 @@ PointCloudVisualizationResult K4APointCloudVisualizer::UpdateTexture(std::shared
|
|||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_viewControl.GetPerspectiveMatrix(m_projection, m_dimensions.Width, m_dimensions.Height);
|
||||
const linmath::vec2 displayDimensions{ static_cast<float>(m_dimensions.Width),
|
||||
static_cast<float>(m_dimensions.Height) };
|
||||
m_viewControl.GetPerspectiveMatrix(m_projection, displayDimensions);
|
||||
m_viewControl.GetViewMatrix(m_view);
|
||||
|
||||
m_pointCloudRenderer.UpdateViewProjection(m_view, m_projection);
|
||||
|
@ -92,14 +94,12 @@ PointCloudVisualizationResult K4APointCloudVisualizer::UpdateTexture(std::shared
|
|||
return PointCloudVisualizationResult::Success;
|
||||
}
|
||||
|
||||
void K4APointCloudVisualizer::ProcessPositionalMovement(const ViewMovement direction, const float deltaTime)
|
||||
void K4APointCloudVisualizer::ProcessMouseMovement(const linmath::vec2 displayDimensions,
|
||||
const linmath::vec2 mousePos,
|
||||
const linmath::vec2 mouseDelta,
|
||||
MouseMovementType movementType)
|
||||
{
|
||||
m_viewControl.ProcessPositionalMovement(direction, deltaTime);
|
||||
}
|
||||
|
||||
void K4APointCloudVisualizer::ProcessMouseMovement(const float xoffset, const float yoffset)
|
||||
{
|
||||
m_viewControl.ProcessMouseMovement(xoffset, yoffset);
|
||||
m_viewControl.ProcessMouseMovement(displayDimensions, mousePos, mouseDelta, movementType);
|
||||
}
|
||||
|
||||
void K4APointCloudVisualizer::ProcessMouseScroll(const float yoffset)
|
||||
|
|
|
@ -46,8 +46,10 @@ public:
|
|||
GLenum InitializeTexture(std::shared_ptr<K4AViewerImage> *texture) const;
|
||||
PointCloudVisualizationResult UpdateTexture(std::shared_ptr<K4AViewerImage> *texture, const k4a::capture &capture);
|
||||
|
||||
void ProcessPositionalMovement(ViewMovement direction, float deltaTime);
|
||||
void ProcessMouseMovement(float xoffset, float yoffset);
|
||||
void ProcessMouseMovement(const linmath::vec2 displayDimensions,
|
||||
const linmath::vec2 mousePos,
|
||||
const linmath::vec2 mouseDelta,
|
||||
MouseMovementType movementType);
|
||||
void ProcessMouseScroll(float yoffset);
|
||||
|
||||
void ResetPosition();
|
||||
|
|
|
@ -57,25 +57,18 @@ void K4APointCloudWindow::Show(K4AWindowPlacementInfo placementInfo)
|
|||
}
|
||||
|
||||
ImVec2 availableSize = placementInfo.Size;
|
||||
availableSize.y -= 3 * ImGui::GetTextLineHeightWithSpacing(); // Instructions text
|
||||
availableSize.y -= GetDefaultButtonHeight(); // Mode radio buttons
|
||||
availableSize.y -= GetDefaultButtonHeight(); // Reset button
|
||||
availableSize.y -= GetDefaultButtonHeight(); // Mode radio buttons
|
||||
availableSize.y -= GetDefaultButtonHeight(); // Reset button
|
||||
|
||||
const ImVec2 sourceImageSize = ImVec2(static_cast<float>(m_texture->GetDimensions().Width),
|
||||
static_cast<float>(m_texture->GetDimensions().Height));
|
||||
const ImVec2 textureSize = GetMaxImageSize(sourceImageSize, availableSize);
|
||||
|
||||
const ImVec2 imageStartPos = ImGui::GetCursorScreenPos();
|
||||
ImGui::Image(static_cast<ImTextureID>(*m_texture), textureSize);
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::Text("Movement: W/S/A/D/[Ctrl]/[Space]");
|
||||
ImGui::Text("Look: [Right Mouse] + Drag");
|
||||
ImGui::Text("Zoom: Mouse wheel");
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (m_missingColorImages != 0 || m_missingDepthImages != 0)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
ImGuiExtensions::TextColorChanger warningColorChanger(ImGuiExtensions::TextColor::Warning);
|
||||
|
@ -110,10 +103,23 @@ void K4APointCloudWindow::Show(K4AWindowPlacementInfo placementInfo)
|
|||
static_cast<int>(K4APointCloudVisualizer::ColorizationStrategy::Shaded));
|
||||
ImGui::SameLine();
|
||||
colorizationStrategyUpdated |=
|
||||
ImGuiExtensions::K4ARadioButton("Color (BGRA only)",
|
||||
ImGuiExtensions::K4ARadioButton("Color",
|
||||
ipColorizationStrategy,
|
||||
static_cast<int>(K4APointCloudVisualizer::ColorizationStrategy::Color),
|
||||
m_enableColorPointCloud);
|
||||
if (!m_enableColorPointCloud)
|
||||
{
|
||||
ImGuiExtensions::K4AShowTooltip("Color mode must be BGRA!");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::VerticalSeparator();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("[Show Controls]");
|
||||
const char *controlsHelpMessage = "Rotate: [Left Mouse] + Drag\n"
|
||||
"Pan: [Right Mouse] + Drag\n"
|
||||
"Zoom: Mouse wheel";
|
||||
ImGuiExtensions::K4AShowTooltip(controlsHelpMessage);
|
||||
|
||||
if (colorizationStrategyUpdated)
|
||||
{
|
||||
|
@ -136,7 +142,7 @@ void K4APointCloudWindow::Show(K4AWindowPlacementInfo placementInfo)
|
|||
m_pointCloudVisualizer.SetPointSize(m_pointSize);
|
||||
}
|
||||
|
||||
ProcessInput();
|
||||
ProcessInput(imageStartPos, textureSize);
|
||||
}
|
||||
|
||||
const char *K4APointCloudWindow::GetTitle() const
|
||||
|
@ -162,48 +168,33 @@ K4APointCloudWindow::K4APointCloudWindow(std::string &&windowTitle,
|
|||
|
||||
m_pointCloudVisualizer.SetPointSize(m_pointSize);
|
||||
CheckVisualizationResult(m_pointCloudVisualizer.SetColorizationStrategy(m_colorizationStrategy));
|
||||
m_lastTime = glfwGetTime();
|
||||
}
|
||||
|
||||
void K4APointCloudWindow::ProcessInput()
|
||||
void K4APointCloudWindow::ProcessInput(ImVec2 imageStartPos, ImVec2 displayDimensions)
|
||||
{
|
||||
const double currentTime = glfwGetTime();
|
||||
const auto timeDelta = static_cast<float>(currentTime - m_lastTime);
|
||||
m_lastTime = currentTime;
|
||||
|
||||
if (ImGui::IsWindowFocused())
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
if (io.KeysDown[GLFW_KEY_W])
|
||||
|
||||
const bool leftMouseDown = io.MouseDown[GLFW_MOUSE_BUTTON_1];
|
||||
const bool rightMouseDown = io.MouseDown[GLFW_MOUSE_BUTTON_2];
|
||||
|
||||
const linmath::vec2 mousePos{ io.MousePos.x - imageStartPos.x, io.MousePos.y - imageStartPos.y };
|
||||
|
||||
const linmath::vec2 mouseDelta{ io.MouseDelta.x, io.MouseDelta.y };
|
||||
const linmath::vec2 dimensions{ displayDimensions.x, displayDimensions.y };
|
||||
|
||||
MouseMovementType movementType = MouseMovementType::None;
|
||||
if (leftMouseDown)
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Forward, timeDelta);
|
||||
movementType = MouseMovementType::Rotation;
|
||||
}
|
||||
if (io.KeysDown[GLFW_KEY_A])
|
||||
else if (rightMouseDown)
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Left, timeDelta);
|
||||
}
|
||||
if (io.KeysDown[GLFW_KEY_D])
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Right, timeDelta);
|
||||
}
|
||||
if (io.KeysDown[GLFW_KEY_S])
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Backward, timeDelta);
|
||||
}
|
||||
if (io.KeysDown[GLFW_KEY_SPACE])
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Down, timeDelta);
|
||||
}
|
||||
if (io.KeysDown[GLFW_KEY_LEFT_CONTROL])
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessPositionalMovement(ViewMovement::Up, timeDelta);
|
||||
}
|
||||
|
||||
if (io.MouseDown[GLFW_MOUSE_BUTTON_2]) // right-click
|
||||
{
|
||||
m_pointCloudVisualizer.ProcessMouseMovement(io.MouseDelta.x, io.MouseDelta.y);
|
||||
movementType = MouseMovementType::Translation;
|
||||
}
|
||||
|
||||
m_pointCloudVisualizer.ProcessMouseMovement(dimensions, mousePos, mouseDelta, movementType);
|
||||
m_pointCloudVisualizer.ProcessMouseScroll(io.MouseWheel);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
K4APointCloudWindow &operator=(const K4APointCloudWindow &&) = delete;
|
||||
|
||||
private:
|
||||
void ProcessInput();
|
||||
void ProcessInput(ImVec2 imageStartPos, ImVec2 displayDimensions);
|
||||
void SetFailed(const char *msg);
|
||||
|
||||
bool CheckVisualizationResult(PointCloudVisualizationResult visualizationResult);
|
||||
|
@ -61,10 +61,6 @@ private:
|
|||
bool m_haveShownMissingImagesWarning = false;
|
||||
int m_missingColorImages = 0;
|
||||
int m_missingDepthImages = 0;
|
||||
|
||||
// OpenGL time
|
||||
//
|
||||
double m_lastTime = 0;
|
||||
};
|
||||
} // namespace k4aviewer
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче