Update geometry realtime

Nov 15, 2007 at 2:21 PM
Hey all,

Maybe you can help me with this problem i have here. Scenario is that i have a landscape and a ball rolling over that landscape. Now i want to create holes into that landscape, this working sort of....

The stuff that i have:
Ball = circle geometry
Landscape = geometry created through the geometryfactory use a list of verticles.

Now please take a look at this screenshot, it will describe what i mean:
http://www.soolstyle.com/images/render06.png

When i create my first hole underneath the ball, it work. When i create a hole further away and roll the ball over it, it wont fall in.
When i create my first hole underneath the ball it falls through, but then i create another one under there and strange things happen.... You can see this is the screenshot bottom right, the right verticle is colliding with something that isn't there.. :S

A choas..... (The lines are not aligned here with the landscape because of my camera)
http://www.soolstyle.com/images/render07.png

Here is the code im using:
(Constructor)
//use the body factory to create the physics body
landscapeBody = BodyFactory.Instance.CreateRectangleBody(Helpers.PhysicsHelper.PhysicsSimulator, landscapeTex.SpriteTexture.Width, landscapeTex.SpriteTexture.Height, 1);
landscapeBody.IsStatic = true;
landscapeBody.Position = new Vector2(Map.mapWidth / 2, Map.mapHeight - landscapeOrigin.Y);

// Set the beginning vert points
landscapeVerts = new Vertices();
landscapeVerts.Add(new Vector2(0, -96));
landscapeVerts.Add(new Vector2(-385, -96));
landscapeVerts.Add(new Vector2(-770, -96));
landscapeVerts.Add(new Vector2(385, -96));
landscapeVerts.Add(new Vector2(770, -96));
landscapeVerts.Add(new Vector2(0, 96));
landscapeVerts.Add(new Vector2(-385, 96));
landscapeVerts.Add(new Vector2(-770, 96));
landscapeVerts.Add(new Vector2(385, 96));
landscapeVerts.Add(new Vector2(770, 96));

landscapeGeometry = GeometryFactory.Instance.CreatePolygonGeometry(Helpers.PhysicsHelper.PhysicsSimulator, landscapeBody, landscapeVerts, 0);
landscapeGeometry.RestitutionCoefficient = 1f;
landscapeGeometry.FrictionCoefficient = .9f;
landscapeGeometry.CollisionCategories = FarseerGames.FarseerPhysics.Enums.CollisionCategories.Cat1;
landscapeGeometry.CollidesWith = FarseerGames.FarseerPhysics.Enums.CollisionCategories.All;
landscapeGeometry.Tag = "Landscape";

(Update)
// Code here to create the circle of verticles and adding it to the list of verticles....
....
Helpers.PhysicsHelper.PhysicsSimulator.Remove(landscapeGeometry);
landscapeGeometry = GeometryFactory.Instance.CreatePolygonGeometry(Helpers.PhysicsHelper.PhysicsSimulator, landscapeBody, landscapeVerts, 0);


I hope this all makes any sense and you can help me out here :)

Thanks in advance! :D
Coordinator
Nov 15, 2007 at 4:42 PM
I'm not sure I follow.

So you have a rectangle that represents your landscape. It's a set of vertices.

When you create a hole, you replace the orignal geom with a new geom that has a semi-circle cut out of it?

When you create another hole you replace the previous landscape with the new one??? I don't think I understand... Could you explain in more detail how you are "making" the holes?

-Jeff
Nov 15, 2007 at 6:03 PM
Edited Nov 15, 2007 at 6:05 PM
Hehe i thought so :P

Wel yeah my landscape body is a rectangle. The geometry of the landscape is a set of verticles wich is stored and kept.

When i make a hole:
1. i calculate verticles based on a radius (from your geometry class.... :)).
2. Then calculate the exact location of those verticles inside the geometry based on the body and the offset.
3. Then i add those verticles that are calculated to the existing list of verticles.
4. I remove the geometry from the list inside the physics engine and create a new Polygon Geometry. (i saw in the code it was auto added to the list of geometry)

