Jump to content

Issue with physics and rotations


KenRubin
 Share

Recommended Posts

Hi!

I am new to Babylon.js.  Love it so far.  

I am trying to write a simple game.  I want the game character to "float" over the playing field.

Right now, I'm just trying to get a simple box to hover.  I'm doing it in a somewhat funny way because I want some wobbling to occur as part of the hover.

I am trying to use physics.  So I have gravity enabled in the scene and collisions enabled for the meshes.

Further, I want to apply impulses to the box to get it to hover.  I wrote some code to figure out which vertex is the "lowest" of all the verticies of the box.

I then apply an impulse to that vertex.  Because the vertex is extended from the centroid of the box, a torque is generated by the impulse.

I am having difficulty keeping the impulses in range.  Typically, without squelching the angular velocity, the box eventually starts rotating out of control.

So, I was looking into just manually leveling the rotation using addRotation.  First I get the Euler angles from the rotation quaternion.  Then I reverse a little bit back onto the box each frame.

Oddly, this seems to work very well for about 1 minute.  Then suddenly, it fails.  I fails slowly, which is even odder to me.  It seems like I have to reset some internal state or something....

Can someone point out my missteps?

Thanks.  

Wingnut was kind enough to build a playground example that works (but without the wobble):  http://playground.babylonjs.com/#1GWEVG#0 (see his post below).

I also have a running version on my website, at: http://165.225.132.154/graphics/BabylonHover/

When I fix the issue, that site will be updated.

 

This snippet shows the original issue.  Notice the difference between the working demo Wingnut wrote and this one which doesn't (specifically: the impulses are applied at the verticies here, whereas in the working example, the impulses are applied to the centroid):

        let dHoverHorizon = 50;
        let dImpulseForceDivisor = 10;
        let dRotationAdjustmentFactor = 20;
        meshBox.registerBeforeRender(() => {

            try {

                // Get all the verticies of the mesh, given as an array of 72 floats.
                // 3 floats for each vertex * 
                //  4 verticies per face *
                //  6 faces.
                //
                // Question #1: Why all 6 faces, which produces 3 times as many verticies as necessary?
                // Question #2: Is there a way to combine these to remove redundant geometry?
                let arrayMeshVertexFloats = meshBox.getVertexBuffer(BABYLON.VertexBuffer.PositionKind)._buffer._data;

                // Extract the 4 verticies for the 
                // face in which we are interested.
                // This happens to be the 6th face.
                let arrayMeshVerticies = [];
                for (let i = 3 * 4 * 5; i < arrayMeshVertexFloats.length; i += 3) {

                    arrayMeshVerticies.push(BABYLON.Vector3.FromArray(arrayMeshVertexFloats, 
                        i));
                }

                // Convert these 4 verticies to world coordinates.
                let arrayWorldVerticies = arrayMeshVerticies.map((vertex) => {

                    let vertexWorld = BABYLON.Vector3.TransformCoordinates(vertex, 
                        meshBox.getWorldMatrix());

                    // Attach original mesh-vertext to the world-vertex.
                    vertexWorld.localVertex = vertex;

                    // Return the new vertex.
                    return vertexWorld;
                });

                // Just for fun, only allow impulse on the lowest of all verticies.
                let v3Lowest = null;
                arrayWorldVerticies.forEach((v3) => {

                    if (!v3Lowest ||
                        v3Lowest.y > v3.y) {

                        v3Lowest = v3;
                    }
                });

                // Drop out now, if lowest vertex is above hover-horizon.
                if (v3Lowest.y > dHoverHorizon) {

                    return;
                }

                // Generate an impulse proportional to a square- 
                // root of the drop down from the hover-horizon.
                let dImpulseForce = Math.sqrt(dHoverHorizon - v3Lowest.y) / dImpulseForceDivisor;

                // Get the linear velocity.
                let v3LinearVelocity = meshBox.physicsImpostor.getLinearVelocity();

                // Only care about the y-axis.
                let dLinearVelocityAlongYAxis = v3LinearVelocity.y;

                // If the velocity is negative, then increase the impulse.
                // Eventually, this will need to take mass into consideration....
                if (dLinearVelocityAlongYAxis < 0) {

                    dImpulseForce *= (1 - dLinearVelocityAlongYAxis);
                }

                // This doesn't seem to work in a madening way:
                // Actually, it works for about 1 minute, then  
                // just slowly and seemingly-deliberately fails.
                let v3Rotation = meshBox.rotationQuaternion.toEulerAngles("XYZ");
                meshBox.addRotation(-v3Rotation.x / dRotationAdjustmentFactor, 
                    -v3Rotation.y / dRotationAdjustmentFactor, 
                    -v3Rotation.z / dRotationAdjustmentFactor);

                // Apply an "up" impulse to the physics 
                // imposter at the local location of the
                // lowest vertex found during this pass.
                meshBox.physicsImpostor.applyImpulse(new BABYLON.Vector3(0, dImpulseForce, 0),
                    v3Lowest.localVertex);
            } catch (e) {

                console.log("Error in meshBox.registerBeforeRender: " + e.message);
            }
        });
 

 

