mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-08 00:00:20 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab5e80a8ef | ||
|
|
ffb301b38c | ||
|
|
9744585cf0 | ||
|
|
7cf363e315 | ||
|
|
9c4a906ec0 | ||
|
|
d6030195f9 | ||
|
|
c607fa30c4 | ||
|
|
eebf2877f3 |
No files matched your search
@@ -273,9 +273,12 @@ void ResetAndDisableOffsets(uint32_t id)
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
static_assert(vr::k_unTrackedDeviceIndex_Hmd == 0, "HMD index expected to be 0");
|
||||
|
||||
void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
ctx.enabled = ctx.validProfile;
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
@@ -292,20 +295,12 @@ void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (!ctx.validProfile)
|
||||
if (!ctx.enabled)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
{
|
||||
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("REF %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
@@ -317,6 +312,21 @@ void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
|
||||
std::string trackingSystem(buffer);
|
||||
|
||||
if (id == vr::k_unTrackedDeviceIndex_Hmd)
|
||||
{
|
||||
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("HMD %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
|
||||
if (trackingSystem != ctx.referenceTrackingSystem)
|
||||
{
|
||||
// Currently using an HMD with a different tracking system than the calibration.
|
||||
ctx.enabled = false;
|
||||
}
|
||||
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trackingSystem != ctx.targetTrackingSystem)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
@@ -333,7 +343,7 @@ void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
if (ctx.chaperone.valid && ctx.chaperone.autoApply)
|
||||
if (ctx.enabled && ctx.chaperone.valid && ctx.chaperone.autoApply)
|
||||
{
|
||||
uint32_t quadCount = 0;
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(nullptr, &quadCount);
|
||||
@@ -465,6 +475,7 @@ void CalibrationTick(double time)
|
||||
req.setDeviceTransform = { ctx.targetID, true, vrTrans };
|
||||
Driver.SendBlocking(req);
|
||||
|
||||
ctx.validProfile = true;
|
||||
SaveProfile(ctx);
|
||||
CalCtx.Message("Finished calibration, profile saved\n");
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ struct CalibrationContext
|
||||
std::string referenceTrackingSystem;
|
||||
std::string targetTrackingSystem;
|
||||
|
||||
bool enabled = false;
|
||||
bool validProfile = false;
|
||||
double timeLastTick = 0, timeLastScan = 0;
|
||||
double wantedUpdateInterval = 1.0;
|
||||
@@ -46,6 +47,21 @@ struct CalibrationContext
|
||||
messages += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
chaperone.geometry.clear();
|
||||
chaperone.standingCenter = vr::HmdMatrix34_t();
|
||||
chaperone.playSpaceSize = vr::HmdVector2_t();
|
||||
chaperone.valid = false;
|
||||
|
||||
calibratedRotation = Eigen::Vector3d();
|
||||
calibratedTranslation = Eigen::Vector3d();
|
||||
referenceTrackingSystem = "";
|
||||
targetTrackingSystem = "";
|
||||
enabled = false;
|
||||
validProfile = false;
|
||||
}
|
||||
};
|
||||
|
||||
extern CalibrationContext CalCtx;
|
||||
|
||||
@@ -14,7 +14,10 @@ static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream);
|
||||
|
||||
static std::string ConfigFileName()
|
||||
{
|
||||
std::string vrRuntimeConfigName = vr::VR_RuntimePath();
|
||||
char cruntimePath[MAX_PATH] = { 0 };
|
||||
unsigned int pathLen;
|
||||
vr::VR_GetRuntimePath(cruntimePath, MAX_PATH, &pathLen);
|
||||
std::string vrRuntimeConfigName(cruntimePath);
|
||||
return vrRuntimeConfigName + "\\..\\..\\..\\config\\01spacecalibrator\\calibration.json";
|
||||
}
|
||||
|
||||
@@ -104,7 +107,7 @@ static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream)
|
||||
LoadFloatArray(
|
||||
chaperone["standing_center"],
|
||||
(float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter) / sizeof(float)
|
||||
sizeof(ctx.chaperone.standingCenter.m) / sizeof(float)
|
||||
);
|
||||
|
||||
if (!chaperone["geometry"].is<picojson::array>())
|
||||
@@ -130,6 +133,12 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
|
||||
std::ofstream file(ConfigFileName());
|
||||
|
||||
if (!ctx.validProfile)
|
||||
{
|
||||
file << "[]";
|
||||
return;
|
||||
}
|
||||
|
||||
picojson::object profile;
|
||||
profile["reference_tracking_system"].set<std::string>(ctx.referenceTrackingSystem);
|
||||
profile["target_tracking_system"].set<std::string>(ctx.targetTrackingSystem);
|
||||
@@ -146,13 +155,13 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
chaperone["auto_apply"].set<bool>(ctx.chaperone.autoApply);
|
||||
chaperone["play_space_size"].set<picojson::array>(FloatArray(ctx.chaperone.playSpaceSize.v, 2));
|
||||
|
||||
chaperone["standing_center"].set<picojson::array>(
|
||||
FloatArray((float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter) / sizeof(float)
|
||||
chaperone["standing_center"].set<picojson::array>(FloatArray(
|
||||
(float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter.m) / sizeof(float)
|
||||
));
|
||||
|
||||
chaperone["geometry"].set<picojson::array>(
|
||||
FloatArray((float *) ctx.chaperone.geometry.data(),
|
||||
chaperone["geometry"].set<picojson::array>(FloatArray(
|
||||
(float *) ctx.chaperone.geometry.data(),
|
||||
sizeof(ctx.chaperone.geometry[0]) / sizeof(float) * ctx.chaperone.geometry.size()
|
||||
));
|
||||
|
||||
@@ -169,8 +178,6 @@ void SaveProfile(CalibrationContext &ctx)
|
||||
profilesV.set<picojson::array>(profiles);
|
||||
|
||||
file << profilesV.serialize(true);
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
static void UpgradeProfileV1(CalibrationContext &ctx)
|
||||
@@ -197,41 +204,3 @@ static void UpgradeProfileV1(CalibrationContext &ctx)
|
||||
file.close();
|
||||
std::remove("openvr_space_calibration.txt");
|
||||
}
|
||||
|
||||
void WriteActivateMultipleDriversToConfig()
|
||||
{
|
||||
std::string configPath = vr::VR_RuntimePath();
|
||||
configPath += "\\..\\..\\..\\config\\steamvr.vrsettings";
|
||||
|
||||
std::ifstream ifile(configPath);
|
||||
if (!ifile.good())
|
||||
throw std::runtime_error("failed to read steamvr.vrsettings");
|
||||
|
||||
picojson::value v;
|
||||
std::string err = picojson::parse(v, ifile);
|
||||
if (!err.empty())
|
||||
throw std::runtime_error(err);
|
||||
|
||||
ifile.close();
|
||||
|
||||
if (!v.is<picojson::object>())
|
||||
throw std::runtime_error("steamvr.vrsettings is empty");
|
||||
|
||||
auto &root = v.get<picojson::object>();
|
||||
|
||||
if (!root["steamvr"].is<picojson::object>())
|
||||
throw std::runtime_error("steamvr.vrsettings is missing \"steamvr\" key");
|
||||
|
||||
auto &steamvr = root["steamvr"].get<picojson::object>();
|
||||
|
||||
const bool tru = true; // MSVC picks the wrong specialization when passing a literal...
|
||||
steamvr["activateMultipleDrivers"].set<bool>(tru);
|
||||
|
||||
std::ofstream ofile(configPath);
|
||||
if (!ofile.good())
|
||||
throw std::runtime_error("failed to write steamvr.vrsettings");
|
||||
|
||||
v.serialize(std::ostream_iterator<char>(ofile), true);
|
||||
|
||||
std::cout << "Successfully set activateMultipleDrivers to true" << std::endl;
|
||||
}
|
||||
@@ -4,4 +4,3 @@
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx);
|
||||
void SaveProfile(CalibrationContext &ctx);
|
||||
void WriteActivateMultipleDriversToConfig();
|
||||
@@ -119,13 +119,45 @@ void TryCreateVROverlay()
|
||||
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(overlayMainHandle, 3.0f);
|
||||
vr::VROverlay()->SetOverlayInputMethod(overlayMainHandle, vr::VROverlayInputMethod_Mouse);
|
||||
vr::VROverlay()->SetOverlayFlag(overlayMainHandle, vr::VROverlayFlags_SendVRScrollEvents, true);
|
||||
vr::VROverlay()->SetOverlayFlag(overlayMainHandle, vr::VROverlayFlags_SendVRDiscreteScrollEvents, true);
|
||||
|
||||
std::string iconPath = cwd;
|
||||
iconPath += "\\icon.png";
|
||||
vr::VROverlay()->SetOverlayFromFile(overlayThumbnailHandle, iconPath.c_str());
|
||||
}
|
||||
|
||||
void ActivateMultipleDrivers()
|
||||
{
|
||||
vr::EVRSettingsError vrSettingsError;
|
||||
bool enabled = vr::VRSettings()->GetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool, &vrSettingsError);
|
||||
|
||||
if (vrSettingsError != vr::VRSettingsError_None)
|
||||
{
|
||||
std::string err = "Could not read \"" + std::string(vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool) + "\" setting: "
|
||||
+ vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
vr::VRSettings()->SetBool(vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool, true, &vrSettingsError);
|
||||
if (vrSettingsError != vr::VRSettingsError_None)
|
||||
{
|
||||
std::string err = "Could not set \"" + std::string(vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool) + "\" setting: "
|
||||
+ vr::VRSettings()->GetSettingsErrorNameFromEnum(vrSettingsError);
|
||||
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
std::cerr << "Enabled \"" << vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool << "\" setting" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "\"" << vr::k_pch_SteamVR_ActivateMultipleDrivers_Bool << "\" setting previously enabled" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void InitVR()
|
||||
{
|
||||
auto initError = vr::VRInitError_None;
|
||||
@@ -148,6 +180,8 @@ void InitVR()
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVROverlay_Version");
|
||||
}
|
||||
|
||||
ActivateMultipleDrivers();
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
@@ -192,10 +226,11 @@ void RunLoop()
|
||||
char buf[0x400];
|
||||
ImGui::GetActiveText(buf, sizeof buf);
|
||||
buf[0x3ff] = 0;
|
||||
uint32_t unFlags = 0; // EKeyboardFlags
|
||||
|
||||
vr::VROverlay()->ShowKeyboardForOverlay(
|
||||
overlayMainHandle, vr::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine,
|
||||
"Space Calibrator Overlay", sizeof buf, buf, false, 0
|
||||
unFlags, "Space Calibrator Overlay", sizeof buf, buf, 0
|
||||
);
|
||||
keyboardOpen = true;
|
||||
}
|
||||
@@ -214,7 +249,7 @@ void RunLoop()
|
||||
case vr::VREvent_MouseButtonUp:
|
||||
io.MouseDown[vrEvent.data.mouse.button == vr::VRMouseButton_Left ? 0 : 1] = false;
|
||||
break;
|
||||
case vr::VREvent_Scroll:
|
||||
case vr::VREvent_ScrollDiscrete:
|
||||
io.MouseWheelH += vrEvent.data.scroll.xdelta * 360.0f * 8.0f;
|
||||
io.MouseWheel += vrEvent.data.scroll.ydelta * 360.0f * 8.0f;
|
||||
break;
|
||||
@@ -342,7 +377,11 @@ static void HandleCommandLine(LPWSTR lpCmdLine)
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
printf("%s", vr::VR_RuntimePath());
|
||||
char cruntimePath[MAX_PATH] = { 0 };
|
||||
unsigned int pathLen;
|
||||
vr::VR_GetRuntimePath(cruntimePath, MAX_PATH, &pathLen);
|
||||
|
||||
printf("%s", cruntimePath);
|
||||
vr::VR_Shutdown();
|
||||
exit(0);
|
||||
}
|
||||
@@ -421,12 +460,12 @@ static void HandleCommandLine(LPWSTR lpCmdLine)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteActivateMultipleDriversToConfig();
|
||||
ActivateMultipleDrivers();
|
||||
ret = 0;
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
std::cerr << "Failed to set activateMultipleDrivers: " << e.what() << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <algorithm>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#define VERSION_STRING "0.8"
|
||||
#define VERSION_STRING "0.9.0"
|
||||
|
||||
struct VRDevice
|
||||
{
|
||||
@@ -62,6 +62,12 @@ void BuildMainWindow(bool runningInOverlay)
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
if (CalCtx.validProfile && !CalCtx.enabled)
|
||||
{
|
||||
ImGui::TextColored(ImColor(0.8f, 0.2f, 0.2f), "Reference (%s) HMD not detected, profile disabled", CalCtx.referenceTrackingSystem.c_str());
|
||||
ImGui::Text("");
|
||||
}
|
||||
|
||||
float width = ImGui::GetWindowContentRegionWidth(), scale = 1.0f;
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
@@ -86,9 +92,8 @@ void BuildMainWindow(bool runningInOverlay)
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.calibratedRotation = Eigen::Vector3d();
|
||||
CalCtx.calibratedTranslation = Eigen::Vector3d();
|
||||
CalCtx.validProfile = false;
|
||||
CalCtx.Clear();
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
# OpenVR-SpaceCalibrator
|
||||
# OpenVR Space Calibrator
|
||||
|
||||
Use VR devices from one company with any other.
|
||||
Use tracked VR devices from one company with any other.
|
||||
|
||||
This is **beta software** and may not work for you. A quick video walkthrough of the calibration process is available at https://www.youtube.com/watch?v=W3TnQd9JMl4
|
||||
This is **experimental software** and may not work for your setup. It's well-tested for the Rift with Vive trackers though, with a community of a few hundred users ([Discord][]). It also seems to work for various HMDs (Windows MR, Rift) with Vive controllers and Knuckles prototypes. A quick video of how this works using an old version (~v0.3) is available at https://www.youtube.com/watch?v=W3TnQd9JMl4.
|
||||
|
||||
## Usage
|
||||
[Discord]: https://discord.gg/m7g2Wyj
|
||||
|
||||
### Install
|
||||
|
||||
Before following the directions below, download and run the installer for the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases). This will automatically set up SteamVR for use with multiple tracking systems (`activateMultipleDrivers: true`).
|
||||
|
||||
### Usage
|
||||
|
||||
Once Space Calibrator has a calibration, it works in the background to keep your devices configured correctly. Since v0.8, everything aside from creating the calibration is automated.
|
||||
|
||||
### Calibration
|
||||
|
||||
If you don't already run a setup with multiple device types, see [Setting up SteamVR](#setting-up-steamvr).
|
||||
As part of first time setup, or when you make a change to your space (e.g. move a sensor), and occasionally as the calibration drifts over time (consumer VR tracking isn't perfectly stable), you'll need to run a calibration:
|
||||
|
||||
1. Download and unzip the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases) of OpenVR-SpaceCalibrator.
|
||||
2. Run SteamVR, and turn on your Touch controllers and only one Vive device to use for calibration.
|
||||
3. Run OpenVR-SpaceCalibrator.
|
||||
4. Hold the left Touch controller and your Vive device in your left hand securely, like they're glued together.
|
||||
5. Click "Start Calibration"
|
||||
6. Wave your left hand around, like you're calibrating the compass on your phone. You want to get as many orientations as possible.
|
||||
7. Done! A profile will be saved automatically. You can turn on the rest of your Vive devices now.
|
||||
1. Copy the chaperone/guardian bounds from your HMD's play space. This doesn't need to be run if your HMD's play space hasn't changed since last time you copied it. __Example:__ if you're using the Rift with Vive trackers and you bump a Vive lighthouse, or if the calibration has just drifted a little, you likely don't need to run this step, but if you bump an Oculus sensor you will (after running Oculus guardian setup again).
|
||||
1. Run SteamVR, with only devices from your HMD's tracking system powered on. __Example:__ for Rift with Vive trackers, don't turn on the trackers yet.
|
||||
2. Confirm your chaperone/guardian is set up with the walls in the right place. If you change it later, you need to run step again.
|
||||
3. Open SPACE CAL in the SteamVR dashboard overlay.
|
||||
4. Click `Copy Chaperone Bounds to profile`
|
||||
|
||||
Next time you run SteamVR, open OpenVR-SpaceCalibrator and it will load the calibration automatically and apply it devices you turn on.
|
||||
2. Calibrate devices.
|
||||
1. Open SteamVR if you haven't already. Turn on some or all your devices.
|
||||
2. Open SPACE CAL in the SteamVR dashboard overlay.
|
||||
3. Select one device from the reference space on the left and one device from the target space on the right. If you turned on multiple devices from one space and can't tell which one is selected, click "Identify selected devices" to blink an LED or vibrate it. __Example:__ for Rift with Vive trackers, you'll see the Touch controllers on the left, and Vive trackers on the right. __Pro tip:__ if you turn on just one Vive tracker, you don't have to figure out which one is selected.
|
||||
4. Hold these two devices in one hand, like they're glued together. If they slip, calibration won't work as well.
|
||||
5. Click `Start Calibration`
|
||||
6. Move and rotate your hand around slowly a few times, like you're calibrating the compass on your phone. You want to sample as many orientations as possible.
|
||||
7. Done! A profile will be saved automatically. If you haven't already, turn on all your devices. Space Calibrator will automatically apply the calibration to devices as they turn on.
|
||||
|
||||
### Calibration outside VR
|
||||
|
||||
### Setting up SteamVR
|
||||
|
||||
Every hardware designer with their own tracking system needs to make a "driver"
|
||||
so SteamVR can see their tracking data. SteamVR by default will load only one driver at a time,
|
||||
but we can tell it to load all of them by editing the vrsettings config file.
|
||||
|
||||
Open `Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings` in a text editor,
|
||||
look for the line that has `"activateMultipleDrivers": false` and change the `false` to `true`.
|
||||
In some guides online you may also see references to `requireHmd`, this does _not_ need to be changed
|
||||
unless you truly want to be able to run without any kind of HMD.
|
||||
|
||||
Sometimes when SteamVR updates this file seems to get wiped, if your setup stops working you might
|
||||
have to edit the config again.
|
||||
|
||||
You can calibrate without using the dashboard overlay by unminimizing Space Calibrator after opening SteamVR (it starts minimized). This is required if you're calibrating for a lone HMD without any devices in its tracking system.
|
||||
|
||||
### Compiling your own build
|
||||
|
||||
1. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
|
||||
Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build. There are no external dependencies.
|
||||
|
||||
|
||||
## The math
|
||||
### The math
|
||||
|
||||
See [math.pdf](https://github.com/pushrax/OpenVR-SpaceCalibrator/blob/master/math.pdf) for details.
|
||||
If you have some ideas for how to improve the calibration process, let me know!
|
||||
Binary file not shown.
Binary file not shown.
+1981
-351
File diff suppressed because it is too large.
Load diff
+1501
-190
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user