Need help with two Configurable joints ! (Two hands grab in VR)

Hi !

Sorry for my bad english, I will do my best

I’m facing a problem with my grab system that I’m working on, it might be a very long post as I need to breakdown my code to explain clearly the process, so take a deep breath, here we go.
Some codes and images are hosted on an external service avoiding this post a moderation validation

The goal

I’m currently working on a VR project using the SteamVR asset from the assets store, my goal is to be able to grab any object with a specific tag. So I wrote my own script for that, I can pick an object and throw it, it works fine. I’m using a “configurable joint” for that and I’m pretty happy with the result.

So this is a cleaned version of my script, I removed every line that’s not part of the grabbing system

https://pastebin.com/SR4Spu25
you can find the complete script here.

The Issue

The issue comes when I want to grab the only weapon available in the game, which is a sniper rifle. On this weapon, I'm able to grab it with two hands. When I grab it with one hand (it don't really matter if you grab with your left or right hand, the script handle it), it grab the weapon like I want. But when I grab it with two hand, something magically(not really) happens, it flips my weapon upside down. Let me illustrate this with some fancy screenshots:

So, as I said, when I pick up the weapon with one hand, everything is fine, the weapon is well oriented.
But when I try to grab it with my second hand, the world is turning upside down (the weapon huh… not the world)

https://i.imgur.com/ynYzntd.png

BUT !
What I noticed is if I flip the first controller towards me, the weapon is correctly oriented again, like this:

https://i.imgur.com/y4j0njs.png

The breakdown

I'm gonna explain step by step how I come to this point by splitting the code above and explain it, but if you don't need it, you can skip this part.

So first, I have a GameObject variable called “inHand”, this variable is setted by two functions “OnTriggerEnter” and “OnTriggerExit”. by doing this, I’m just telling to the grab system: “Hey, there is this object beneath you in case the player press the grip button” (I don’t remember exactly why I’ve done it this way, but it is not important for resolving the issue imo).

void OnTriggerEnter(Collider col) {
	if (col.gameObject != inHand && col.tag == "Interactable") {
		inHand = col.gameObject;
	}
}

void OnTriggerExit(Collider col) {
	if (col.gameObject == inHand) {
		inHand = null;
	}	
}

In the Update function, there is this simple condition:

if (gripAction.GetStateDown (hand.handType)){
    if (cj == null && inHand != null) {
        cj = createJoint(inHand);
    }
}

This simply call the “createJoint” function if the user press a particular button on the vive controller (in this case, the grip button), and if there is something stored in the “inHand” variable, then create a joint linked with this object.

Now, we are in the “createJoint” function, this is where it connect the controller with the object. So i start by adding a Configurable Joint to the object and getting his Rigidbody.

ConfigurableJoint joint = gameObject.AddComponent(typeof(ConfigurableJoint)) as ConfigurableJoint;
Rigidbody objRb = obj.GetComponent<Rigidbody>();

Then, I check if there is a script attached to the object called “AnchorSetter”. It’s a simple script that return a “Transform” for the anchor position set below. If there is no anchor point available, it return null.

AnchorSetter anchors = obj.GetComponent<AnchorSetter> ();

if (anchors != null) {
	Transform nextAnchor = anchors.getNextAnchor();

	if (nextAnchor != null) {
		joint.autoConfigureConnectedAnchor = false;
		currentAnchor = nextAnchor;
		joint.anchor = Vector3.zero;
		joint.connectedAnchor = nextAnchor.localPosition;
	}
}

At this point, you might be screaming and flipping your desk for what I wrote above, but meh ¯\(ツ)

So the last bit of code is setting some stuff for the configurable joint

if (other.cj == null || other.cj.connectedBody != objRb) {
	obj.transform.eulerAngles = transform.eulerAngles;
	joint.angularXMotion = ConfigurableJointMotion.Locked;
	joint.angularYMotion = ConfigurableJointMotion.Locked;
	joint.angularZMotion = ConfigurableJointMotion.Locked;
}
			
joint.xMotion = ConfigurableJointMotion.Locked;
joint.yMotion = ConfigurableJointMotion.Locked;
joint.zMotion = ConfigurableJointMotion.Locked;

joint.connectedBody = objRb;
return joint;

The condition you can see simply tell if there is no hands that is already grabbing this object then do this. (btw, the “other” variable is set in the inspector, it refers to the opposite handscript)

I’m locking the “motion” on every axe no matter what, but I’m locking the “angular motion” if there is no hand that is already grabbing the object, then I align the object with the controller by setting his “eulerAngles”. What I’m trying to achieve here is, when you grab the weapon with the “main hand”, basically the one that is gonna be placed near the weapon trigger, I want the player to be able to lean the rifle sideway with the “main hand”. This condition is telling to the script: “Hey, if the player grab the weapon with one hand, just stick the weapon to his hand and keep track of his position and rotation, but if it’s the “second hand”, just ignore his orientation but track his position”.

So now you’ve read this giant post, you can take a break, go get some water, and if you want, help me with this :slight_smile:

As i’m really struggling with the “Configurable Joint” documentation, I’m thinking the issue come from the “createJoint” function, there is something that I missed but I can’t figure it out. As it is very specific, I will not be surprise if nobody can resolve this problem, but if you try, feel free to ask any question.

Up please !

I’m aware I could use VRTK instead, but I really want to make this myself.