Counteracting Gravity? Math help

I’m writing a manipulator for clicking and dragging ragdolls, and rigidbodies, and i’m trying to make the grabbed rigidbody hover at a certain height above the spot of ground where my cursor is. (about half a metre) by pushing it constantly towards the specified point

While this works if the target is light enough, when i try to drag it horizontally, the target sinks downwards as it moves horizontally in a sort of inverse parabola, and doesn’t climb back up until i stop horizontal movement.

I can minimise this problem by increasing the force i move it with, but that causes other problems.

What i’d like to do instead, is apply a constant secondary force that pushes it upwards. The math i’m trying to use for this is

Physics.Gravity * targetrigidbody.mass * Time.DeltaTime

This force is applied repeatedly every frame (is there a better way ? should i specify a forcemode?)

It’s worth noting that i’m NOT applying these forces directly to the rigidbody, but instead to a manipulator object which is linked to it with a fixedJoint. as far as i’m aware that shouldn’t make a difference, but maybe i’m wrong

as a far as i’m aware this should make the object float freely and act as if it’s not obeying gravity, which should result in completely horizontal motion when i drag it around. But it doesn’t. And that’s just on single bodied objects.

I also need to figure out how to apply this method to ragdolls, which are obviously made of several parts.

I am well aware of the UseGravity flag on rigidbodies, however i’m opting not to use that if possible for two reasons:

  1. Ragdolls. Gravity is essential for making them flop around realistically
  2. Limiting. I’m putting an upper limit on this lifting force, so that it still won’t work on exceptionally heavy objects

I’m trying to implement this feature as a way to make the player feel more incontrol of dragging and manipulating objects. Without this force it’s kind of lame

Here’s me attempting to drag a multipart ragdoll around. It’s supposed to float horizontally though the air, not drag along the floor.

And here’s a demonstration on just a plain, single-rigidbody ball. The lifting force code is active here, but it doesn’t seem to do anything

As can be seen when i attempt to drag it horizontally, the ball still dips and moves in an arc. It also greatly overshoots the target, which is a result of me cranking up the basic force to try to eliminate this dipping

I could do with some advice on making this work better

Also, here’s my entire manipulator code: Legobet88 = Daftar Situs Slot Online Terpercaya & Slot Gacor Resmi Hari Ini di Login Bet88

The most relevant parts are the coroutine starting on line 139,
And these selected lines from within it:

            Vector3 tempLiftingForce = Physics.gravity * target.mass * Time.deltaTime;
            Vector3 LiftingForce = Vector3.ClampMagnitude(tempLiftingForce, maxLiftingStrength * Time.deltaTime);

Here i’m calculating the required lifting force, and clamping it to the maxLiftingStrength which is a value per second. I have a debug message after that indicating whether or not it was clamped, it is not being clamped indicating that the max strength i’ve set is sufficient for test cases.

Also here, where i’m adding the lifting force to the total force which will be applied this frame, and then applying it to the manipulator object

else if (movementMode == 1)
            {
               
                Vector3 force = targetPosition - transform.position;
                float dist = force.magnitude;
                strengthBonusMult = strengthBonusMaxMult * (Mathf.Min(dist, strengthBonusMaxDist) / strengthBonusMaxDist);
                force.Normalize();
                strength = (baseStrength * (1 + strengthBonusMult));
                force *= ( strength * Time.deltaTime);


                force += LiftingForce;
                body.AddForce(force);
                if (dist < stoppingZone)
                {
                    body.position = targetPosition;
                }
            }

Force calculation typically don’t use Time.deltaTime. The unit of force, Newtons is equivalent to kg m /s /s. So no need to use time.deltaTime to scale it.

if you want to counter act gravity just do something like this.

rigidBody.AddForce(-Physics.gravity * 2);

make sure you do that in the physics update, so FixedUpdate or a OnTrigger/CollsionStay

What? noooo, hold on a second @passerbycmc

Gravity works as a constant acceleration that is not dependant on mass. PhysX forces definitely do not, i’m screwing around with them right now, the effect is very noticeable if i increase the mass of an object, the same force produces less change in velocity, and doesn’t move it as far.

I don’t see any logical way that could work on an object whose mass is not 1, unless the ForceMode were set to Acceleration

ya sorry the force mode in my test was Acceleration, but simply adding the inverse of gravity, with ForceMode.Acceleration in the physics update will hold the object in place and nullify the effects of gravity on it.

Well that would certainly work, but it also doesn’t allow me to limit the force applied, and would work equally on any object. That’s not what i’m looking for D:

A way to calculate a force i can clamp is preferable. how close was i originally?

I must say, as someone who can contribute absolutely nothing to this conversation (as I’ve rarely worked directly with forces and physics), that your threads are always extremely fascinating Nanako. I have this feeling that we should bundle them all up in one place and submit them to the devs as an example of aspects of Unity where they could make things a bit easier to control.

2 Likes

Random thought, ever consider using a spring joint? A spring joint basically applies force based on the distance from a target point. Further you are away, the more force is applied. This may well reduce the amount of math you have to do.

I have, and i tried it. I didn’t find it to offer a sufficient degree of control, and the force seems to scale up almost-infinitely. It also suffered the same problems mentioned here

What i have now is basically my own remake of the spring joint, with more control i guess. Though i’m still polishing iot, clearly there are issues

Hah, thank you! I do tend to delve very deep into things that i’m working on, and often find shortcomings.
You could subscribe to me, apparently someone else already did. A fan club would be fun :stuck_out_tongue:

I assume setting a height and turning off gravity while selected isn’t a viable option?

