Jump to content

Rigidbody physics in KSP


Recommended Posts

I'm trying to make a vessel jump with the given velocity on ground contact by using rigidBody.AddForce(force, ForceMode.VelocityChange).

Briefly, the problem is that the vessel reacts to the approximately same vertically applied force differently when it is on the ground or when it just touches the surface after falling down.

What I've tried:

When a vessel is landed and settled on the ground, applying a force straight up with a magnitude of 0.5 .. 1 has no significant effect instead of making the vessel change it vertical velocity. Even changing to ForceMode.Acceleration that should apply a constant force does nothing. But if I change to ForceMode.Impulse the magnitude of 0.01, it is engough to have a minimal significant effect on the vessel.

So my thoughts are: When I use AddForce(force, ForceMode.VelocityChange), in fact it tells the physics to apply force to the rigidbody to make equivalent velocity change. But there's another force in the opposite direction that counters it - the gravity, that's why it has no effect. ForceMode.Impulse uses impulse, i.e. mass * velocity. So having magnitude of 0.01 m/s and mass around 1000 kg I have impulse equal to 10 that is just above the 9,8 m/s^2 of gravity and that let's the vessel feel the punch. Is that right?

So I add -g vector to my force to overcome gravity and have the desired effect. Unless when the vessel is not settled on the ground but falls down, the effect is that it bounces back up at excessive velocity every time it touches the surface and it starts to feel like the added -g is redundant. EVAs also seem to be overpushed, being Kraken-ejected to the sky and vaporized at 243 m/s.

The question: how to properly manage both landed and fallen down vessels to react to the vertical force in the same and proper way? In both cases the vessels have landed = true state and their parts have GroundContact = true.

 

 

Edited by Ser
Link to comment
Share on other sites

Do you apply force in every update or only once? If its the latter then ofc it would not work as expected. AddForce is meant to be maintained in each FixedUpdate to be meaningful, with the exception of Impulse type

Link to comment
Share on other sites

1 minute ago, Ziw said:

Do you apply force in every update or only once? If its the latter then ofc it would not work as expected. AddForce is meant to be maintained in each FixedUpdate to be meaningful, with the exception of Impulse type

I apply it only once. In fact it should simulate a momentary impulse disregarding the vessel's mass, so I have no idea how long should I maintain it. Should I use the Impulse type with magnitude divided by mass instead?

Link to comment
Share on other sites

On 5/21/2016 at 8:12 AM, Ser said:

Thanks.

Dividing by mass doesn't work well for massive vessels, so using just Impulse type seems to suite my needs best although I don't fully understand the math behind it.

You multiply by mass.

Newtons 2nd law states F = MA

You want to increase your upwards velocity by 0.01 + g m/s, which is an acceleration of 0.01 + g.

To get the correct Force, you multiply Mass by Acceleration. F = MA.

Alternatively you could use the VelocityChange ForceMode, and just use 0.01 + g as the magnitude, without mucking about with masses.

 

Side note:
The difference between the ForceModes are as follows:

Force - A regular force. Applying a force of 1kN for 1 second on a 1kg object speeds it up to 1m/s.

Acceleration - An acceleration. Applying an acceleration of 1kN for 1 second speeds the object up to 1m/s regardless of mass.

Impulse - An impulse force. Applying an impulse of 1kN for 1 frame on a 1kg object speeds it up to 1m/s.

VelocityChange - A change in velocity. Applying a velocity change of 1kN for 1 frame speeds the object up to 1m/s regardless of mass.

 

Side note 2:
You can get the vector for gravity (gravity is not always down because of round planets) by using the following code:

var gravityVector = FlightGlobals.getGeeForceAtPosition (vessel.GetWorldPos3D ());

The vessel.GetWorldPos3D() function gets the worldspace position of the vessel.

For your purposes, you'd do this to apply an upwards impulse of 0.01m/s:

var impulseVector = gravityVector.normalized * (gravityVector.magnitude * -(1 + impulseSpeed)); //impulseSpeed is 0.01m/s in this case

You'd take the impulseVector and use it in the rigidbody.AddForce function.

Edited by MrHappyFace
side note 2
Link to comment
Share on other sites

Thanks, MrHappyFace

I know the basic physics but something was useful.

17 hours ago, MrHappyFace said:

Alternatively you could use the VelocityChange ForceMode, and just use 0.01 + g as the magnitude, without mucking about with masses.

As I've said in the OP, the problem is when I do so, it behaves differently under various conditions in KSP. As if when a vessel stands on the ground it is pulled down with gravity, but if it falls and touches the surface then it isn't. So I've tried to use the Impulse mode to change velocity as its effect is more predictable. As impulse is v * m, I've tried to divide it by mass to get the plain velocity but it seems like using just Impulse without modifications suits well.

Edited by Ser
Link to comment
Share on other sites

4 hours ago, Ser said:

Thanks, MrHappyFace

I know the basic physics but something was useful.

....

