refactor how multiple overlays get grabbed at the same time

This commit is contained in:
Crispy 2023-04-17 21:23:19 +02:00
parent 895bec3bd5
commit 286c1d08a7
6 changed files with 92 additions and 75 deletions

View file

@ -1,3 +1,5 @@
# ovr-screen
A SteamVR overlay for Linux+X11 that displays all your screens in VR.
From my limited testing, this uses about half the CPU performance of Steam's built-in desktop overlay, if running at 60 FPS. Currently the default is 30 FPS which brings the factor to 3-4x. On my machine, the Steam desktop view increases cpu usage by about 100% of a CPU thread (looking only at the `steam` process), while this overlay uses around 25% at 30 FPS and 45% at 60 FPS.

View file

@ -46,6 +46,11 @@ App::App()
_panels[i].GetOverlay()->SetWidth(width);
}
for (auto &panel : _panels)
{
_root_overlay.AddChildOverlay(panel.GetOverlay());
}
{ // initialize SteamVR input
auto exe_path = std::filesystem::read_symlink("/proc/self/exe");
_actions_path = exe_path.parent_path().string() + "/bindings/action_manifest.json";
@ -126,19 +131,6 @@ void App::InitRootOverlay()
// clang-format on
_root_overlay.SetTransformWorld(&root_start_pose);
_root_overlay.SetTextureToColor(110, 30, 190);
_root_overlay._GrabBeginCallback = [this](Controller *controller) {
for (auto &panel : _panels)
{
panel.GetOverlay()->ControllerGrab(controller);
}
};
_root_overlay._GrabEndCallback = [this]() {
for (auto &panel : _panels)
{
panel.GetOverlay()->ControllerRelease();
}
};
}
void App::Update()

View file

@ -8,6 +8,7 @@ const float width = 0.004f;
Controller::Controller(App *app, ControllerSide side)
{
_grabbed_overlay = nullptr;
_app = app;
_input_handle = 0;
_is_connected = false;
@ -51,29 +52,30 @@ void Controller::SetHidden(bool state)
_hidden = state;
}
void Controller::RegisterGrabbedOverlay(Overlay *overlay)
void Controller::ReleaseOverlay()
{
_grabbed_overlays.push_back(overlay);
}
void Controller::ReleaseOverlay(Overlay *overlay)
{
for (auto i = _grabbed_overlays.begin(); i != _grabbed_overlays.end(); i++)
{
if (*i == overlay)
{
_grabbed_overlays.erase(i);
break;
}
}
_grabbed_overlay = nullptr;
}
void Controller::Update()
{
UpdateStatus();
if (!_is_connected)
if (!_is_connected || _hidden)
return;
UpdateLaser();
float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time
if (_grabbed_overlay && move != 0.0f)
{
auto transform = _grabbed_overlay->GetTarget()->transform;
transform.m[2][3] = glm::clamp(transform.m[2][3] - move, -5.0f, -0.1f); // moving along z axis
_grabbed_overlay->SetTransformTracker(_device_index, &transform);
}
}
void Controller::UpdateLaser()
{
auto controller_pose = _app->GetTrackerPose(_device_index);
auto controller_pos = GetPos(controller_pose);
auto forward = -glm::vec3(controller_pose[2]);
@ -92,25 +94,14 @@ void Controller::Update()
{
if (_app->IsInputJustPressed(_app->_input_handles.grab, _input_handle))
{
ray.overlay->ControllerGrab(this);
}
}
if (!_grabbed_overlays.empty())
{
float move = _app->GetInputAnalog(_app->_input_handles.distance, _input_handle).y * 0.1; // TODO use frame time
if (move != 0.0f)
{
// delta is calculated & clamped for first overlay so that child overlays don't move further than the root
float main_z = _grabbed_overlays[0]->GetTarget()->transform.m[2][3];
float new_main_z = glm::clamp(main_z - move, -5.0f, -0.1f);
float real_delta = new_main_z - main_z;
for (auto overlay : _grabbed_overlays)
if (ray.overlay->IsHeld())
{
auto transform = overlay->GetTarget()->transform;
transform.m[2][3] += real_delta;
overlay->SetTransformTracker(_device_index, &transform);
// TODO resize mode
}
else
{
_grabbed_overlay = ray.overlay;
ray.overlay->ControllerGrab(this);
}
}
}

View file

@ -23,13 +23,14 @@ class Controller
void SetHidden(bool state);
void RegisterGrabbedOverlay(Overlay *overlay);
void ReleaseOverlay(Overlay *overlay);
void ReleaseOverlay();
void Update();
void UpdateStatus();
private:
void UpdateStatus();
void UpdateLaser();
App *_app;
Overlay _laser;
ControllerSide _side;
@ -37,5 +38,5 @@ class Controller
vr::VRInputValueHandle_t _input_handle;
bool _is_connected;
bool _hidden;
std::vector<Overlay *> _grabbed_overlays;
Overlay *_grabbed_overlay;
};

