Weird Rigidbody 3d behaviour when applying a force at a certain point

Godot Version

4.2

Question

Hello, I am currently making a Rigidbody 3D player controller that is a floating capsule with a raycast to detect contact with the ground and other RigidBodies under him. I use a spring-like force to maintain the player floating and wanted to apply this force in the opposite direction to the rigidbodies under the player, simulating the mass of the player. I managed to do all of this and the result is mostly what I wanted except when the player “walks” on a rigidbody with a small mass, it sometimes glitches really bad and sends everything flying. I am not really sure why this is happening but I suspect I might be applying the “player mass” force wrong.

Here is the code :

public void ApplySpringForce(GodotObject otherObject)
	{
		Vector3 rayDirection = Vector3.Down;
		Vector3 otherVelocity = Vector3.Zero;

		if(otherObject is RigidBody3D)
		{
			otherVelocity = ((RigidBody3D)otherObject).LinearVelocity;
		}

		float rayDirectionVelocity = rayDirection.Dot(RelativePlayerVelocity);
		float otherDirectionVeloctiy = rayDirection.Dot(otherVelocity);

		float relativeVelocity = rayDirectionVelocity - otherDirectionVeloctiy;

		float heightDelta = Feet.GlobalPosition.DistanceTo(Feet.GetCollisionPoint()) - RideHeight;
		//Calculate the force to achieve rideheight, with a damping value based on velocity
		float springForce = (heightDelta * RideSpringForce) - (relativeVelocity * RideSpringDamper);

		ApplyCentralForce(rayDirection * springForce);

		DebugPrint("--- Spring force debug ---");
		DebugPrint("rayDirectionVelocity = ", rayDirectionVelocity);
		DebugPrint("otherDirectionVelocity = ", otherDirectionVeloctiy);
		DebugPrint("relativeVelocity = ", relativeVelocity);
		DebugPrint("heightDelta = ", heightDelta);
		DebugPrint("springForce = ", springForce);
		DebugPrint("Applied springForce = ", rayDirection * springForce);


		//Apply a force to the object you are jumping on 
		if(otherObject is RigidBody3D)
		{
			//only apply force if the springforce is going downwards or when jumping the RB will have an upward force and be pulled with you
			if((rayDirection * -springForce).Y < 0)
			{
				// ((RigidBody3D)otherObject).ApplyForce(rayDirection * -springForce,  Feet.GetCollisionPoint() - ((RigidBody3D)otherObject).GlobalPosition);
				((RigidBody3D)otherObject).ApplyForce(rayDirection * -springForce,  Feet.GetCollisionPoint() - ((RigidBody3D)otherObject).GlobalPosition);

				DebugPrint("Point of applied force to other RB = ",  Feet.GetCollisionPoint() - ((RigidBody3D)otherObject).GlobalPosition);
				DebugPrint("Force applied to other RB = ", rayDirection * springForce );
			}
			
		}

		
	}

I set the mass of the player to be 80kg and currently walking on a 1x1x1 cube of 1kg sometimes send it flying at the speed of light when walking on the edges of it. Is there a reason this is happening ? I also made a 50kg seesaw to validate that the force was applied correctly, which works but jitter if the player is standing on an extremity “forcing” it into the ground.

Thanks a lot.

The only thing i can think of is that godot physics doesn’t work very well. I have a jointed rope that seemed to bug out if there was too much “tension” on the joints the segments would wiggle like crazy and shoot off in all directions, especially with low mass segments. To resolve this I added custom rotation inertia. this made things more stable.

Your second option is get Jolt physics plugin.

another option is to use ApplyImpulse function

1 Like

Thanks a lot for your response.

Can you explain what you did with the rotation inertia that stopped the weird behaviors ?

I tried the jolt plugin and this issue was mostly gone but the jitter is still present but barely noticeable. However, there seems to have issues with axis locks on rigidbodies: I have a seesaw to test vertical forces only with rotation locked on 2 axis. It doesn’t spin anymore and teleports me at the speed of light. I also had some rigidbodies with constant torque to rotate them, but also with some axis locked that didn’t turn anymore and also sends you flying if you touch them.

For the apply impulse function, the description of the function says not to apply it every frame (which I would be doing in my situation), so I don’t really see how I could use it.

So in the rigidbody settings there should be an inertia property. It defaults to zero and will be calculated by the mass and collision shape later ( the collision shape calculates the center of mass, while assuming the material is uniform density).

What i did was put an arbitrary value for the inertia. This makes the physics engine think the body is heavier when it comes to torque forces. Its technically less realistic, but for bodies joined together, kept them from spazing so much as joint physics can place high forces based on joint restrictions.

An alternative is to just increase the mass until it stops.

