cancel
Showing results for 
Search instead for 
Did you mean: 

Grab objects with weight

Kenki
Honored Guest

Hi, I would like to know if there is a way to make that when I pick up objects they move according to their weight, for example if I pick up a heavy object, when I move my hand the hand tracking should take more time to reach the position of my real hand compared to if I was holding a lighter object, I have looked for multiple solutions but I have not been able to achieve anything yet, I appreciate any help!

1 ACCEPTED SOLUTION

Accepted Solutions

hvox1138
Protege

Muahahaha, I have attempted a funky approach, and it seems to have worked! So, while we don't provide something that does this out-of-the-box, I think it is possible to achieve the desired behavior with very little code, but it does require a slightly funky bit of setup. Essentially what you're going to do is shim the Grabbable's transformer with one that applies your own weight-influenced motion instead. In my quick test, I just used a low-pass filter on position and orientation to represent "weight," which basically means the transformer should do a damped version of what GrabFreeTransformer (the default grab ITransformer) does in the first place.

So here's the FilteredTransformer I made:

using Oculus.Interaction;
using UnityEngine;
 
public class FilteredTransformer : MonoBehaviour, ITransformer
{
    [SerializeField]
    private GrabFreeTransformer _underlyingTransformer;
 
    [SerializeField]
    private Transform _targetTransform;

    [SerializeField]
    private Transform _underlyingTargetTransform;

    [SerializeField, Range(0f, 1f)]
    private float _filterStrength = 0.05f;

    public void BeginTransform()
    {
        _underlyingTransformer.BeginTransform();
    }

    public void EndTransform()
    {
        _underlyingTransformer.EndTransform();
    }

    public void Initialize(IGrabbable grabbable)
    {
        _underlyingTransformer.Initialize(grabbable);
    }
 
    public void UpdateTransform()
    {
        _underlyingTransformer.UpdateTransform();
 
        _targetTransform.position = Vector3.Lerp(_targetTransform.position, _underlyingTargetTransform.position, _filterStrength);
        _targetTransform.rotation = Quaternion.Slerp(_targetTransform.rotation, _underlyingTargetTransform.rotation, _filterStrength);
    }
}

All this does is basically shim all the ITransformer calls through to an underlying GrabFreeTransformer, letting it do whatever it wants to some separate _underlyingTargetTransform, then filter the outcome of that GrabFreeTransformer before applying it to the real _targetTransform. Changing the _filterStrength will adjust how closely the FilteredTransformer follows the GrabFreeTransformer, which can give the impression of different weights. And that's it!

To actually use this in a scene requires a little hook-up. Here's a screenshot of my hierarchy, then one of my grab interaction GameObject, with explanations to follow:

hvox1138_0-1726687881630.png

hvox1138_1-1726687921621.png

I used the grab interaction setup you can get from the right-click menu (make a cube, right-click on the cube, Interaction SDK > Add Grab Interaction), so that's what you see in the hierarchy. You also need to make an UnderlyingTransformTarget, which is just an empty transform that the FreeGrabTransformer can apply its motion to. Note that UnderlyingTransformTarget should not be in the same hierarchical line as the cube (neither its parent nor its descendant) because we don't want the free motion affecting the filtered motion or vice versa.

Once you have your grabbable set up and UnderlyingTransformTarget available, hooking up your FilteredTransformer is just a matter of overriding your Grabbable's defaults. The Inspector view of ISDK_HandGrabInteraction is shown in the second screenshot, and as you can see I've added both a GrabFreeTransformer and a FilteredTransformer to it. The GrabFreeTransformer can be left default as we want it to just do what it normally does. For the FilteredTransformer, set its underlying transformer to the GrabFreeTransformer, its underlying target transform to UnderlyingTransformTarget (the empty game object we added to the scene), and set its target transform to Cube (or whatever it is in the scene that you actually want it to move). Then, in the Optionals section of the Grabbable, set both transformer overrides to be your FilteredTransformer, then set the Grabbable's target transform to UnderlyingTransformTarget. This last step is necessary because GrabFreeTransformer doesn't actually have a target transform of its own, it just gets and uses the Grabbable's one, so to get GrabFreeTransformer to move the empty transform instead of the cube, we have to set that up on the Grabbable.

But once that's all set up, you should be able to grab your cube and have it slowly follow the motion of your grab in a way that you control and can customize. Taking that motion and applying it also to hand tracking is something I haven't yet experimented with, but it may just work out-of-the-box if you add a scaled hand-grab pose as that will override the hand tracking during the grab interaction.

Sorry if that was kind of an information dump, but hopefully it's helpful or at least gives some interesting directions to explore in. Let me know if you get something working, and best of luck!

View solution in original post

3 REPLIES 3

MetaQuestSupport
Community Manager
Community Manager

Hi there @Kenki,

 

