• 3D
  • Holding a Rigidbody object

For my project I'm working on a system that the player can grab a physics object akin to Half-Life 2, Soma, ... I thought a lot about it and experimented with various popular methods of picking up and holding an object so that it interacts with the world in a nice fashion. One method I tired was parenting the object to the camera so it follows the camera around, but that method resulted in very unexpected physics and collision behavior. I tried updating the position of the picked up object every physics frame to be in-front of the camera. I even believe that's how it was done in half-life 2. I also tried freezing the rigidbody object and moving it around by manually setting the linear velocity. However all of these methods resulted in several problems with collision and interaction with other geometries and physics bodies. It was not a robust and modern framework to build upon. However, I discovered a fairly good method of achieving such system and that's with the help of Joints. This setup has several advantages compared to the former/popularly used methods. This method is very easy to set up and configure. It also has a great performance advantage as it does not require to run a piece of code every frame! It is very robust and flexible. Here is the basic (camera) node setup: The static body acts as the hinge where the object will be grabbed from. It doesn't need to have a mesh and or collision. In my case its fully empty. The joint itself is a Generic6DOFJoint with almost default settings. The static body is set as Node A in the Nodes section. Node B will be left empty and will be assigned via code. This is how I've done it:

var picked_object = get_collider().get_path()
physics_joint.set_node_b(picked_object)

After executing this code, the object at the end of the raycast will automatically get pinned to the defined position and that's it! Not only this setup performs better than the formerly mentioned methods but also it reacts to external rigidbodies, forces, and collisions in a much more convincing way.

However, I'm having some trouble finalizing this setup. The biggest problem is when looking at a wall or the floor, it's easy to crush the object into a collision shape, making the physics system freak out. Essentially when looking at a wall up-close, the held object should be pushed closer to the player's face. I thought of moving the Joint position to the end of a raycast node casting from the player camera, but the problem with it is that, the picked up object is being moved around by its origin point and because of the size of the object it will result in half of the object still being crushed into a wall. Also if it gets too close to the player, it will crush into the player and will push the player in some direction.

I'm asking the community for help and for ideas on how to overcome these issues and finalize this into a setup that could be used in other projects as well. How do you think it's possible to control the position and physics handling of the picked up object so that it won't crush into the wall and the player?

Probably above my paygrade, did you create the player as a complicated rigid body or a "simpler" kinematic body? I think there are collision layers/masks that can help with this, you could perhaps put your player into a different layer as the object behind held? Just temporarily.

@Erich_L said: did you create the player as a complicated rigid body or a "simpler" kinematic body?

At the moment the player is a Kinematic body. But this is part a project that I'm working on, to make an advanced and fully viable physics driven player character. I plan to release it as a free and open-source framework.

I think there are collision layers/masks that can help with this, you could perhaps put your player into a different layer as the object behind held? Just temporarily.

Yeah that would solve the problem of the object getting jammed into the player. However, there is still the issue of the held object being jammed into walls and other objects.

It hit me out of nowhere that if the joint can be 'broken', it might solve the issue to some degree. I don't think that the Joints themselves have a breaking feature. But it might be possible to implement this via GDscript. Something like, if too much force is being applied to the held object, it simply drops. But that could introduce some new problems like the player having buttery fingers :D as everything falls from their hand with even slight collisions and also the fact that this would require a code to run every frame which defeats the point of this setup.

I experimented with such a feature a couple months ago.

The rig setup i have now is a kinematic rig controlling a rigid body character. The rig uses 6dof (actually two) with spring relations and linear limits to pilot the actual (capsule!) character body. Tweaking the spring params to your satisfaction may take a little time to gain a good intuition on how the (spring) params interplay. Absolutely consider linear limits to prevent the spring restoration force from growing too large

You may wish to implement a limiting factor on the rig (kinematic body) forcing/force application on rigid body it controls to limit the forces it may apply. For example: if the rig is some distance from the controlled object, user inputs no longer effect it and the rig is instead drawn towards the controlled object. If you are developing a frame work you might want to provide signals for this condition for UX feed back.