But surely you can clamp that statement based off mass of the object? For instance, the higher the mass of the object, the less constant upwards force you apply. Also going through your code I’d recommend getting these parts out of the while() statement and into a FixedUpdate. It makes things simpler and more efficient without having to worry about framerate.

As mentioned, i’m applying a limited strength to this functionality, turning off gravity is an indiscriminate, unlimited thing

How can i clamp an acceleration? Any value less than gravity will be worthless. It’s just coming at the problem from the wrong end of the equation. A maximum force magnitude seems better. That’s what i was originally trying to do, but it didn’t work for reasons unknown

The manipulator is an object that spends a lot of time not doing things, and only gets forced around when the player is attempting to manipulate an object. Which is a common gameplay feature, but not constant.

I used a coroutine because i can turn that on and off, whereas the Update/FixedUpdate monobehaviours can’t be disabled and will continue firing every frame whether i need them or not. That concept has always annoyed me, and i try to simply not use them if i can help it. This seemed like an appropriate situation

While it’s true that those functions can’t be disabled, the performance you save from using FixedUpdate rather than adding force values every frame is much greater than the performance you lose from having the FixedUpdate fire all the time. Plus all you really need to do is if (doThing) for the entirety of the FixedUpdate and basically it’s the same, the FixedUpdate call itself is nothing compared to the calculations in the script.

However if your game requires extremely accurate physics, then doing it every frame would probably be worth the performance cost.

Clamping acceleration? It’s not a matter of clamping acceleration, but clamping the value that goes into that acceleration. Hmmmm… So if the object moves down when moving from point A to B, have you considered that there is some downwards force when the object is moving? I see tempLiftingForce has already taken into account gravity, but it’s added only after you do some more calculations with strength and the Normalize() function. So if there was any downwards force before hand, liftingForce would be only be adding to it. Have you tried just setting the force.y = LiftingForce.y? That would make sure there is no downwards force since we are just setting the value to be LiftingForce. I don’t quite understand how you want to limit the force applied, but LiftingForce has the mass inside that calculation, so there wouldn’t be any limit there. It would always be counter acting gravity correctly. Limits would have to be applied manually. Or, if you want the mass to be a factor in LiftingForce, then just remove mass from that statement and just add an upwards force based off a static variable. Since force up doesn’t change but mass will change, that means you’ll be limited by the weight of the object. If you want smaller objects to be the same height, just lower the force when the mass is really small.

Could i perhaps set the coroutine’s yield time to Time.FixedDeltaTime in order to alleviate that? Extreme accuracy isn’t an issue, no.

Perhaps you’re right there.

The other calculations are for the main, mostly horizontal force that moves the object around. It is possible there’s a downward force, but in that case I WOULD want it to be applied.

There’s lots of confusing modes in there i added while testing. But what it basically does right now is raycasts through the cursor, hits something, and pushes the manipulator to a point a flat distance above the hit location, so the higher the object the mouse is over, the higehr up the target would be, thats ok.

I believe you missed something.

Vector3 tempLiftingForce = Physics.gravity * target.mass * Time.deltaTime;
            Vector3 LiftingForce = Vector3.ClampMagnitude(tempLiftingForce, maxLiftingStrength * Time.deltaTime);

The force limiting is done by Vector3.ClampMagnitude. It clamps the magnitude of the already calculated force, to a predetermined maxLiftingStrength value. I first precalculate the infinitely scaling force required to counteract gravity, and then clamp it like so. If it was too high before the clamping, then it should fail to properly lift the object. If it wasn’t too high, then it should suspend the object and perfectly counteract gravity.

F = MA, right? As far as i’m aware, this code should work.
I’m not really here for alternate suggestions, i created this thread to get help on why that exact code does not work, and how to fix it.

Images in the OP doesn’t work for me :frowning:

Anyway; I’ll ask some stupid questions;

On line 145 you do

if (tempLiftingForce.sqrMagnitude > LiftingForce.magnitude)

Should that be sqrMagnitudes on both sides?

It also seems your lifting force is pointing in the same direction as the gravity. Is that intentional?

force += LiftingForce; //where liftingforce having a negative y component

body.AddForce(force); //the result here would be downwards movement, unless the y component of force is greater than LiftingForce
1 Like

With regards to ragdoll, unless you simulate every body, it won’t work without a high enough Solver Iteration Count and fixedupdate rate. Because joints won’t resolve in the same frame, so it’ll all lag behind.

You will want to enable Preprocessing option on joints as well to deal with higher forces. Having a fixedjoint on the cursor location that connects to the grabbed limb’s rigidbody will solve the rest and it should drag around as expected with AddForce upward equal to gravity on the limbs of your choice.

And don’t forget physics materials. I do this stuff in my game right now, which has a lot of dragging around of ragdolls, I didn’t need any special maths, just the realisation that Physx joints are very conservative settings to begin with (obviously as they are quite expensive).

The joint you use to drag also cannot be part of the same hierarchy.

Here’s direct links to the two images, these might work for you:
http://i.imgur.com/oLEgsaG.gif
http://i.imgur.com/ftW9HmF.gif

Ooh, you’re right. That could be a part of the problem. I use that just for a debug line to tell me whether the clamping is being applied, but as i’ve written it, it’s unlikely to be meaningful. So maybe i’ve set the force limit too low and didn’t know it.

Yikes ! That would also explain things. My lifting force is pushing down, and not up >.<

Congratulations, you’ve seen two things that i, and everyone else seem to have missed. I nominate this for best post in the thread.

1 Like