Here is the code i use for it (bit messy because im just testing it). I think the problem lies when i remove the vectors floating in the air when i create more then one holes.
/// <summary>
/// Creates a circle of vectors inside the existing vertices list
/// </summary>
/// <param name="rectangleA">Representing the rectangle of the circle</param>
/// <param name="rectangleB">The rectangle of the landscape</param>
/// <param name="dataB">The Color data of the landscape (Array of Colors 1d)</param>
public void CircleIntersect(Rectangle rectangleA,
                            Rectangle rectangleB, Color[] dataB)
{
    // Find the bounds of the rectangle intersection
    int top = Math.Max(rectangleA.Top, rectangleB.Top);
    int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
    int left = Math.Max(rectangleA.Left, rectangleB.Left);
    int right = Math.Min(rectangleA.Right, rectangleB.Right);
 
    // Calculate the circle points
    Vertices vertices = new Vertices();
    float radius = rectangleA.Width / 2;
    int numberOfEdges = 10;
    float stepSize = Microsoft.Xna.Framework.MathHelper.TwoPi / (float)numberOfEdges;
    vertices.Add(new Vector2(radius, 0));
    for (int i = 1; i < numberOfEdges; i++)
    {
        vertices.Add(
            new Vector2(
                radius * (float)Math.Cos((double)stepSize * i),
                -radius * (float)Math.Sin((double)stepSize * i)
            )
        );
    }
 
    // Go check if the circle of vectors are within the color rectangle of the landscape
    foreach (Vector2 vert in vertices)
    {
        int a1 = ((int)vert.X + rectangleA.X);
        int a2 = ((int)vert.Y + rectangleA.Y);
 
        if (a2 >= rectangleB.Top && a1 >= rectangleB.Left)
        {
            int b = (a1 - rectangleB.Left) + (a2 - rectangleB.Top) * rectangleB.Width;
            // Get the color of pixels at this point
            Color colorA = dataB[b];
            // Check if the landscape color is not alpha
            if (colorA.A != 0)
            {
                // Then we add this vector to the list
                Vector2 vec = new Vector2(
                    (rectangleA.X - ((rectangleB.Width / 2) + rectangleB.X)) + vert.X,
                    (rectangleA.Y - ((rectangleB.Height / 2) + rectangleB.Y)) + vert.Y
                );
                landscapeVerts.Add(vec);
            }
        }
    }
    // Nasty code here.... Just checks if there are some vectors inside the list that are floating inside the air within the circles radius
    Vector2 circle = new Vector2(
        (rectangleA.X - ((rectangleB.Width / 2) + rectangleB.X)),
        (rectangleA.Y - ((rectangleB.Height / 2) + rectangleB.Y))
    );
    // Lower the radius a bit
    radius = radius - 5;
    for (int i = 0; i < landscapeVerts.Count; i++)
    {
        // check for intersection
        if ((circle.X + radius) >= landscapeVerts[i].X && (circle.X - radius) <= landscapeVerts[i].X &&
            (circle.Y + radius) >= landscapeVerts[i].Y && (circle.Y - radius) <= landscapeVerts[i].Y)
        {
            // Remove this vector
            landscapeVerts.RemoveAt(i);
 
            i--;
            if (i < 0 && landscapeVerts.Count > 0)
                i = 0;
            else if (i < 0 && landscapeVerts.Count == 0)
                break;
        }
    }
 
    Helpers.PhysicsHelper.PhysicsSimulator.Remove(landscapeGeometry);
    landscapeGeometry = GeometryFactory.Instance.CreatePolygonGeometry(Helpers.PhysicsHelper.PhysicsSimulator, landscapeBody, landscapeVerts, 0);
}
Nov 15, 2007 at 6:20 PM
Also i this possible what im trying to do with this physics engine? If not im going for a per pixel collision detection and only use the bodies from you nice physics engine :).

If this is possible i sometimes also have the following problem, that the ball just rolls over the rectangle created although there are holes beneath it. Let me show it to you with a picture:
http://www.soolstyle.com/images/render08.png
Coordinator
Nov 15, 2007 at 7:27 PM
"3. Then i add those verticles that are calculated to the existing list of verticles."

Do you get rid of the vertices that use to be where the hole is? It seems like you have some geometry still hanging around where it shouldn't be.

I'm not sure Farseer is the best way to go for what you are trying to do. By the looks of your game, per-pixel might be better. Could be wrong, though.
Nov 15, 2007 at 8:49 PM
Yeah i remove those verticles in the last loop of the code. I just made a test run where the top of the landscape is almost fully filled with vectors (a 10pixel space in between).
But then when i create my holes, the ball never goes in the hole and just rolls over it like in the last picture. Here is a new pic with a better overview:
http://www.soolstyle.com/images/render09.png

Ah wel atleast i tried it this way :).

