Lately, I've been doing a lot of AR development for the HoloLens! Very exciting stuff, but a little rough on iteration time! Deploying to a device that has the right sensors, hardware, and setup just takes too much time, especially considering that in many cases, these sensors and hardware are already on my laptop! They're simply not accessible from within the Unity Editor by default. Adding access to them has really sped up development for a number of my use cases, so hopefully this will be of help to you as well!
If you've ever tried to use Unity's Input.acceleration, or Input.gyro.attitude, you'll know that it doesn't work unless you deploy to device. As a tool developer, even if it did work in-editor, I still wouldn't be able to use it unless Unity was actively running the game as well. So I decided to bypass everything Unity provides, and go straight to the source! This is my first real dive into native plugins for Unity, and it was much nicer than I was expecting!
If this example doesn't rotate with your device, then you either don't have a gyroscope, or your browser is out of date!
If you're not interested in the explanation, you can grab the finished .unitypackage I have up on Github! It only provides access to the gyroscope, but if you're interested in adding other sensors, or just want to know the details of it, keep reading on! :)
So first off, there's the Windows Sensor API which gives you access to all sorts of wonderful data from the C++ side! I'm a little rusty with my C++, so it took me a little bit to settle back into it. But ultimately, the documentation and examples were great, and I had a snippet of code that was doing what I wanted pretty quickly in a standalone console application!
After I had that, I set up a "Windows Desktop DLL" project with Visual Studio, and arranged my code in a format that would work well. I referenced Alan Zucconi's wonderful blog for this, it's pretty straighforward, but the core of it is that your DLL needs to export functions, and your Unity application then needs to import them!
In C++, your function declaration looks like this! Check this file to see it in context.
extern "C" {
__declspec(dllexport) Vector4 GyroGetRotation();
}
The extern "C" part tells the compiler to leave the function names the same when compiling. C++ by default will 'mangle' the names of your functions because of function overloading, so this allows you to reference the name you expect from outside the compiled code!
In C#, with your compiled DLL in any folder called "Plugins", this is how you would import that function from the DLL! And check this file to see it in full context.
[DllImport("GyroDLL", EntryPoint = "GyroGetRotation")]
static extern Quaternion GetRawRotation();
You might notice that in C++, we're returning a Vector4, and in C#, we're returning a Quaternion! Passing data to and from a DLL is called "marshalling", and marshalling your data can be a complicated topic. In this case, Vector4 is a C struct I defined in the DLL with 4 floats. This matches up to Unity's Quaternion, which is a C# struct, also with 4 floats in the same order. Passing classes is a more complicated topic, but for value types like a struct, the memory just gets copied directly in, and everything is quite straighforward!
I've put all the source for this up on Github! There's a Visual Studio project for building the DLL, and a Unity project that wraps the DLL. There's also a .unitypackage if you want to just get the functionality into your own project!
These are all super minimal projects, so they should be really easy to reference and figure out! The DLL is a single .cpp file within the Visual Studio project, and the Unity project is just the DLLs, a single wrapper file, and an example script for usage!
Enjoy! :)