As impulse is v * m, I've tried to divide it by mass to get the plain velocity but it seems like using just Impulse without modifications suits well.

Impulse is not v * m.

(Note that acceleration is change in velocity and velocity is change in position.)

In unity, you pass a vector into the AddForce function, which is used as a force when it's in Force or Impulse mode, and an acceleration when it's in Acceleration or VelocityChange mode.

That means that the resulting change in velocity (acceleration), in Force and Impulse mode can be calculated easily by solving for A in the equation F = MA.

F = MA

(input of AddForce function) = (mass of rigidbody) * A

(input of AddForce function) / (mass of rigidbody) = A

Now, assuming you input a force of 1kN with a mass of 10kg, you get this acceleration:

F = MA

1kN = 10kg * A

1kN / 10kg = A

A = 1/10m/s or 0.1m/s

If you add a 10kN force to a mass of 1kg, you get this:

F = MA

10kN = 1kg * A

10kN / 1kg = A

A = 10m/s

From this, we can see that (in force or impuse mode) it requires a greater force to accelerate more massive objects by the same amount, so we increase the force by multiplying it by the mass, NOT dividing it by the mass like (I think) you were doing.

Of course you can bypass masses and forces entirely by just using Acceleration or VelocityChange modes, and just pass the desired acceleration in directly.

 

EDIT: I reread your first post, and now I'm not entirely sure I know what the problem is. I though it was that the AddForce was behaving differently in different conditions, but that doesn't seem logical. Are you applying the force upwards as in (0, 1, 0), or upwards as in negative gravity. The gravity in KSP isn't always down, or even consistent for different positions, so you need to use the function getGeeForceAtPosition I explained in my first post. Also, are you using AddForce or AddRelativeForce, because if you're using AddRelativeForce, then the force would be applied in different directions based on the orientation of the rigidbody. Some source code would be immensely helpful.

Edited by MrHappyFace
added EDIT
Link to comment
Share on other sites

1 hour ago, MrHappyFace said:

 

EDIT: I reread your first post, and now I'm not entirely sure I know what the problem is. I though it was that the AddForce was behaving differently in different conditions, but that doesn't seem logical. Are you applying the force upwards as in (0, 1, 0), or upwards as in negative gravity. The gravity in KSP isn't always down, or even consistent for different positions, so you need to use the function getGeeForceAtPosition I explained in my first post. Also, are you using AddForce or AddRelativeForce, because if you're using AddRelativeForce, then the force would be applied in different directions based on the orientation of the rigidbody. Some source code would be immensely helpful.

 

The source code is different now because I decided to rely on Impulse instead of VelocityChange with -g vector.

And I calculate the gravity vector slightly different. It looked as something like this:
 

Vector3 straightDown = (vessel.mainBody.position - vessel.GetWorldPos3D()).normalized;

double gAtAltitude = 6.67408f / Math.Pow(10, 11) * vessel.mainBody.Mass / Math.Pow(vessel.mainBody.Radius + vessel.altitude, 2); // just g calculation

vessel.parts.ForEach( part -> 
	{
		if (part.GroundContact) {
			part.rigidBody.AddForce(deltaVelocity - gAtAltitude * straightDown, ForceMode.VelocityChange);
		}
	});

deltaVelocity was a vector pointing straight up with magnitudes 0.01 - 1.0.

This had the effect I've described earlier: a vessel standing on the ground received a tiny punch. But if the vessel was falling down and touched the ground it bounced up pretty high. If the vessel was a standing EVA kerbal, he was thrown even higher being teared apart by Kraken forces.

Edited by Ser
Link to comment
Share on other sites

1 hour ago, MrHappyFace said:

Now, assuming you input a force of 1kN with a mass of 10kg, you get this acceleration:

F = MA

1kN = 10kg * A

1kN / 10kg = A

A = 1/10m/s or 0.1m/s

I think you've made a mistake with your units here:

Quote

Definition. A newton (N) is the international unit of measure for force. One newton is equal to 1 kilogram meter per second squared. In plain English, 1 newton of force is the force required to accelerate an object with a mass of 1 kilogram 1 meter per second per second.

...so your results are 1000 times too small and the units should be m/s².

Link to comment
Share on other sites

29 minutes ago, Ser said:

The source code is different now because I decided to rely on Impulse instead of VelocityChange with -g vector.

And I calculate the gravity vector slightly different. It looked as something like this:
 


Vector3 straightDown = (vessel.mainBody.position - vessel.GetWorldPos3D()).normalized;

double gAtAltitude = 6.67408f / Math.Pow(10, 11) * vessel.mainBody.Mass / Math.Pow(vessel.mainBody.Radius + vessel.altitude, 2); // just g calculation

vessel.parts.ForEach( part -> 
	{
		if (part.GroundContact) {
			part.rigidBody.AddForce(deltaVelocity - gAtAltitude * straightDown, ForceMode.VelocityChange);
		}
	});