I think i will just go and try per pixel that should be easier to implement, only downside is that i need to calc the forces myself then :P.
Coordinator
Nov 15, 2007 at 11:09 PM
are you displaying the geometry vertices with any kind of debug viewer. That should tell you what's going on.
Nov 16, 2007 at 6:04 AM
Yeah i am using the debug viewer you had written for the demo's. As you can see in the last picture, the white lines and the red dots are from that debug viewer.
Coordinator
Nov 20, 2007 at 4:22 PM
The red line around the landscape, is that the "edge" from the debug view?
If it's not, try to enable the edge view to see any abnormalities.
Nov 22, 2007 at 10:11 PM
I enabled the edge as you said and i see the geometry lines crossing the circles. http://www.soolstyle.com/images/render10.png

The lines are a bit strange.... :P


@crashlander: Is there also a way to manually tell the physicsengine to create a collision between two objects? I mean over ruling the collision of the engine, create your own collision detection and is then a collision occurs in your own detection, tell the collided objects a collision is between the objects.
Coordinator
Nov 23, 2007 at 1:40 AM
The closest thing is going to be ApplyImpulse. You will have to calculate the impulse required though. Check here for a paper on Collision Response.

Nov 23, 2007 at 10:29 PM
Thanks for the reply crash, i was looking for those documents :).

I read the 2d collision article and tried to figure out the math without the spinning. Can you maybe take a quick look at the math i did, maybe you will see at a glance what i did wrong here. When i apply this impulse my ball goes trough the landscape with an enormous speed, and when i negate the impulse it goes through it slowly (depending on the mass of the ball).

Where entity A = the ball, and b = the landscape (static)

/*
 * j = -(1 - e)V1ab * n
 *     ----------------
 *     n*n(1/Ma + 1/Mb)
 * 
 * e = 0 ... 1
 * n = vectordistance.Normal
 * 
 * Va2 = Va1 + (j/Ma)n
 * Va1 = Va2 + (j/Mb)n
 */
 
float e = .2f;
 
Vector2 Vab = Vector2.Subtract(
    ((PhysicsEntity)entityCollection[b]).EntityBody.GetVelocityAtPoint(new Vector2(0,0)),
    ((PhysicsEntity)entityCollection[a]).EntityBody.GetVelocityAtPoint(new Vector2(0,0))
);
 
float n = Vector2.Subtract(vecPointA, vecPointB).Length();
float n2 = Vector2.Subtract(vecPointA, vecPointB).LengthSquared();
 
Vector2 x = Vector2.Multiply(
    Vab, -(1 - e)
);
 
Vector2 y = Vector2.Multiply(x, n);
float z = n2 * ((1 / ((PhysicsEntity)entityCollection[a]).EntityBody.Mass) + (1 / ((PhysicsEntity)entityCollection[b]).EntityBody.Mass));
 
Vector2 j = Vector2.Divide(y, z);
 
// No matter is i use entity A or B here, both give the same results...
Vector2 Va2 = Vector2.Add(
    ((PhysicsEntity)entityCollection[a]).EntityBody.GetVelocityAtPoint(new Vector2(0, 0)),
    Vector2.Multiply(Vector2.Divide(j, ((PhysicsEntity)entityCollection[a]).EntityBody.Mass), n)
);
 
((PhysicsEntity)entityCollection[a]).EntityBody.ApplyImpulse(Vector2.Negate(Va2));
Dec 8, 2007 at 6:59 PM
Have you had any luck with this?

Im trying the similiar thing but the problem seems to be that once an object has made a collision with your landscape it keeps the geometry in memory.

I tried the following test:
1. created a landscape
2. have a ball that drops onto the landscape
Results: Works as expected (the ball lands on the landscape)

Then I tried the following test:
1. created a landscape
2. before the ball bounces onto the landscape i call the following:
physicsSimulator.Remove(landscapeGeometry);

Results: Ball falls as if there is no landscape.

Then my last test:
1. created a landscape
2. let the ball bounce once onto the landscape
3. then call the following:
physicsSimulator.Remove(landscapeGeometry);

Result:
the ball continues to bounce and move as if the landscape still exits.

Anybody have any ideas why it does this?
Dec 8, 2007 at 7:16 PM
I added the following to the Initialization:

BruteForceCollider brute = new BruteForceCollider(physicsSimulator);
physicsSimulator.SetBroadPhaseCollider(brute);

and after that my above tests worked.
Coordinator
Dec 9, 2007 at 9:40 PM
This should be fixed in the new 1.0.0.3 release.