Extending The OVRGrabber
When working with frameworks, the last thing we want to do is directly edit the code in them, but sometime it just doesn’t have all the tools you need! Sometimes there are bits that are problematic or don’t quite work situationally. Today we are going to correct some of the issues I have with the OVRGrabber script, and we will do it by extending the script and overriding functions.
The functionality I am going to change today is:
1. Exposing the controller variable.
2. Fixing the null reparent issue
The goal of this is to not modify the original framework in anyway, while keeping everything as optimized as possible.
The first thing we need to do is Create our own Grabber Script. Mine is called OVRGrabberCustom but you can really call it whatever make sense to you. Rather than inheriting from monobehavior, we will inherit from OVRGRabber.
Exposing the Controller Variable:
The OVRGrabber, has a protected OVRInput.Controller called m_controller, but no way of returning that information if we need to see what controller is grabbing! This is important if we wanted to have the grabbed object know which hand picked it up.
We can create a return function that returns m_controller.
Now that’s all fine and dandy but how exactly do we use this?
Lets take a look at an extended grabber that would be using this function, and how exactly we would access it. Below we have a class overriding OVRGrabbable and its GrabBegin function.
Say we want to know what hand grabbed this object. It takes a parameter of our base class OVRGrabber called hand, which as we already know doesn’t have our new return function. So how can we get a hold of this function? We are going to have to cast the parameter into our new extended class.
With a null check in place, we can safely use our new function in our extended script. Now our grabbables can know what hand grabbed them.
Fixing The Null Reparent Issue:
The smoothest movement for grabbed objects seems to be when they are parented to the hand, and the OVRGrabber has a bool that enables this on pickup. The issue is whenever we release an object after its been parented, it does not go back to its original parent. This causes issues, especially in the physics interaction setup guide I just put out. At first thought, you would think you could just simply reparent it after GrabEnd, on the grabbable side. But that doesn’t work.
************************WARNING the original functionality was meant to keep you from reparenting on an offhand grab If you make this change you MUST not allow offhand grabbing or risk reparenting to your original hand******************
Lets look at the GrabbableRelease function on OVRGrabbable and see where the issue lies.
We are calling GrabEnd on the grabbable, then in the next line we are setting the parent to null. So even you reassign the parent in GrabEnd, the next line will undo it. Now there is a problem here. If you look at the function it is not virtual. Meaning we can’t override it. And if you look at the function GrabEnd() that calls this, it is not virtual either. Interestingly enough GrabBegin() is virtual. I honestly think that this is a mistake on Occulus’ side that was missed, but to align to the goal of this article and not change anything we will come up with a work around. I will also include the fix if you do want to correct it to being virtual.
The non cheater solution:
On our GrabEnd() function in our extended grabbable script(Not the grabber!), which IS virtual, we can have it invoke a reparent function at a delay of .1f. I went ahead an normalized that delay just to be safe, but it may not be entirely necessary. This will cause it to run the initial parenting code, setting it to null, and then fires off the reparent to correct it. The issue with this is that if we want this to happen on EVERY grabbable in our scene, we need to be using this extended grabbable. Which I’m not a huge fan of, but it does work and adheres to the rules of this article. We wont always access to the source code directly so it is important to think outside the box on issues like these.
It should look something along these lines:
Cheater Cheater Pumpkin Eater:
Okay. were going to break the one rule we had here, but were going to do it in the way that I think the script was truly meant to work. So we wont be allowed to directly override the GabbableRelease(). We’re not stooping that low. We will be allowed to override on GrabEnd though. GrabBegin is virtual, so GrabEnd should be as well from a logical perspective.
First we are going to make GrabEnd() virtual on the base OVRGrabber.
We need to accomplish three things. Get the parent, store the parent, and reassign the parent. And just for a little bonus we will allow the option to choose whether to reassign or make it null. Lets go ahead and create two variables in our extended grabber:
Now we need to override GrabBegin(). We don’t actually want to use the base here, because at the end of the base it assigns the grabbables parent. If we tried to assign the parent after the base implementation we would just get our grabbable back. We are going to need to copy the whole method over to our override and make our changes to it. A quick copy and paste will do the trick. The first thing you will probable notice is that we are getting an error around where it disables the grab volume. We can fix that by replacing the closestGrabbable.grabbedby with base:
Now let go down to the very bottom where we assign the parent, and record who the grabbable’s original parent was, using that _grabbedParent variable we already created.
We will now override the GrabEnd in the same way. Override it, and instead of calling base, copy the entire function over. GrabEnd is a much shorter function, go to the bottom and we finally can get a hold of our culprit.
We can delete this line and put in a new function to replace it, we will create this function right below that takes two vector 3’s as parameters: linearVelocity and angularVelocity. I’ll call mine CustomGrabbableRelease, to fit with the theme.
We are going to steal the code from what was in the original GrabbableRelease and modify it to fit our needs. You should have something that looks like the following:
Lastly we are going to check our Reassign parent bool and act accordingly.
Now we have the option of whether we would like to reparent or not! There are advantages both but its nice to be able to choose the default. ************************Do note that the original functionality was meant to keep you from reparenting on an offhand grab If you make this change you MUST not allow offhand grabbing or risk reparenting to your original hand******************