This had the effect I've described earlier: a vessel standing on the ground received a tiny punch. But if the vessel was falling down and touched the ground it bounced up pretty high. If the vessel was a standing EVA kerbal, he was thrown even higher being teared apart by Kraken forces.

Why not do this:

public float impulseSpeed = 0.01;

//...

var gravityVector = FlightGlobals.getGeeForceAtPosition (vessel.GetWorldPos3D ());
var impulseVector = gravityVector.normalized * (gravityVector.magnitude * -(1 + impulseSpeed));

vessel.parts.ForEach( part -> 
	{
		if (part.GroundContact) {
			part.rigidBody.AddForce(impulseVector, ForceMode.VelocityChange);
		}
	});

The function getGeeForceAtPosition is the standard way to calculate gravity, used by stock code and all the mods I've seen, and it's probably more optimized than yours is. Math.Pow function calls are relatively expensive too.

Also, I'm pretty sure the EVA thing was because EVA kerbals don't take kindly to odd forces. I've had a kerbal fly into to the air at 100m/s for hitting the ground in ragdoll mode.

19 minutes ago, Padishar said:

I think you've made a mistake with your units here:

...so your results are 1000 times too small and the units should be m/s².

Yup, you're right. I was in the mindset of KSP where everything is listed as kilonewtons and tonnes. :P

I meant m/s as in that's how much the velocity was increased in that frame. It doesn't make much sense to use m/s2 when we're dealing with instantaneous impulses. Impulses last one frame, and frames are of variable length, although meters per frame squared might work.

Edited by MrHappyFace
Link to comment
Share on other sites

4 minutes ago, MrHappyFace said:

Why not do this:

The function getGeeForceAtPosition is the standard way to calculate gravity, used by stock code and all the mods I've seen, and it's probably more optimized than yours is. Math.Pow function calls are relatively expensive too.

 

I'll try that of course, thanks for pointing me out the getGeeForceAtPosition. But doesn't your code do exactly the same job? I don't see anything that could solve the bouncing vessels mystery. I've logged and visualized the forces every time they were applied and saw no significant difference in directions and magnitudes that could give any clues to understand that weird behavior.

Link to comment
Share on other sites

9 minutes ago, Ser said:

I'll try that of course, thanks for pointing me out the getGeeForceAtPosition. But doesn't your code do exactly the same job? I don't see anything that could solve the bouncing vessels mystery. I've logged and visualized the forces every time they were applied and saw no significant difference in directions and magnitudes that could give any clues to understand that weird behavior.

I have no idea what could be causing the bouncing. Maybe it's got something to do with some parts still falling while others have already settled on the surface. Does this happen with 1-part (non-EVA) vessels?

Link to comment
Share on other sites

4 minutes ago, MrHappyFace said:

It doesn't make much sense to use m/s2 when we're dealing with instantaneous impulses. Impulses last one frame, and frames are of variable length, although meters per frame squared might work.

Yeah, I was being a bit picky with that part, the 1000x was the main point of my post.

A bit more pickiness, "frames" (FixedUpdate) are actually a fixed length of 20ms (except in physics warp).  Impulse is the integration of the force with respect to time, which, assuming a constant force over the period of a frame, is simply the force multiplied by the time.  The units of this are Ns or kgm/s (as impulse is equivalent to momentum).  I'd need to read the Unity docs to be certain (well, as certain as I could be) of how the value passed to AddForce is treated for the different force types but I think I would correct what you wrote above to say:

On 5/23/2016 at 5:21 PM, MrHappyFace said:

Force - A regular force. Applying a force of 1kN for 1 second on a 1kg object speeds it up by 1m/s.

Acceleration - An acceleration. Applying an acceleration of 1m/s2 for 1 second speeds the object up by 1m/s regardless of mass.

Impulse - An impulse force. Applying an impulse of 1kNs for 1 frame on a 1kg object speeds it up by 1m/s.

VelocityChange - A change in velocity. Applying a velocity change of 1m/s for 1 frame speeds the object up by 1m/s regardless of mass.

17 minutes ago, Ser said:

I don't see anything that could solve the bouncing vessels mystery. I've logged and visualized the forces every time they were applied and saw no significant difference in directions and magnitudes that could give any clues to understand that weird behavior.

It does sound very strange.  Do your vessels have landing legs or wheels?  Given their somewhat unstable behaviour in 1.1.2 I would avoid using them in your tests to rule out any possibility of an odd interaction...

Link to comment
Share on other sites

13 minutes ago, MrHappyFace said:

I have no idea what could be causing the bouncing. Maybe it's got something to do with some parts still falling while others have already settled on the surface. Does this happen with 1-part (non-EVA) vessels?

I haven't try that.I'll try and see what happens.

 

7 minutes ago, Padishar said:

It does sound very strange.  Do your vessels have landing legs or wheels?  Given their somewhat unstable behaviour in 1.1.2 I would avoid using them in your tests to rule out any possibility of an odd interaction...

Exactly. They have wheels. But when they fall down they touch the ground by different parts. I'll try to exclude wheels.

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...