You should also consider using area/ray cast on the camera to get sense of its approach to scene objects because driving a camera into scenery is visually unpleasant anyway.

I prefer using spring relation on any kinematic driving a rigid-body when target bodies interact with the environment generally

In general the rig I have itself is an instance of your desired behavior because it is a kinematic body directly manipulating (an assembly of) rigid bodies via 6dof joints.

I would not recommend using a static body being moved around. Static bodies are modeled as -static- in the (Bullet) physics engine. Use a kinematic body instead which is expected to be under programmatic control.

Generally futzing with the physics simulation by injecting velocities is touchy because you can overwhelm the modeling or conflict its forward estimations and collision modeling.

Thank you for the advice @dotted but that's not what I am doing at the moment. I'm trying to create an object pickup system akin to the one in this video:

I'm trying to create an improved version of this system using joints.

Joints should work. I found 6DOF Joint to be buggy and not work well (also listed as deprecated) so I used a simple Pin Joint and it seemed to work okay. You'd also have to limit the axis (lock) so it doesn't spin around wildly. But should be fine for simple HL2 style pickups.

Right I pick up objects and carry them around half-life like except nicer. That is what the kinematic rig does it fluidly controls a rigid body character. Half life pickups and carries were quirky some times very irritating and perhaps intended to look like that but I feel like the devs worked around its behavior as one of the strange things in that universe. IIRC in several games you can drag knocked out guards around and your avatar gasps a limb while the victim rag dolls as you drag them. These simulations are actually very smooth and well implemented.

The quirky behavior in HL2 came from in essence a kinematic body forcing a rigid body against the environment and overdriving the physics simulation system (Havoc probbably)

@cybereality said: Joints should work. I found 6DOF Joint to be buggy and not work well (also listed as deprecated) so I used a simple Pin Joint and it seemed to work okay. You'd also have to limit the axis (lock) so it doesn't spin around wildly. But should be fine for simple HL2 style pickups.

I don't see 6dof as depreciated at all in the docs. There is complaint in engine about setting the params but that's because one of the parameter setting methods has been deprecated, not the joint.

6dof works, but the down side is the user interface in editor is not that nice, there is little documentation about the frame of referenced used by the joint (ie which node it is relative to) and you must have a good grasp of basic (rotationa/springl) physics and some idea of how simulations are performed.

A pin joint might seem nice until the carried object hits other physics elements, where the physics simulation will freak out.

@cybereality said: Joints should work. I found 6DOF Joint to be buggy and not work well (also listed as deprecated) so I used a simple Pin Joint and it seemed to work okay. You'd also have to limit the axis (lock) so it doesn't spin around wildly. But should be fine for simple HL2 style pickups.

Really? In my tests I had the exact opposite results. Pin joints work really poorly and 6DOF joints were superior in every way. Just as a note, I have already a working system that the object is nicely picked up using a 6DOF joint. However, I have trouble making it not get jammed into other collision objects. Quote from original post:

Not only this setup performs better than the formerly mentioned methods but also it reacts to external rigidbodies, forces, and collisions in a much more convincing way.

However, I'm having some trouble finalizing this setup. The biggest problem is when looking at a wall or the floor, it's easy to crush the object into a collision shape, making the physics system freak out. Essentially when looking at a wall up-close, the held object should be pushed closer to the player's face. I thought of moving the Joint position to the end of a raycast node casting from the player camera, but the problem with it is that, the picked up object is being moved around by its origin point and because of the size of the object it will result in half of the object still being crushed into a wall. Also if it gets too close to the player, it will crush into the player and will push the player in some direction.

I'm asking the community for help and for ideas on how to overcome these issues and finalize this into a setup that could be used in other projects as well. How do you think it's possible to control the position and physics handling of the picked up object so that it won't crush into the wall and the player?

