help with water (solved)

Apr 28, 2009 at 9:23 AM
Edited Apr 29, 2009 at 12:45 AM
Hi

Im busy trying to convert the Farseer FluidDragController to the Physics2D.NET physics engine, so I can use  the WaveController in the engine, but Im having a few problems.

Basically I just copied the Update procedure from the FluidDragController to the FluidLogic class in Physics2D.NET (which is the same thing), along with the other procedures Id need, and adapted it till it worked. The code is almost exactly the same.

The problem is that bodies seem to spin off  randomly out of the water.

I traced it to the _LinearDragForce variable in the FluidDragContainer class. If I dont apply this force its allright, everything does what its supposed to just without drag, but when its applied things get pulled or thrown out the water at funny angles.

I think maybe Im calculating the force at the wrong point (getvelocityatworldpoint), but the codes almost exactly the same and Ive gone through it a lot and cant find a fault.

heres a video of what it does: (removed)
Apr 28, 2009 at 9:26 AM
Edited Apr 28, 2009 at 9:28 AM
Heres some of the code

(this is the same as the Update procedure in Farseers FluidDragContainer)
protected internal override void RunLogic(TimeStep step)
        {
            for (int index = 0; index < items.Count; ++index)
            {
                Wrapper wrapper = items[index];
                Body body = wrapper.body;

                if (wrapper.affectable == null ||
                    body.IgnoresPhysicsLogics ||
                    Scalar.IsPositiveInfinity(body.Mass.Mass))
                {
                    continue;
                }

                _totalArea = body.Shape.Area;

                //find vertexes in fluid
                _vertices.Clear();
                Vector2D V;
                Matrix2x3 Mat = body.Matrices.ToWorld;
                foreach (Vector2D corner in body.Shape.Vertexes)
                {
                    //Scalar distance = line1.GetDistance(corner);
                    V = Mat * corner;
                    if (Wave.Contains(ref V))
                    {
                        _vertices.Add(corner);
                    }
                }

                if (_vertices.Count < 3) continue;

                _area = _vertices.GetArea();
                if (_area < .000001) continue;

                _centroid = _vertices.GetCentroid(_area);

                //calculate bouyancy
                _buoyancyForce = -_gravity * _area * density;

                CalculateDrag(ref body);

                //
                Vector2D.Add(ref _buoyancyForce, ref _linearDragForce, out _totalForce);
                //_centroid = body.Matrices.ToBodyNormal * _centroid;
                body.ApplyForce(ref _totalForce   ,ref _centroid );

                body.ApplyTorque(_rotationalDragTorque);

            }
        }


private void CalculateDrag(ref Body geom)
        {
            //localCentroid = geom.body.GetLocalPosition(_centroid);
            geom.GetVelocityAtWorldPoint(ref _centroid, out _centroidVelocity);
            //_centroid = geom.State.Position.Linear - _centroid ;
            //PhysicsHelper.GetRelativeVelocity(ref geom.State.Velocity, ref _centroid, out _centroidVelocity);

            _axis.X = -_centroidVelocity.Y;
            _axis.Y = _centroidVelocity.X;
            //can't normalize a zero length vector
            if (_axis.X != 0 || _axis.Y != 0)
            {
                _axis = _axis.Normalized ;
            }

            _vertices.ProjectToAxis(ref _axis, out _min, out _max);

            _dragArea = Math.Abs(_max - _min);

            _partialMass = geom.Mass.Mass * (_area / _totalArea);

            _linearDragForce = -.5f * density * _dragArea * dragCoefficient  * _partialMass * _centroidVelocity;

            _rotationalDragTorque = -geom.State.Velocity.Angular * dragCoefficient * _partialMass;
        }


I think the problems in this last procedure.

If anyone feels up to it Il send them my whole code. Maybe someone will have an idea where the problem is from looking at this though. If you want to see anything else just ask, Im desperate!

:) thanks
Apr 29, 2009 at 12:42 AM
Never mind everybody its solved.

Heres the solution for anyone interested:
(by Jono Porter)

OK the issue seems to be with keeping your reference frames strait. It
seems that you successfully transform the vertexes to the world
reference frame for collision detection, but when you calculate the
forces its on untransformed vertexes.

                    if (Wave.Contains(ref V))
                    {
                        _vertices.Add(corner);
                    }

This messes up with the force calculations by making your centroid
velocity explode because it is calculating that assuming world
coordinates; among other things.
I would change this to

                    if (Wave.Contains(ref V))
                    {
                        _vertices.Add(V);
                    }

And add the line

_centroid = _centroid - geom.State.Position.Linear

right before you call ApplyForce

See how that works for you.


It worked.
May 22, 2009 at 3:54 PM

@genbox / matt / anyone

Can anyone confirm this change that robert has suggested. I'm getting this exact behaviour (objects shooting out the water), but I assumed that my mass and density values were to blame?

 

 

Coordinator
May 22, 2009 at 5:53 PM

I've seen this behavior too when converting the silverlight water demo to XNA. I thought it was my settings, so I changed them and got a resonable behavior - the problem might be as described by Jono Porter, I'll take a look at it.

Coordinator
May 22, 2009 at 6:07 PM

@robertdodd: Could you direct me to where the problem lies? The code you provided must be from Physics2D.net and not from Farseer Physics. I would very much appreciate If you could make the appropriate changes to the source control version of the FluidDragController, and send it to me. (or upload to patch section)

 

Developer
May 23, 2009 at 1:53 AM

Water is very tricky. You'll need to get your settings just right to get the expected behaviour.

May 23, 2009 at 4:33 AM

Hi

Make sure you're not confusing my "objects shooting out of the water" with objects just "bobbing wildly". What was happeinging to me was that objects would fly off in some random direction at a crazy speed and spinning wildly. "bobbing wildly" is just crazy bobbing :)

I only had this problem when I converted Farseer code to Physics2D.NET, so I thought it was just my conversions and not the actual code itself.

The objects bobbing wildly is still a problem I suppose. The Physics2D.NET Fluid controller doesnt have this problem, it works very smoothly, but it works by afffecting objects below a line, so no waves or custom shapes. Because of using a line to determine when to affect objects, it had a whole different code for calculating the centroid and force etc, which I couldnt manage to modify to use a custom shape which is why I used the Farseer code. Maybe someone who understands the code could take a look at it though.

Another thing I noticed which might affect it(not that I understand much of it anyway, this was just a thought I never tested) is that the Physics2D.NET fluid affected the corners of the object that were underwater, while the Farseer code affects every vertex of the object. I never tested this though, but I thought it might produce different results.

If you're really interested in this, I suggest you contact Jono Porter from Physics2D.Net, as he wrote the Physics2D.NET code and solved my above problem. He might be able to help.

 

Cheers

May 26, 2009 at 2:26 PM

I got the latest snapshot from SVN and used the values from the XNA Water sample (previously trying with the Silverlight values). Things are working MUCH better now! 

 

Coordinator
May 26, 2009 at 3:58 PM

Indeed. You need to use the values from the XNA sample if you run at the same update speed as the XNA samples. Otherwise the simulation will bounce violently and can crash with an exception (because velocity is NaN).