Understanding PolygonCreationAssistance coordinates

Dec 27, 2009 at 12:25 PM

Hi all,

I'm trying to use the PolygonCreationAssistance class to automatically generate collision information for my sprites, but I've been having matching problems. I'll try and explain it as clearly as I can:

The symptoms:

Suppose I start with a sprite of size 128x128 which has a drawn square of size 60x60 centered in the middle of the image. In this case if I use PolygonCreationAssistance to generate Vertices for the sprite, and then use CreatePolygonBody() and CreatePolygonGeom(), the collision information matches the drawn sprite.

However, if I offset the square from the middle of the image to the top-left corner, for instance, the collision still happens as if the square was still in the image center, although it is now drawn in the top-left corner.

The problem:

As far as I've been able to ascertain, Vertices created by PolygonCreationAssistance have their coordinates relative to the center of each detected polygons, and not relative to the image center. For me, this seems to be a problem, since it makes it difficult to match sprite location with physics body.

Of course I agree that typically you want to center the sprite image around drawn pixels, but it's hard to get it exactly right when working with hand-drawn sprites, and even more difficult for multi-polygon sprites (in this case, how can you simulate each individual polygon correctly while drawing it?).

What strikes me as odd is that this problem seems to me such a fundamental one in using PolygonCreationAssistance and no one else seems to be reporting it. As such, it may be the case that I'm just misinterpreting the correct usage of PolygonCreationAssistance in some way, and that there's a correct method somehow to achieve the correct matching.

In any case, I will appreciate any assistance you can provide me.

Best regards, thanks in advance for all the help and have a nice holiday season,

Gonçalo

Dec 27, 2009 at 10:12 PM
Edited Dec 27, 2009 at 10:14 PM

Hi again,

I've managed to get around the issue, and gained further insight into where the problem was.

By looking into the samples I found out that the GetCentroid() method supposedly gives the image space center of the polygon, so if you use it to render the sprite, everything should match up just fine. Strange thing was that when I added the position from GetCentroid() as my sprite origin,, it didn't work at all.

By digging into my code I managed to find the reason. Apparently, if you call GetCentroid() just after Vertices.CreatePolygon(), the center is given in image space coordinates, which usually is what you want.

However, I found out that after calling GeomFactory.CreatePolygonGeom(), the vertices structure is somehow modified so that the coordinates are now relative to polygon center. Since I was creating my sprite after the call to this method, I was getting an "incorrect" centroid value.

Now this seems a bit inconsistent to me, especially since BodyFactory.CreatePolygonBody() does not touch the Vertices at all. In this way it also makes it more difficult to just reuse/cache the Vertices structure, as you're never not sure whether its been made dirty or not by some call to CreatePolygonGeom().

Is it absolutely necessary that GeomFactory.CreatePolygonGeom() is a destructive operation on the Vertices structure?

Anyway, now that I know the issue, at least I can get around it.

Thanks for the great work on Farseer and hope that these comments help improve it for the future, or help someone with the same issues.

Best regards,

Gonçalo

Coordinator
Dec 28, 2009 at 1:08 AM

I've always been bothered by the centroid offsetting, just never got around to fix it.

Once you create a polygon geometry, its vertices gets centered around the centroid of the geometry. This is to allow good rotations of geometries. There might be a inconsistency between the texture-to-vertices implementation and the geometry setup, it would be great if you filed a bug about this.

Dec 28, 2009 at 8:27 AM
Edited Dec 28, 2009 at 8:28 AM

I've been digging a bit on Farseer's source, and I really think that there is no need to change the input Vertices. From Farseer's source:

public Geom CreatePolygonGeom(Body body, Vertices vertices, Vector2 positionOffset, float rotationOffset, float collisionGridSize)
{
<!-- My Comments:
    (...)
    // Below is where the input vertices get changed
-->
    
    //Adjust the verts to be relative to the centroid.
    Vector2 centroid = vertices.GetCentroid();

    Vector2.Multiply(ref centroid, -1, out centroid);

    vertices.Translate(ref centroid);

    Geom geometry = new Geom(body, vertices, positionOffset, rotationOffset, collisionGridSize);
    return geometry;
}

public void SetVertices(Vertices vertices)
{
<!-- My Comments:
    // And then some more here.
    // But after that, new copies of Vertices are created.
-->
    vertices.ForceCounterClockWiseOrder();
    localVertices = new Vertices(vertices);
    worldVertices = new Vertices(vertices);

    AABB.Update(ref vertices);
}

As you can see, in the end of the process, new copies are created of the Vertices structure. If these copies could have been created before the modifications, the Vertices submitted to the GeomFactory would be untouched. I'll try to consider a bit more how this could be done cleanly to include in the report.

Thanks for your attention,

Gonçalo