@Leakbang said: It hit me out of nowhere that if the joint can be 'broken', it might solve the issue to some degree. I don't think that the Joints themselves have a breaking feature. But it might be possible to implement this via GDscript. Something like, if too much force is being applied to the held object, it simply drops. But that could introduce some new problems like the player having buttery fingers :D as everything falls from their hand with even slight collisions and also the fact that this would require a code to run every frame which defeats the point of this setup.

The problem is you don't really get force (delta velocity) information back.

Havoc implements a breaking system, but Bullet does not at least not exposed in godot.

You can test against distance divergence of the 'hand' and the object and sever the joint if a limit is exceeded.

Again, don't use a static body as a control. Bullet does not expect a static body to move in its simulation. If you want to move a rigid body via a joint, attach it to a kinematic body

Hmm... I don't know. Maybe I had the settings wrong since 6DOF seemed to not work right.

I went back and did some more research. The implementation in Half-Life 2 is just a series of duct tapes. It is not robust. I took a look at Soma again and the physics in that game really shine. Their in-house engine uses the Newton Dynamics physics engine. It's pretty good. This video showcases the object grabbing in Soma:

However in Godot, it seems that the Joint is holding the two objects together using an infinite amount of force. I believe limiting the force that the joint uses to hold the two nodes together would automatically solve this issue. But is it even possible to limit the value?

I loved SOMA. That thumbnail, tho, WTF!!!

I got it sort of working with the PinJoint.

The main trick is to lock angular axis while holding the object. Otherwise the physics bugs out. The other trick is to have the "hand" object (the thing that is attached to the object you are dragging) be a RigidBody but in mode Static. KinematicBodies don't work and normal StaticBodies don't work. You set visible to false and disable collisions for this hand object. The object you are grabbing is a normal RigidBody and the environment is a normal StaticBody. When you grab the object, you set the "hand" to be in the position of the center of the grabbed object, and then create a PinJoint attaching them. This works as long as you also lock all x/y/z angular axis on the grabbed object (and unlock when you let go). Otherwise things get crazy. But this is okay, as you probably don't want the object rotating as it's supposed to be in your hand. And to move, you can just move the hand object using normal methods, like adjusting the translation and the grabbed object follows. Seems to work alright.

I did try changing the staticbody 'hand' object to a rigidbody and to be honest no matter how much I tested it, I didn't see a difference. As for the axis lock, I'd say it's not helping at all. Even in your video, when the box is near the wall it starts to freak out. I played around more with the PinJoint but I still think 6DOF works better. Since there was no video of someone playing with the Soma physics, I reinstalled it and took a good look at how they did it. Their setup is surprisingly simple. They pretty much are also using a 6DOF Joint with a huge difference, it's the force limit. The joint setup that they have in Soma has a limit. In Godot that force is infinite, that's why the object is getting jammed in the wall and other horrible interactions are happening. In soma if the player tries to hold a heavy object like a chair, the chair is grabbed by the 'hand' joint, but because the weight of the chair is higher than the Joint's maximum force, the player can only limply push/drag it around. Bullet is pretty extensive... I'd reckon this must be implemented in it. This might already even exist in Godot. The question is how to do it. :s Perhaps tagging the engine contributors and bringing this post to their attention would also help.

I haven't tried any of this, but it seems like you want to carry a kinematic body, and then just destroy it and make an identical rigidbody when you want to let it loose with physics, or just hide it or something. Or else, just change the shape of the player kinematic body while carrying a mesh that represents it.

It already works, my video is almost there. The reason it was jumping on the wall is because I didn't put a constraint on the hand, (so it was clipping through the wall or behind it). In a real game, you would use ray casts or separate physics layers to stop the hand from getting into impossible positions, and this would work fine.