View file

@ -109,10 +109,21 @@ void Overlay::SetTextureToColor(uint8_t r, uint8_t g, uint8_t b)
void Overlay::SetTransformTracker(TrackerID tracker, const VRMat *transform)
{
auto original_pose = _target.transform;
_app->vr_overlay->SetOverlayTransformTrackedDeviceRelative(_id, tracker, transform);
_target.type = TargetType::Tracker;
_target.id = tracker;
_target.transform = *transform;
auto relative_transform = ConvertMat(*transform) * glm::inverse(ConvertMat(original_pose));
for (auto child : _children)
{
if (!child->IsHeld() && child->_target.type == TargetType::Tracker)
{
VRMat local_transform = ConvertMat(relative_transform * ConvertMat(child->_target.transform));
child->SetTransformTracker(tracker, &local_transform);
}
}
}
void Overlay::SetTransformWorld(const VRMat *transform)
@ -122,6 +133,14 @@ void Overlay::SetTransformWorld(const VRMat *transform)
_target.transform = *transform;
}
void Overlay::SetTargetTracker(TrackerID tracker)
{
auto abs_mat = GetTransformAbsolute();
auto controller_mat = _app->GetTrackerPose(tracker);
VRMat relative_pose = ConvertMat(glm::inverse(controller_mat) * abs_mat);
SetTransformTracker(tracker, &relative_pose);
}
void Overlay::SetTargetWorld()
{
auto abs_pose = ConvertMat(GetTransformAbsolute());
@ -213,25 +232,16 @@ void Overlay::Update()
void Overlay::ControllerGrab(Controller *controller)
{
if (_holding_controller != nullptr)
{
_holding_controller->ReleaseOverlay(this);
}
_app->vr_overlay->SetOverlayColor(_id, 0.6f, 0.8f, 0.8f);
SetTargetTracker(controller->DeviceIndex());
auto abs_mat = GetTransformAbsolute();
auto controller_mat = _app->GetTrackerPose(controller->DeviceIndex());
VRMat relative_pose = ConvertMat(glm::inverse(controller_mat) * abs_mat);
SetTransformTracker(controller->DeviceIndex(), &relative_pose);
controller->RegisterGrabbedOverlay(this);
if (_GrabBeginCallback != nullptr)
for (auto child : _children)
{
_GrabBeginCallback(controller);
if (!child->IsHeld()) // overlay may have been picked up by other controller
{
child->SetTargetTracker(controller->DeviceIndex());
}
}
_holding_controller = controller;
}
@ -239,16 +249,34 @@ void Overlay::ControllerRelease()
{
if (_holding_controller != nullptr)
{
_holding_controller->ReleaseOverlay(this);
_holding_controller->ReleaseOverlay();
}
_app->vr_overlay->SetOverlayColor(_id, 1.0f, 1.0f, 1.0f);
auto new_pose = ConvertMat(GetTransformAbsolute());
SetTransformWorld(&new_pose);
if (_GrabEndCallback != nullptr)
SetTargetWorld();
for (auto child : _children)
{
_GrabEndCallback();
if (!child->IsHeld()) // overlay may have been picked up by other controller
{
child->SetTargetWorld();
}
}
_holding_controller = nullptr;
}
void Overlay::AddChildOverlay(Overlay *overlay)
{
_children.push_back(overlay);
}
void Overlay::RemoveChildOverlay(Overlay *overlay)
{
for (auto i = _children.begin(); i != _children.end(); i++)
{
if (*i == overlay)
{
_children.erase(i);
break;
}
}
}

View file

@ -3,6 +3,7 @@
#include "util.h"
#include <functional>
#include <string>
#include <vector>
class App;
struct Ray;
@ -49,17 +50,17 @@ class Overlay
void SetTransformTracker(TrackerID tracker, const VRMat *transform);
void SetTransformWorld(const VRMat *transform);
// void SetTargetTracker(TrackerID tracker);
void SetTargetTracker(TrackerID tracker);
void SetTargetWorld();
Ray IntersectRay(glm::vec3 origin, glm::vec3 direction, float max_len);
std::function<void(Controller *)> _GrabBeginCallback;
std::function<void()> _GrabEndCallback;
void ControllerRelease();
void ControllerGrab(Controller *controller);
void AddChildOverlay(Overlay *child);
void RemoveChildOverlay(Overlay *child);
private:
bool _initialized;
@ -73,5 +74,7 @@ class Overlay
float _ratio;
Controller *_holding_controller;
std::vector<Overlay *> _children;
Target _target;
};