• Projects
  • 3Dconnexion Space Mouse Support in Godot

I've been looking into this project for @Kojack , to support the 3Dconnexion 3D mice, like the SpaceMouse and SpaceNavigator in Godot. For those that don't know, this is a mouse that supports 6DOF (rotation and translation) and makes it very easy to move the camera and position objects in 3D space.

I think I figured it out, but it's a little harder than I initially thought. It might take me about a week to get working. The basic idea is that you make an EditorPlugin. See here:

https://docs.godotengine.org/en/3.4/tutorials/plugins/editor/making_main_screen_plugins.html

You'll also need a GDNative plugin to access the native shared libraries for the mouse:

https://docs.godotengine.org/en/stable/tutorials/scripting/gdnative/index.html

Then you can get access to the editor interface windows with EditorInterface:

https://docs.godotengine.org/en/stable/classes/class_editorinterface.html

From there you would use get_editor_viewport() to get the viewport, and then search through that to find the camera.

I still need at least a couple days to get a prototype together, but I have some of the pieces working on their own with command line apps. So maybe like a week to get it working. Will be fun to try this with my stereo 3D plug-in.

Here is the code that finds the camera given a viewport:

func find_camera(node) :
	var children = node.get_children()
	for child in children:
		if child is Camera:
			return child
	for child in children:
		return find_camera(child)

Nice.

I just went to find the camera code I was testing, and the gd script file is missing from my project. I think it was that damn fast boot thing that screwed things up recently after I reinstalled windows. Of course it didn't help that I was testing the camera stuff in Godot 4, before the alpha came out (I got the repo and built it myself). The docs were a bit out of date. :) The camera code I was using was from here: https://github.com/me2beats/godot-tips-and-tricks/issues/15 Your one is a lot simpler. :)

I really need to buy a new Connexion. Not just because the buttons are a bit jammed on my Space Pilot Pro, but also because their newer devices have a different protocol. I use HID to access the devices, but I can't test my reverse engineering without one of the newer ones. Maybe a Space Mouse Enterprise, although I never used the LCD screen of my Space Pilot Pro.

I've got the Space Navigator (wired) and Space Pilot Pro. Started with the Navigator, now I keep it at work and use the bigger one at home.

After using one with the palm rest, I don't like going back to the smaller one. Not because I actually need a palm rest, but because that holds it down so hard upwards movement doesn't lift the thing off the desk.

Yeah, that makes sense. I have to touch it lightly because it moves too much. But usually it's not too bad.

4 months later

So I resumed this project. It's sort of working now, @Kojack . I used the libspnav, so it only works on Linux, but I kind of don't feel like supporting the proprietary SDK. There may be a way to compile for Windows/OSX but I'll have to look into that later. I'm getting all the values for position and rotation in Godot. Right now I am just moving a cube, but I will hook it up to the camera tomorrow. The results are kind of wonky since I'm using Euler, I think I have to convert to quaternion, but that shouldn't be hard.

cybereality Hey, yep notifications work. I was asleep until 30min ago. 🙂

Nice.
Yeah, I don't use their proprietary sdk either. I use direct HID access using HIDAPI from http://github.com/signal11/hidapi
It's windows, linux, bsd and osx. The connexion protocol is really simple. The great thing about HID level is it doesn't need drivers installed, so I can plug my space navigator or pilot pro into any PC and use it (in my own apps) without admin permissions to install the official drivers. That's handy at work where classroom computers don't let me admin.

The annoying thing is they've changed the protocol for newer devices and I can't test they work. I want to buy a new one, but they don't sell to australia directly and resellers add over $100. Plus their educational discount system is "Page not found" for me. Oh well.

Since you generously gifted me one, should you need someone to help with testing, just let me know.

I see right. I'm using this SDK, but now that I look at it, I'm not sure if it can compile for anything but Linux.

https://github.com/FreeSpacenav/libspnav

However, I will finish what I have because it's like 75% there and it if seems good I can look into how to support other platforms. I have the older and newer space nav devices, so figuring out the HID protocol shouldn't be too difficult. I'll look into that later.

The old protocol is basically:

#pragma pack(push,1)
struct Packet
{
	unsigned char type;
	union
	{
		struct
		{
			short x;
			short z;
			short y;
		};
		unsigned char bytes[6];
	};
};
#pragma pack(pop)

If type is 1, the shorts are position offsets. If type is 2, they are euler rotations. If type is 3, the x and y are bitfields for buttons (32 bit).

Thanks @Megalomaniak . I should be able to figure it out, I have a bunch of computers for testing, though that will probably be a good idea once I am ready to release something.

Oh yeah, that is dirt simple. Okay. I will probably go with that, because I don't think I could release it into the wild only supporting Linux. Though let me work with what I have for now and finish the rest of it and see if it is even worthwhile.

Hmm, the Connexion forums say that their wireless devices are harder to use through HID. That's annoying. I have no use for a wireless connexion, I wasn't planning on getting one (the Enterprise model has no wireless option anyway).

I also see that the official Linux sdk hasn't been updated in 17 years, so it may be a little out of date. Probably a good idea to go with libspnav instead. 🙂

    So I made some progress. I can now move the viewport camera around. The axis are all messed up, so I'll need to do some math, but both translation and rotation are getting correct values from the device.

    My issue now is that after moving with the spacenav, if you use the mouse/keyboard to move it snaps back to the previous position (before you moved with the spacenav). I guess the editor has it's own copy of the transform it uses, so I may have to hook into that rather than modifying the camera directly. Hopefully that is possible with a plugin and won't need source access.

    I also had to rewrite the function to find the camera. That code works for a game, but not in the editor. In the editor you have to find the Viewports and then get the Camera from that. Here is the new function.

    func find_camera(node, list) :
    	if node is Viewport:
    		var camera = node.get_camera()
    		list.append(camera)
    		return list
    	for child in node.get_children():
    		find_camera(child, list)
    	return list

    And you can call it like this:

    var editor = get_editor_interface()
    var viewport = editor.get_editor_viewport()
    var results = find_camera(viewport, [])
    var camera = results[1]

    The number 1 is needed because I have 1 user camera in my scene (results[0], the first editor camera is results[1]). If I had more, that would be a different number. It would also be a higher number if you used the split view for multiple view angles in the editor. I'll have to figure out a way to determine where you are looking rather than hard-coding the index.

    Kojack I also see that the official Linux sdk hasn't been updated in 17 years, so it may be a little out of date. Probably a good idea to go with libspnav instead. 🙂

    Yeah, the fact that they haven't updated the Linux SDK in 2 decades doesn't make me eager to support them. Like it's not even a lot of work, the drivers are fairly simple and they basically abandoned Linux.

    So I kept looking into it, and no, it is not possible without a source code change. The editor camera transform is controlled by a class called Cursor and is updated in the file spatial_editor_plugin.cpp. However, it holds it's own state, it does not read it from the editor viewport camera. Meaning even though I can move the camera, the state is not maintained (as soon as you start altering the camera with the mouse or keyboard it will revert to the previous state). So it's not going to work. Sorry, @Kojack

    Oh well. Thanks for looking into it.

    I guess I'll just hack the Godot source. 🙂