Link to comment
Share on other sites

Hi KenRubin, welcome.  Around here, we really like using the Babylon Playground, and being the nice guy that I am, I pasted your code into a playground, did a little adjusting, and hit save (and RUN a few times, too).   http://playground.babylonjs.com/#1GWEVG#0

I turned off all your .checkCollisions.  No big deal, but those are for the BJS built-in collision/intersects system, not for the 3rd party physics engines such as CannonJS and OimoJS.

That's quite a bit of code in your render loop (in registerBeforeRender).  It's WAY over my head, technically.  But look at line 156 and notice diff from line 155.  Contact point for impulse/thrust... is dead center of mesh (.getAbsolutePosition).  It gives you a nice steady hover, but, it sure is boring, huh?  :D  No "wobble", eh?  *nod*  I hear ya.  heh

Your renderLoop code sure looks fancy (and may be a bit overkill).  Tilt testing and distributed impulsing.  :)

Whelp, we have a playground now.  Smarter people than I... can play, now.  Welcome again.  Fun ahead.  Now that we can see your code in playground, feel free to clean-up previous post, if you wish.  ;) 

Link to comment
Share on other sites

Hi Wingnut,

Thanks for the help, kind words and welcome.

Did you see the odd behavior?  I'm just not sure what's going on.  I noticed something additional since posting the original: the unwanted rotation goes nuts for another minute, then it actually settles down and the whole simulation runs just fine.  

Do you know if there are some internal accumulators which can be nulled or reset?  This really looks like some sort of transient state issue in cannon.  I'm just not sure why the adjustment code works, fails to work and then works again.

I suppose if I follow your lead, I could continue to apply the impulse to the centroid, and manually apply a non-physics-based rotation to the mesh just for the effect.  

However, first I want to look into that Y-axis rotation you mentioned.  In addition to the "physics engine's rotationDamping feature", it should also produce gyroscopic torque, which should help stabilize the mesh.  On the other hand, I tried several different techniques to dampen the errant rotation and it always failed in the same, odd way....

Have a great evening,

Ken

Link to comment
Share on other sites

Hey, really interesting problem!

I haven't thought deeply on it, but here's my first blush advice:

Before anything else: does the wobble need to be at the physics level? If the wobble is basically to make the ship look the way you want it to, but it doesn't affect gameplay, then it would probably be better to just wobble the mesh without doing anything in the physics.

If that doesn't apply, then I think you're taking the right approach - for wobbling you usually want some kind of occasional perturbation, and some constant spring-like force countering the perturbation. It's not clear to me whether your counter force is working right though. For the simplest case you'd want to be applying a constant torque that's equal to the current rotation times some negative constant. I doubt this can be made to work with Euler angles though, it would probably need to be done with quaternions.

With that said, it usually helps to keep in mind what kind of physical thing you're modeling - i.e. what's perturbing the ship, and what's making it wobble? One answer could be, it has a gyro that keeps it level but it occasionally gets struck by little asteroids or whatever. If that's the idea, then I think what you're doing makes sense, but make sure your counter-force is doing what it's meant to, and you could try making the perturbations occasional, rather than constant.

Or a completely different approach could be, suppose the ship is a square box with rockets at all four corners, and each rocket independently applies an upwards force (torque) on the ship, and the ship wobbles because the engines do an imperfect job of deciding how much force to imply. For example if they decide how much force to apply based on whether their corner is below the ship's center, then there'd be a time lag in their response, which would create a wobble. 

Either way, for problems like this I think it usually helps to shy away from thinking "well I'll try applying a force here and an impulse there and see what happens", and instead focus on what kind of physical system you want to model, and whether your engine is really modeling that system or not.

Link to comment
Share on other sites

Thx Fenomas.  Good thinks.

Hey Ken... Yeah, I saw the out-of-control spinning, and yes, it IS really interesting that it self-corrects after some time.  This is likely due to a "carousel  effect"... what goes around, comes around.  heh.  (I should give-up comedy attempts... really.)  But yeah, the lowest vert position "cycles-around", first being a point of force that contributes to tilt-correcting, and then it cycles-around to be tilt-causing, and then returns to tilt-correcting again.  I think it has to do with slow rotation around all axes.  This slow rotation causes the impulsing forces (accumulating in-code?), or counter-leverage forces stored in the cube's momentum (not code, inertia)... to accumulate (and then disseminate).  Wow, huh?  Just speculation.

