mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-07 16:00:22 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d1fa11f98 |
No files matched your search
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Justin Li
|
||||
Copyright (c) 2020 Justin Li
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -113,7 +113,7 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
}
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Got %zd samples with %zd delta samples\n", samples.size(), deltas.size());
|
||||
CalCtx.Message(buf);
|
||||
CalCtx.Log(buf);
|
||||
|
||||
// Kabsch algorithm
|
||||
|
||||
@@ -155,7 +155,7 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
Eigen::Vector3d euler = rot.eulerAngles(2, 1, 0) * 180.0 / EIGEN_PI;
|
||||
|
||||
snprintf(buf, sizeof buf, "Calibrated rotation: yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[2], euler[0]);
|
||||
CalCtx.Message(buf);
|
||||
CalCtx.Log(buf);
|
||||
return euler;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ Eigen::Vector3d CalibrateTranslation(const std::vector<Sample> &samples)
|
||||
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Calibrated translation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
|
||||
CalCtx.Message(buf);
|
||||
CalCtx.Log(buf);
|
||||
return transcm;
|
||||
}
|
||||
|
||||
@@ -214,15 +214,15 @@ Sample CollectSample(const CalibrationContext &ctx)
|
||||
bool ok = true;
|
||||
if (!reference.bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Reference device is not tracking\n"); ok = false;
|
||||
CalCtx.Log("Reference device is not tracking\n"); ok = false;
|
||||
}
|
||||
if (!target.bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Target device is not tracking\n"); ok = false;
|
||||
CalCtx.Log("Target device is not tracking\n"); ok = false;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
CalCtx.Message("Aborting calibration!\n");
|
||||
CalCtx.Log("Aborting calibration!\n");
|
||||
CalCtx.state = CalibrationState::None;
|
||||
return Sample();
|
||||
}
|
||||
@@ -361,7 +361,7 @@ void StartCalibration()
|
||||
{
|
||||
CalCtx.state = CalibrationState::Begin;
|
||||
CalCtx.wantedUpdateInterval = 0.0;
|
||||
CalCtx.messages = "";
|
||||
CalCtx.messages.clear();
|
||||
}
|
||||
|
||||
void CalibrationTick(double time)
|
||||
@@ -406,26 +406,26 @@ void CalibrationTick(double time)
|
||||
|
||||
if (ctx.referenceID == -1)
|
||||
{
|
||||
CalCtx.Message("Missing reference device\n"); ok = false;
|
||||
CalCtx.Log("Missing reference device\n"); ok = false;
|
||||
}
|
||||
else if (!ctx.devicePoses[ctx.referenceID].bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Reference device is not tracking\n"); ok = false;
|
||||
CalCtx.Log("Reference device is not tracking\n"); ok = false;
|
||||
}
|
||||
|
||||
if (ctx.targetID == -1)
|
||||
{
|
||||
CalCtx.Message("Missing target device\n"); ok = false;
|
||||
CalCtx.Log("Missing target device\n"); ok = false;
|
||||
}
|
||||
else if (!ctx.devicePoses[ctx.targetID].bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Target device is not tracking\n"); ok = false;
|
||||
CalCtx.Log("Target device is not tracking\n"); ok = false;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
ctx.state = CalibrationState::None;
|
||||
CalCtx.Message("Aborting calibration!\n");
|
||||
CalCtx.Log("Aborting calibration!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ void CalibrationTick(double time)
|
||||
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Starting calibration, referenceID=%d targetID=%d\n", ctx.referenceID, ctx.targetID);
|
||||
CalCtx.Message(buf);
|
||||
CalCtx.Log(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -444,15 +444,15 @@ void CalibrationTick(double time)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CalCtx.Message(".");
|
||||
|
||||
const int totalSamples = 100;
|
||||
static std::vector<Sample> samples;
|
||||
samples.push_back(sample);
|
||||
|
||||
if (samples.size() == totalSamples)
|
||||
CalCtx.Progress(samples.size(), CalCtx.SampleCount());
|
||||
|
||||
if (samples.size() == CalCtx.SampleCount())
|
||||
{
|
||||
CalCtx.Message("\n");
|
||||
CalCtx.Log("\n");
|
||||
if (ctx.state == CalibrationState::Rotation)
|
||||
{
|
||||
ctx.calibratedRotation = CalibrateRotation(samples);
|
||||
@@ -477,7 +477,7 @@ void CalibrationTick(double time)
|
||||
|
||||
ctx.validProfile = true;
|
||||
SaveProfile(ctx);
|
||||
CalCtx.Message("Finished calibration, profile saved\n");
|
||||
CalCtx.Log("Finished calibration, profile saved\n");
|
||||
|
||||
ctx.state = CalibrationState::None;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,14 @@ struct CalibrationContext
|
||||
double timeLastTick = 0, timeLastScan = 0;
|
||||
double wantedUpdateInterval = 1.0;
|
||||
|
||||
enum Speed
|
||||
{
|
||||
FAST = 0,
|
||||
SLOW = 1,
|
||||
VERY_SLOW = 2
|
||||
};
|
||||
Speed calibrationSpeed = FAST;
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
|
||||
struct Chaperone
|
||||
@@ -40,14 +48,6 @@ struct CalibrationContext
|
||||
vr::HmdVector2_t playSpaceSize;
|
||||
} chaperone;
|
||||
|
||||
std::string messages;
|
||||
|
||||
void Message(const std::string &msg)
|
||||
{
|
||||
messages += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
chaperone.geometry.clear();
|
||||
@@ -62,6 +62,54 @@ struct CalibrationContext
|
||||
enabled = false;
|
||||
validProfile = false;
|
||||
}
|
||||
|
||||
size_t SampleCount()
|
||||
{
|
||||
switch (calibrationSpeed)
|
||||
{
|
||||
case FAST:
|
||||
return 100;
|
||||
case SLOW:
|
||||
return 250;
|
||||
case VERY_SLOW:
|
||||
return 500;
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
struct Message
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
String,
|
||||
Progress
|
||||
} type = String;
|
||||
|
||||
Message(Type type) : type(type) { }
|
||||
|
||||
std::string str;
|
||||
int progress, target;
|
||||
};
|
||||
|
||||
std::vector<Message> messages;
|
||||
|
||||
void Log(const std::string &msg)
|
||||
{
|
||||
if (messages.empty() || messages.back().type == Message::Progress)
|
||||
messages.push_back(Message(Message::String));
|
||||
|
||||
messages.back().str += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
|
||||
void Progress(int current, int target)
|
||||
{
|
||||
if (messages.empty() || messages.back().type == Message::String)
|
||||
messages.push_back(Message(Message::Progress));
|
||||
|
||||
messages.back().progress = current;
|
||||
messages.back().target = target;
|
||||
}
|
||||
};
|
||||
|
||||
extern CalibrationContext CalCtx;
|
||||
|
||||
@@ -97,6 +97,9 @@ static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream)
|
||||
ctx.calibratedTranslation(1) = obj["y"].get<double>();
|
||||
ctx.calibratedTranslation(2) = obj["z"].get<double>();
|
||||
|
||||
if (obj["calibration_speed"].is<double>())
|
||||
ctx.calibrationSpeed = (CalibrationContext::Speed)(int) obj["calibration_speed"].get<double>();
|
||||
|
||||
if (obj["chaperone"].is<picojson::object>())
|
||||
{
|
||||
auto chaperone = obj["chaperone"].get<picojson::object>();
|
||||
@@ -149,6 +152,9 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
profile["y"].set<double>(ctx.calibratedTranslation(1));
|
||||
profile["z"].set<double>(ctx.calibratedTranslation(2));
|
||||
|
||||
double speed = (int) ctx.calibrationSpeed;
|
||||
profile["calibration_speed"].set<double>(speed);
|
||||
|
||||
if (ctx.chaperone.valid)
|
||||
{
|
||||
picojson::object chaperone;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <algorithm>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#define VERSION_STRING "0.9.0"
|
||||
#define VERSION_STRING "0.9.2"
|
||||
|
||||
struct VRDevice
|
||||
{
|
||||
@@ -33,31 +33,41 @@ VRState LoadVRState();
|
||||
void BuildSystemSelection(const VRState &state);
|
||||
void BuildDeviceSelections(const VRState &state);
|
||||
void BuildProfileEditor();
|
||||
void BuildMenu(bool runningInOverlay);
|
||||
|
||||
static const ImGuiWindowFlags bareWindowFlags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
|
||||
void BuildMainWindow(bool runningInOverlay)
|
||||
{
|
||||
ImGuiWindowFlags windowFlags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(io.DisplaySize, ImGuiSetCond_Always);
|
||||
|
||||
if (!ImGui::Begin("MainWindow", nullptr, windowFlags))
|
||||
if (!ImGui::Begin("MainWindow", nullptr, bareWindowFlags))
|
||||
{
|
||||
ImGui::End();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImGui::GetStyleColorVec4(ImGuiCol_Button));
|
||||
|
||||
auto state = LoadVRState();
|
||||
BuildSystemSelection(state);
|
||||
BuildDeviceSelections(state);
|
||||
BuildMenu(runningInOverlay);
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void BuildMenu(bool runningInOverlay)
|
||||
{
|
||||
auto &io = ImGui::GetIO();
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
ImGui::Text("");
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
@@ -125,6 +135,26 @@ void BuildMainWindow(bool runningInOverlay)
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Text("");
|
||||
auto speed = CalCtx.calibrationSpeed;
|
||||
|
||||
ImGui::Columns(4, NULL, false);
|
||||
ImGui::Text("Calibration Speed");
|
||||
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(" Fast ", speed == CalibrationContext::FAST))
|
||||
CalCtx.calibrationSpeed = CalibrationContext::FAST;
|
||||
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(" Slow ", speed == CalibrationContext::SLOW))
|
||||
CalCtx.calibrationSpeed = CalibrationContext::SLOW;
|
||||
|
||||
ImGui::NextColumn();
|
||||
if (ImGui::RadioButton(" Very Slow ", speed == CalibrationContext::VERY_SLOW))
|
||||
CalCtx.calibrationSpeed = CalibrationContext::VERY_SLOW;
|
||||
|
||||
ImGui::Columns(1);
|
||||
}
|
||||
else if (CalCtx.state == CalibrationState::Editing)
|
||||
{
|
||||
@@ -141,22 +171,6 @@ void BuildMainWindow(bool runningInOverlay)
|
||||
ImGui::Button("Calibration in progress...", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2));
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x - 40.0f, io.DisplaySize.y - 40.0f), ImGuiSetCond_Always);
|
||||
if (ImGui::BeginPopupModal("Calibration Progress", nullptr, windowFlags))
|
||||
{
|
||||
ImGui::TextWrapped(CalCtx.messages.c_str());
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
ImGui::Text("");
|
||||
if (ImGui::Button("Close", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(10.0f, ImGui::GetWindowHeight() - ImGui::GetItemsLineHeightWithSpacing()));
|
||||
ImGui::BeginChild("bottom line", ImVec2(ImGui::GetWindowWidth() - 20.0f, ImGui::GetItemsLineHeightWithSpacing() * 2), false);
|
||||
ImGui::Text("OpenVR Space Calibrator v" VERSION_STRING " - by tach/pushrax");
|
||||
@@ -167,7 +181,38 @@ void BuildMainWindow(bool runningInOverlay)
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x - 40.0f, io.DisplaySize.y - 40.0f), ImGuiSetCond_Always);
|
||||
if (ImGui::BeginPopupModal("Calibration Progress", nullptr, bareWindowFlags))
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor(0, 0, 0));
|
||||
for (auto &message : CalCtx.messages)
|
||||
{
|
||||
switch (message.type)
|
||||
{
|
||||
case CalibrationContext::Message::String:
|
||||
ImGui::TextWrapped(message.str.c_str());
|
||||
break;
|
||||
case CalibrationContext::Message::Progress:
|
||||
float fraction = (float)message.progress / (float)message.target;
|
||||
ImGui::Text("");
|
||||
ImGui::ProgressBar(fraction, ImVec2(-1.0f, 0.0f), "");
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetFontSize() - style.FramePadding.y * 2);
|
||||
ImGui::Text(" %d%%", (int)(fraction * 100));
|
||||
break;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
ImGui::Text("");
|
||||
if (ImGui::Button("Close", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void BuildSystemSelection(const VRState &state)
|
||||
@@ -233,13 +278,14 @@ void BuildSystemSelection(const VRState &state)
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(paneWidth);
|
||||
ImGui::Combo("##TargetTrackingSystem", ¤tTargetSystem, &targetSystems[0], (int) targetSystems.size());
|
||||
|
||||
if (currentTargetSystem != -1 && currentTargetSystem < targetSystems.size())
|
||||
{
|
||||
CalCtx.targetTrackingSystem = std::string(targetSystems[currentTargetSystem]);
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void AppendSeparated(std::string &buffer, const std::string &suffix)
|
||||
@@ -428,10 +474,8 @@ void BuildProfileEditor()
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Yaw", &CalCtx.calibratedRotation(1), 0.1, 1.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Pitch", &CalCtx.calibratedRotation(2), 0.1, 1.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Roll", &CalCtx.calibratedRotation(0), 0.1, 1.0, "%.8f");
|
||||
|
||||
TextWithWidth("XLabel", "X", width);
|
||||
@@ -440,14 +484,12 @@ void BuildProfileEditor()
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("ZLabel", "Z", width);
|
||||
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##X", &CalCtx.calibratedTranslation(0), 1.0, 10.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Y", &CalCtx.calibratedTranslation(1), 1.0, 10.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Z", &CalCtx.calibratedTranslation(2), 1.0, 10.0, "%.8f");
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void TextWithWidth(const char *label, const char *text, float width)
|
||||
|
||||
Reference in new issue
Block a user