Thank you for posting into our forum regarding your question. Unfortunately, we wouldn't have anything available right now with changing the weight on objects in VR, but it's a very interesting idea! If you would like, you can comment this idea directly to our Ideas forum for our developers to see.

 

Thank you for posting into our forums once again and if you come up with any more ideas or have any more questions, please feel free to share them here!

hvox1138
Protege

Muahahaha, I have attempted a funky approach, and it seems to have worked! So, while we don't provide something that does this out-of-the-box, I think it is possible to achieve the desired behavior with very little code, but it does require a slightly funky bit of setup. Essentially what you're going to do is shim the Grabbable's transformer with one that applies your own weight-influenced motion instead. In my quick test, I just used a low-pass filter on position and orientation to represent "weight," which basically means the transformer should do a damped version of what GrabFreeTransformer (the default grab ITransformer) does in the first place.

So here's the FilteredTransformer I made:

using Oculus.Interaction;
using UnityEngine;
 
public class FilteredTransformer : MonoBehaviour, ITransformer
{
    [SerializeField]
    private GrabFreeTransformer _underlyingTransformer;
 
    [SerializeField]
    private Transform _targetTransform;

    [SerializeField]
    private Transform _underlyingTargetTransform;

    [SerializeField, Range(0f, 1f)]
    private float _filterStrength = 0.05f;

    public void BeginTransform()
    {
        _underlyingTransformer.BeginTransform();
    }

    public void EndTransform()
    {
        _underlyingTransformer.EndTransform();
    }

    public void Initialize(IGrabbable grabbable)
    {
        _underlyingTransformer.Initialize(grabbable);
    }
 
    public void UpdateTransform()
    {
        _underlyingTransformer.UpdateTransform();
 
        _targetTransform.position = Vector3.Lerp(_targetTransform.position, _underlyingTargetTransform.position, _filterStrength);
        _targetTransform.rotation = Quaternion.Slerp(_targetTransform.rotation, _underlyingTargetTransform.rotation, _filterStrength);
    }
}

All this does is basically shim all the ITransformer calls through to an underlying GrabFreeTransformer, letting it do whatever it wants to some separate _underlyingTargetTransform, then filter the outcome of that GrabFreeTransformer before applying it to the real _targetTransform. Changing the _filterStrength will adjust how closely the FilteredTransformer follows the GrabFreeTransformer, which can give the impression of different weights. And that's it!

To actually use this in a scene requires a little hook-up. Here's a screenshot of my hierarchy, then one of my grab interaction GameObject, with explanations to follow:

hvox1138_0-1726687881630.png

hvox1138_1-1726687921621.png

I used the grab interaction setup you can get from the right-click menu (make a cube, right-click on the cube, Interaction SDK > Add Grab Interaction), so that's what you see in the hierarchy. You also need to make an UnderlyingTransformTarget, which is just an empty transform that the FreeGrabTransformer can apply its motion to. Note that UnderlyingTransformTarget should not be in the same hierarchical line as the cube (neither its parent nor its descendant) because we don't want the free motion affecting the filtered motion or vice versa.

Once you have your grabbable set up and UnderlyingTransformTarget available, hooking up your FilteredTransformer is just a matter of overriding your Grabbable's defaults. The Inspector view of ISDK_HandGrabInteraction is shown in the second screenshot, and as you can see I've added both a GrabFreeTransformer and a FilteredTransformer to it. The GrabFreeTransformer can be left default as we want it to just do what it normally does. For the FilteredTransformer, set its underlying transformer to the GrabFreeTransformer, its underlying target transform to UnderlyingTransformTarget (the empty game object we added to the scene), and set its target transform to Cube (or whatever it is in the scene that you actually want it to move). Then, in the Optionals section of the Grabbable, set both transformer overrides to be your FilteredTransformer, then set the Grabbable's target transform to UnderlyingTransformTarget. This last step is necessary because GrabFreeTransformer doesn't actually have a target transform of its own, it just gets and uses the Grabbable's one, so to get GrabFreeTransformer to move the empty transform instead of the cube, we have to set that up on the Grabbable.

But once that's all set up, you should be able to grab your cube and have it slowly follow the motion of your grab in a way that you control and can customize. Taking that motion and applying it also to hand tracking is something I haven't yet experimented with, but it may just work out-of-the-box if you add a scaled hand-grab pose as that will override the hand tracking during the grab interaction.

Sorry if that was kind of an information dump, but hopefully it's helpful or at least gives some interesting directions to explore in. Let me know if you get something working, and best of luck!

Wow, this is an incredible solution! It worked perfectly. I only found one detail: when grabbing starts, the UnderlyingTransformTarget object always needs to be in the same position as the object you want to drag with the weight. Otherwise, as soon as you grab it, the object will move toward the current location of the UnderlyingTransformTarget. It's an easy fix, but I wanted to point it out in case this information helps someone in the future. That aside, thank you so much! You did an amazing job—I tried a thousand things, and you figured it out really quickly! Haha, I'm very grateful.