Anyway, as Wingnut returns from fantasy land... @fenomas recently reminded us of another possibility, too.  Using an invisible mesh as an anchor point (a stead/steadfast/steady-fastener).  I call them steads, whether invisible or not.  You could "hang" your meshBox from invisible "chains" of physics joints.  Fenomas said that impostors maintain a better natural "feel" when they are not directly rotated or positioned, but instead done with joints/links connected to invisible steads.  Then position/rotate the steads.  The chains/joints will transfer those energies to the meshBox... but without restricting it's physics motions like a "hard move" would.  Physics joints have springy-ness.

A four-corner joints/springs method... is similar-to the four thruster-rockets idea, except it's using pulls instead of pushes.  :)  BUT, jointed things tend not to fly away or go out of control.  i.e. Keep the chain connected to the dog, and there's less chance that his experimental rocket-pack will fly him to a different town.  :)

 Although broken right now, this PG demo has a green "stead" and some invisible chains (joints) used to "hang" the buttons.  When working, button clicks make those buttons wobble/swing.

Link to comment
Share on other sites

6 hours ago, fenomas said:

Before anything else: does the wobble need to be at the physics level? If the wobble is basically to make the ship look the way you want it to, but it doesn't affect gameplay, then it would probably be better to just wobble the mesh without doing anything in the physics.

If that doesn't apply, then I think you're taking the right approach - for wobbling you usually want some kind of occasional perturbation, and some constant spring-like force countering the perturbation. It's not clear to me whether your counter force is working right though. For the simplest case you'd want to be applying a constant torque that's equal to the current rotation times some negative constant. I doubt this can be made to work with Euler angles though, it would probably need to be done with quaternions.

fenomas,

I'd like to use physics--if for no reason other than the exercise itself.

The solution presented with the dampening Euler angles isn't really physics based though.  It was just my poor attempt at correcting the problem with the impulses.  It made some sort of sense to me that a rounding imbalance in the integration facility of the physics engine could escalate out of control.  What doesn't make sense to me is that the dampening would seem to work, then slowly and deliberately stop working (assigning agency to Cannon!) and then start to work again after going haywire for a minute.

I don't know enough about quaternions to use them directly--which is why I tried to convert into "intelligible" coordinates.  Do you have a reference for quaternions that could help me understand them functionally?  I like the idea of using them directly--even if a final solution would be purely physics-based.

I appreciate your time, take care,

Ken

Link to comment
Share on other sites

29 minutes ago, Wingnut said:

Thx Fenomas.  Good thinks.

Hey Ken... Yeah, I saw the out-of-control spinning, and yes, it IS really interesting that it self-corrects after some time.  This is likely due to a "carousel  effect"... what goes around, comes around.  heh.  (I should give-up comedy attempt... really.)  But yeah, the lowest vert position "cycles-around", first being a point of force that contributes to tilt-correcting, and then it cycles-around to be tilt-causing, and then returns to tilt-correcting again.  I think it has to do with slow rotation around all axes.  This slow rotation causes the impulsing forces (accumulating in-code?), or counter-leverage forces stored in the cube's momentum (not code, inertia)... to accumulate (and then disseminate).  Wow, huh?  Just speculation.

Anyway, as Wingnut returns from fantasy land... @fenomas recently reminded us of another possibility, too.  Using an invisible mesh as an anchor point (a stead/steadfast/steady-fastener).  I call them steads, whether invisible or not.  You could "hang" your meshBox from invisible "chains" of physics joints.  Fenomas said that impostors maintain a better natural "feel" when they are not directly rotated or positioned, but instead done with joints/links connected to invisible steads.  Then position/rotate the steads.  The chains/joints will transfer those energies to the meshBox... but without restricting it's physics motions like a "hard move" would.  Physics joints have springy-ness.

A four-corner joints/springs method... is similar-to the four thruster-rockets idea, except it's using pulls instead of pushes.  :)  BUT, jointed things tend not to fly away or go out of control.  i.e. Keep the chain connected to the dog, and there's less chance that his experimental rocket-pack will fly him to a different town.  :)

Wingnut,

Awesome idea.  A keel.  I love it!

Thanks.

Link to comment
Share on other sites

Hi All,

I've created another playground example: http://playground.babylonjs.com/#1GWEVG#1

This time, I'm hard-coding the rotation quaternion to "up", by constructing a quaternion from a rotation axis pointing along the Y-axis with 0 rotation:

                meshBox.rotationQuaternion = BABYLON.Quaternion.RotationAxis(new BABYLON.Vector3(0, 1, 0), 
                    0);
This works in the same way as with Euler angles.  That is, it works for a minute then fails to work.