Bullet can definitely do it, it's fully featured, but I'm not sure how much is exposed in Godot. Theoretically the 6DOF Joint would be the answer, and might allow for greater range of movement (as with the Pin Joint you can't do rotations without it bugging out) but like I said, the 6DOF Joint is difficult to work with. But I'm sure you could do it in Godot, it's just that it's not well documented and no one has figured it out.

@fire7side that would work for simple stuff (like picking up a photo in Resident Evil) but in games like SOMA and HL2 the objects are part of the physics system. So you can be holding them and brush them against the wall and they will react realistically.

I made some more progress. The problem with the Pin Joint was that you need to set the Joint position to the hand position right before you link the objects together. Otherwise there is a weird offset and that was causing the glitch with rotations. So it's working a lot better. I still need to get collision on the hand, I'll work on it more tomorrow and do another video.

@cybereality said: It already works, my video is almost there. The reason it was jumping on the wall is because I didn't put a constraint on the hand, (so it was clipping through the wall or behind it). In a real game, you would use ray casts or separate physics layers to stop the hand from getting into impossible positions, and this would work fine. I already have a raycast in my setup. Actually I should've showcased my setup earlier. Here it is:

the box in the center of the screen represents the 'hand' object. You can see that if I look at a close wall, the hand position moves to the position where the raycast hits. This setup is using the 6DOF joint, pretty much with the default settings.

You can see at 0:30 that even when the hand object is floating in the air, the movement of the box is jittery. That's because of the infinite force it is applying to the box. Also you can see that I can push and throw other objects while holding the can.

Okay, I got it working for real this time.

It was actually pretty complicated. Basically, there are 4 objects. The object you want to grab (the box in my video), which is a RigidBody. The object that is pulling the box, which is a StaticBody. This is what is attached to the PinJoint. A KinematicBody which is what is actually moving, you could think of this as your hand. And the fourth object is just a Vector3, which is the position of where you want to move your hand to.

So basically, you only ever adjust this invisible position vector, and then setup the rest so they follow each other. You can adjust the position freely by any method depending on your game. Then the KinematicBody (which is what handles the wall collision) has a script which follows the invisible position. You must use move_and_slide so that the physics and collision work (but put it only another collision layer so it only collides with the environment and not the things you are grabbing). The move_and_slide finds the difference between the current KinematicBody position and the invisible vector, and creates a pretty fast velocity that will keep them in the same place. That is the first part. And this solves the clipping into the wall. The KinematicBody is just a sphere, with a size equal to the size of the box. If you have different sized objects, then you would need to adjust the physics shape to roughly equal the grabbed object.

Then you set the StaticBody (the thing attached to the object you actually want to grab) to the position of the KinematicBody. You can just set the translation direction equal to each other, this is easy. Now since the RigidBody is attached to the StaticBody already with a PinJoint, it moves automatically without any additional code. So that is the basic setup.

I also set the RigidBody to lock axis when being grabbed, but to unlock once it touches something. So while you are holding it in the air it is stable and solid, but as soon as you brush by the wall, it will allow rotation. It is also unlocked if you let go or throw it.

This was pretty crazy and complex, but it's actually not a lot of code. The project I have is too big, but I could look into making a minimal project as an example, if the directions are not clear. Really glad I got this working.

One other trick. You have to make sure the invisible vector doesn't get too far into the wall. So check every frame that the distance between the vector and the KinematicBody is not more than some small amount, and it is it larger, than set the vector equal to the KinematicBody position.

My mind's been blown. Impressive work @cybereality @Leakbang. To be fair tho I don't ever remember anytime the object grabber in HL2 didn't work as expected. Expectations toward physics change I guess?

@cybereality said:

This was pretty crazy and complex, but it's actually not a lot of code. The project I have is too big, but I could look into making a minimal project as an example, if the directions are not clear. Really glad I got this working.

Demo for the demo repository, blood for the blood gods - wait no. Just demo for the demo repo?

Where are you @Leakbang? I hope you see the video, I stayed up all night to finish it.

@Megalomaniak Yeah, I want to keep working on it and release a demo. Right now I don't have the licenses for the textures I downloaded, so I want to make my own art and do a proper demo. And there are a few last things I need to figure out. One is that you can't zoom the object in and out with the scroll wheel smoothly when it is touching the wall (which I avoided for the video). It should theoretically work, but there is a bug somewhere. So I have to fix that. I also smoothed out the camera and added a few more features (so you can rotate the object in your hand like Resident Evil and other games).

So I worked on it a bit more. Got mouse smoothing so the camera is more fluid. Finally got rotations working 100%, no more axis lock. Changed the zoom feature to work with the mouse instead of the scroll wheel and now it doesn't glitch out when hitting the wall. Added a feature to rotate the object in your hand. A random spin when throwing the object. And more smoothing on the drag point with a low pass filter and a 10 frame average, which gets rid of any small remaining jitter.

The trick to get the rotation working was to override _integrate_forces. This is what handles the physics, and you can add your own code to this function and basically do whatever you want to the state before it gets updated on the screen. So in this case I clamped the angular velocity so it could not get too high (by default there is no limit).

extends RigidBody

export var max_angular = 10.0

func _integrate_forces(state):
	if state.angular_velocity.length() > max_angular:
		state.angular_velocity = state.angular_velocity.normalized() * max_angular

It's pretty much working how I want. I need to make some of my own art and maybe a more interesting test scene before I release it.

@cybereality said: @Megalomaniak And there are a few last things I need to figure out. One is that you can't zoom the object in and out with the scroll wheel smoothly when it is touching the wall (which I avoided for the video). It should theoretically work, but there is a bug somewhere.

There's probably no bug at all, you are perhaps just taking the scroll wheel input directly without interpolating it? Scroll wheels in terms of the actual input are never smooth, but in steps - even if a company like say logitech makes the scroll wheel physically feel smooth on their mice. I guess you could think of the scroll wheel input like a pulse width modulation function either inputting 1 or -1 as a value(and 0 for no change). Speed of scrolling is determined by the frequency/width of pulses.

Unless it's only in the case of when touching the wall? In which case, could it be friction?

I was using the scroll wheel like a button. When it detected a change it would start a tween and then lock the input for the duration of the tween. All the code looked right, and I printed the values and they were in an okay range, but something about it didn't work right with the physics. In any case, I changed it so you hold the middle mouse button down and drag the mouse in and out and that works a lot better and looks better too.

Mouse positional x & y should work out per frame as float values, so that makes sense. I really thought a tween would work for the mouse wheel tho.

I apologize for my sudden absence. I saw both your videos @cybereality and they look pretty good. I couldn't notice any jittering. I'll try to implement and test your method and I'll give an update on how it goes.

@Erich_L said: My mind's been blown. Impressive work @cybereality @Leakbang. To be fair tho I don't ever remember anytime the object grabber in HL2 didn't work as expected. Expectations toward physics change I guess?

Yeah looking back at Half-Life 2, it doesn't stand the test of time in various aspects. It was a game that at the time was known for having an interactable world with a lot of dynamic/physics elements. It uses the Havoc physics engine... which is serviceable in my opinion, but it had a lot of limitations. Probably the most popular one being that objects freak out when stacked on top of each other. Bullet is so much better in comparison to Havoc. I'm a bit saddened that it'll be removed from Godot 4, but I believe that the Godot's physics engine will also be competent.

Godot Physics is alright. It works better for some stuff, but it behaves differently, so you can't just freely switch between them. Bullet is okay, but I think a custom solution is better long term as it can be tailored for Godot and also easier to fix bugs.

So I went and I did some more extensive tests with @cybereality 's model. I genuinely think it's pretty good, but for my use case, since there are a lot of physics interactions, it is not good enough. I went back to Soma and recorded this short clip:

A noteworthy point is at 1:10 when I fill up a trash can and try to fill it with other objects then pick it up. You could see that it's much harder to move the bin vertically and when I try to move it around, it feels like there is an invisible bouncy spring holding the object (like a yoyo :D). Also, I can't move heavy objects with light objects even when holding them. I think that currently, it is impossible to achieve this in Godot (I really hope I'm wrong). There are many various ways to fake this effect as already discussed in this thread, but I think there is no way to it for real.

I'm pretty sad as I can't continue with my project until this is implemented :disappointed:

This is an area that Godot could really use some improvements in. I believe the 2 main missing properties are 1. the maximum amount of force the joint can apply and 2. the breaking tolerance for the joint. When the tolerance is exceeded, the joint is broken. (This could be done with GDScript even now, but it would open new doors when it's actually integrated in the engine)

It would be great if others also give out their suggestions so we could compile all of these requested features and reach out to the maintainers to have these features added to Godot.

I don't think it's impossible. I put together that demo in 3 days, and it went from looking like Godot physics were totally broken to looking quite good. I think SOMA quality physics should be doable. The main difference is that SOMA is using spring joints and my demo was based on pin joints. Pin joints are not the right choice here, but they were easier for me to work with and I got decent results. But they are limited because you are setting a fixed distance. With a spring joint you can get more flexible behavior, like objects getting caught on other objects or pushing back and forth. I think it should be possible with 6 DOF joint in Godot, but I need to spend more time with it because it wasn't working well when I first tried it (though I learned a lot so far, so maybe it will be easier the second time around).

Also, in terms of the weight, there are a few ways to do this. One you could have everything in the game simulated by physics. Like in my demo I was moving the target point directly based on the mouse position. But if instead the hand was a rigid body, and the movement was based on applying forces, then all the physics should just work (including gravity and mass). However, this is hard to control and can be inconsistent. The other option would be to use a kinematic body and simply modify the control speed based on the weight of the object. So if the object was twice as heavy, the mouse would move twice as slow.

This is a hack, but it would give more repeatable control and easier to tweak. You could also fake gravity in this way, like if you are holding a heavy object then the camera moves down a certain amount each frame. This could be done in a more physically accurate manner with spring joints, if you could detect the pressure and adjust the camera/objects to move better. So if there is a large pull you could slow the camera to simulate resistance. You can also change the spring parameters based on the pressure/distance, which is what I think they did in SOMA. Like in the part where you catch the vacuum on the couch, when it jumps over the edge, it doesn't snap to the other side. With a fixed spring it would snap quickly. So they must relax the spring when there is a certain amount of force so that objects don't snap too fast.

But I don't see why all this would not be possible in Godot. It's just a matter of figuring out if 6 DOF Joint actually works, and exposes enough data to make the calculations. For example, we need to know the pressure of the joint (unknown), the forces on the object (this we know), the mass (we know), and whether you can modify joints (for example the spring distance) in real-time and not mess up the physics engine.

Oh my god, I think you're right, I think it's possible now as well. Great observation that they are using a spring joint. Originally, I thought this property was broken in Godot, but I went back and figured out what the problem was. This actually works simpler than I thought. I still haven't nailed the physics properties yet, but I believe this is the way to go. With springs in a 6DOF joint, the exact joint shown in the Soma demo can be replicated. Here are the instructions: Add 6DOF Joint Disable all linear limits Enable the angular and linear springs for each axis Profit

Originally, I always had the linear limits activated and the effects of it overpowered everything... so that's why I thought the other properties are broken.

I am filled with jubilation :D Thank you again @cybereality . You've helped a lot and provided a lot of insightful information. Without your help it wouldn't have been possible!

Now all that remains is to play with the physics properties and match values that work nicely. I will definitely upload a video showcasing it.

Also, this setup is pretty minimal. All you need is: A 6DOFJoint, A staticbody for the hand, a rigidbody to move around, and a simple piece of code to attach the rigidbody to the Joint.

So here's a demo video showcasing the effect in Godot:

It took a lot of tinkering with the values to get it to function nicely. I'd say this compares pretty well to the system they have in Soma. The line is connecting the invisible hand object with the held object. Just a debug tool to help me figure it out. I still don't like the way it stretches like the cheese on a pizza. Also the further the hand is from the held object, the joint applies more force. So a simple piece of code needs to be implemented to lower the Stiffness of the joint, the further the hand is from the held object.

I'm pretty happy as we got the basic setup working. What do you think?