I can’t say for sure if your physics equation is okay, I feel like it could be simpler. And I’m a little confused about the relative velocity part. If both objects are moving toward each other you get a 2.0 for the relativeVelocity difference of the dot products. Which actually reduces the force equally but it should be to some proportion of mass here and I don’t see mass used at all.

Another part that may concern me is the manual calculation of the position of contact. The each body should get a collision signal to the position of contact. You could remove some math if you collected collision information from the other body where it was colliding. I’m wondering if you are closer to the edge you are actually applying a force outside the collision shape which would mean more leverage from the torque force?

Maybe it’s fine and Godot physics has its quirks…

1 Like

The calculations might be wrong, I followed the concept of this video : https://youtu.be/qdskE8PJy6Q?si=zuwS-VVWrc8beW1G&t=118
But maybe I made a mistake, I am not very good with physics. The game is based on physics so I need to have accurate values unfortunately.

For the point of collision, the player doesn’t really collide, it floats away from the ground and uses a raycast facing downward to simulate feets. I debuged the collision point and it seemed to be coherent. I am however unsure if I apply the force correctly or not. The position of the applyforce is a bit confusing in the documentation.

Okay, that is a cool system.

I took a harder look, I think your modifications and porting are correct.

The one thing I took away from the video is that most of the world is static. Except for the jumping on car example.

Which behaved as predicted. I think if the collision to ride height is negative, where the force would pull up on the body. Maybe it’s a unity thing? Hmm. Anyways

Your character is 80kg which is a lot, and I assume your spring constant is tuned to handle that mass. so stepping on a 1kg object and appling a full 80kg tuned spring force to it should result in some crazy physics.

I assume that the other object is only assigned if the collision signals are reported? Otherwise during the spring it may miss the object if near the edge? Maybe you can tune the the collision margin of the ray so it misses more, when near the edge?

1 Like

Maybe a margin change isn’t possible.

1 Like

The force vector applied to the object is something like (0,-784,0) which is the opposite of the force needed to maintain 80kg floating. So I am forced to have weird interactions when applying this force to very light objects ? I will try to investigate more into Jolt, but those axis lock behavior are quite problematic and there is even less discussions about it. Thanks a lot for your responses

One thing about springs and physics is that there is a common assumption that the anchor is static, I.e. has infinite mass.

In this case we are colliding two bodies with finite mass.

If we are free floating with a small mass on one end of the spring, the small mass will not have enough moment of inertia to push back the larger mass. So the force too the small object will cause it to get flung away, while the large mass will stay almost motionless.

This system assumes what ever object we are colliding with has infinite mass, which is incorrect if the object is in the air. If the object is against a static body like the floor then the assumption is correct.

I was reading this and it seems like your code resembles this except for the point of contact velocity, it doesn’t take into account angular velocity, and we can make it more precise if you calculate the velocity at the point of contact.

Vector3 rayDirection = Vector3.Down;
Vector3 otherVelocity = Vector3.Zero;

if(otherObject is RigidBody3D)
{
  otherPointVelocity = ((RigidBody3D)otherObject).LinearVelocity + ((RigidBody3D)otherobject).AngularVelocity.Cross(Feet.getCollisionPoint()-((RigidBody3D)otherObject).GlobalPosition));
}

float rayDirectionVelocity = rayDirection.Dot(RelativePlayerVelocity);
float otherDirectionPointVeloctiy = rayDirection.Dot(otherPointVelocity);

float relativeVelocity = rayDirectionVelocity - otherDirectionVeloctiy;
...

I think if the object begins to rotate the spring force on that object will reduce due to relative velocity.

1 Like

my last suggestion would be to use the spring joint physics object and connect it to another rigid body with a physics material removing friction/damping and gravity that will do this physics collision event for you.

1 Like

Thanks a lot for all your responses, I will check out what you sent to see if I can implement it. It seems like I will have to go with jolt if I want to use the mechanics I made as is but it is clearly still not perfect unfortunately.

Btw I was curious myself and tried implementing a spring joint. It worked okay but there are clear disadvantages from using a ray. Especially colliding with steps, I chose to increase the “foot” sphere size so it could “glide” up the step. It is not as elegant as the raycast.

I didn’t implement the pull down feature for slopes and stairs.

For a 80kg object stepping on a 1kg box still wiggles out. Changing the box to 5kg is more stable.

From what I see it seems like the force on the box is pushing it into the floor and the physics engine wants to push it back out. Alternating frames of spring push and penetration push back. I feel like all forces should be calculated before the position changes. This doesn’t seem true for Godot it seems.

I did look at the physics code and margins are used. Although I’m not sure how they could help really here.

1 Like