I have noticed a slow drift along the X-axis in the negative direction.  Once the magnitude of the drift reaches 1/2 the width of the mesh (along the X-axis) the issue starts.

Does this make any sense?  After all, I am setting the rotation after applying the impulse, thus effectively cancelling the effect for which I'm aiming.

Is the imposter becoming disjoint with the mesh somehow?  Like the imposter is drifting relative to the mesh?

In any case, the oddest aspect is that no matter what I try, the simulation always fails in the same way.  Even if I hard-code the orientation!  What is going on?

Thanks,

Ken

Link to comment
Share on other sites

1 hour ago, jerome said:

beware when using addRotation() as it accumulates the rotations... if this is really

 

Thanks for replying,Jerome

please notice that my latest demo just sets the rotation quaternion directly.  In fact it is hard-coded to "up".  Still doesn't work.  

Thanks for your time,

ken 

Link to comment
Share on other sites

@KenRubin 

after a few failed attempts, i think i came up with something that works;
I replaced your wobbling with "hardcoded" x & z rotationQuaternions, (random value within an acceptable range).

note that it may still "drift" very slightly, because gravity & rotated x & z.

it was still acting stangely sometimes,
i'm not sure exactly what part was doing it,
but i believe it had something to do with the vertice data part of your code.


And since the wobbling is now taken care of, i removed all the code which went through vertice data and replaced the lowest y with the meshBox position y.

Here's the result; http://playground.babylonjs.com/#1GWEVG#5

running 10 minutes now without issues so i hope that was it.

Link to comment
Share on other sites

On 3/11/2017 at 5:57 AM, KenRubin said:

The solution presented with the dampening Euler angles isn't really physics based though.  It was just my poor attempt at correcting the problem with the impulses.  It made some sort of sense to me that a rounding imbalance in the integration facility of the physics engine could escalate out of control.  What doesn't make sense to me is that the dampening would seem to work, then slowly and deliberately stop working (assigning agency to Cannon!) and then start to work again after going haywire for a minute.

I don't know enough about quaternions to use them directly--which is why I tried to convert into "intelligible" coordinates.  Do you have a reference for quaternions that could help me understand them functionally?  I like the idea of using them directly--even if a final solution would be purely physics-based.

Hey,

I don't have a particular reference for quaternions, but the short version is that a rotation quaternion is an arbitrary unit vector paired with an amount of rotation around that vector. Basically they let you represent any arbitrary rotation as a single thing, rather than as three separate rotations that add up to the desired rotation. (The reason they're useful is that quaternion-based rotations combine and commute with each other the way you expect, which is not true with Euler angles).

To skip over all that though, here's a minimal example of the other idea I mentioned - it models the ship as having engines at all four corners, and applies an upwards force at each corner depending on whether it's higher or lower than some target height.

http://playground.babylonjs.com/#1FXV44

It also applies occasional random perturbations to make things wobble, and some damping to make sure things don't just oscillate forever.

Note of course that I'm not suggesting you need to model things this way. I just mean to demonstrate that it might be simpler to model a system that's inherently wobbly, rather than take a stable system and figure out how to perturb in just such a way that it appears to wobble.

Link to comment
Share on other sites

Actually, having now typed that all out, it occurs to me that it would be a lot simpler to just create several static, invisible anchors above the ship, and attach the ship's corners to those anchors by spring constraints. In physical terms the results of this would be mostly similar to the demo I linked, but using springs would make it a lot more straightforward to fine-tune the demo - to get more wobble by increasing the spring's stiffness, or less oscillation by increasing their damping, etc.

Link to comment
Share on other sites

There's some kind of echo in here.  :D

But still, thrusters from below... that is a much more dangerous challenge.  No room for physics mistakes, or the ship will crash into a mall.  But... there's always thrusters from below... WITH a joint from below, too.  A safety chain.  :)  Flyaway prevention.  Could hang a low heavy mass... an invisible pendulum (while still using chain joints from above?)

Wow, a guy could rattle-on, eh?  That most recent PG from Fenomas... that looks pretty good... esp closer-up and at various camera angles.  Nice floating.

Link to comment
Share on other sites

On 3/12/2017 at 5:32 AM, fenomas said:

Actually, having now typed that all out, it occurs to me that it would be a lot simpler to just create several static, invisible anchors above the ship, and attach the ship's corners to those anchors by spring constraints. In physical terms the results of this would be mostly similar to the demo I linked, but using springs would make it a lot more straightforward to fine-tune the demo - to get more wobble by increasing the spring's stiffness, or less oscillation by increasing their damping, etc.

That is a really cool idea with the springs.  I'm definitely going to play around more wth this stuff.

Take care.

Link to comment
Share on other sites

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.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...