How to combine polygon and circle local/world transformation?

Started by
3 comments, last by Finalspace 8 years, 5 months ago

I have a rigid body, it have a world position and rotation.

The rigid body may have multiple shapes, each shape may have a local rotation and offset.

Maybe one shape is a polygon and another is a circle - so its a combined thing.

Each of that has its local offset to some extend - so that its not on the body center anymore.

When i for example want to draw a polygon in world space with all the transformation applied i do it like this:


Mat2f localRotation(0.05f);
Vec2f localOffset(100, 0);

Mat2f worldRotation(0.15f);
Vec2f worldPosition(0, 0);

for (int i = 0; i < numVerts; i++) {
  v2 p0 = (V2(localVertices[i]) * localRotation + localOffset) * worldRotation + worldPosition;
  v2 p1 = (V2(localVertices[i < numVerts - 1 ? i + 1 : 0]) * localRotation + localOffset) * worldRotation + worldPosition;
  drawLine(p0, p1);
}

But what about circle shapes? They will change the position when the local offset is not zero.


//Mat2f localRotation(0f); // Circles dont have a local rotation at all
Vec2f localOffset(-100, 0);

Mat2f worldRotation(0.15f);
Vec2f worldPosition(0, 0);

Vec2f pos = V2(localOffset) * worldRotation + worldPosition;

drawCircle(pos, radius);

This seems to be a totally different way than the implementation above.

Is there a nice way to change the polygon drawing to use this way - so that it uses a rotated position and of course, includes the vertex rotation as well ?

It must be really easy, but right now i dont see it at all...

Advertisement

Maybe one shape is a polygon and another is a circle - so its a combined thing.


But they're still individual shapes.


I'm not really sure what your question is, but you may want to structure your hierarchies like this:

A shape has its local transformation relative to the rigid body world transform that is attatched to it;
A rigid body stores its world center of mass and world rotation (world transform) and it can have 0...n shapes;

Then you loop through a rigid body shape list and render each shape as below:

ShapeWorldTransform = BodyWorldTransform * ShapeLocalTransform;
RenderShapeAt(ShapeWorldTransform);

And hopefully answering the question: You usually don't need to transform each local vertex on the CPU. I suggest to read the graphics API documentation you're using and check how to send local vertices and matrices to the GPU for it automatically transform the local vertices into world-space after you make a draw call.

To ensure I never got confused I decided this the pipeline of transformations is:

model -> local -> world

Bodies are stored in world space. Shapes are stored in model space, and fixtures (or colliders) are stored in local space. For simple shapes like circles I just store them directly in local space. It only makes sense to store models that are complicated in model space, that way the data does not need to be duplicated each time a shape referencing a single model appears.

Edit: IIRC Box2D stores everything in local space. When you pass Box2D vertices for a shape, even AABBs, the vertices are copied into local space. This makes for a lot of wasted memory in a lot of tile-style games where AABBs are all over everywhere.

What i mean with local space is the space relative to the body position / rotation.

The center of mass is a separeted vector which is defined relative to the bodies position - which is in most cases equals zero and it will be only used in contact preparation (calculating rA and rB).

A shape has its local transformation relative to the rigid body world transform that is attatched to it;

A rigid body stores its world center of mass and world rotation (world transform) and it can have 0...n shapes;

Then you loop through a rigid body shape list and render each shape as above:

ShapeWorldTransform = BodyWorldTransform * ShapeLocalTransform;

RenderShapeAt(ShapeWorldTransform);

And for the (not-so-related with math/physics) question: You usually don't need to transform each local vertex on the CPU. I suggest to read the graphics API documentation you're using and check how to send local vertices and matrices to the GPU for it automatically transform the local vertices into world-space after you make a draw call.

My structure is already defined like this, but i dont use any graphics API at all - its just plain pixels and i do the transform myself.

But it seems combining the translation and rotation into a 3x3 matrix should be better anyway... so i can really just do "worldTransform * localTransform".

It was so simple...


		Mat2f worldRot = new Mat2f().setFromAngle(body.rotation);
		Vec2f worldPos = body.pos;
		
		Mat2f localRot = new Mat2f().setFromAngle(shape.localRotation);
		Vec2f localPos = shape.localPos;
		
		Mat2f finalRotation = new Mat2f(worldRot).mult(localRot);
		Vec2f finalPos = new Vec2f(localPos).mult(worldRot).add(worldPos);
		
		VertexBasedShape vbs = (VertexBasedShape) shape;
		int numVerts = vbs.getVertexCount();
		Vec2f[] localVertices = vbs.getLocalVertices();
		for (int i = 0; i < numVerts; i++) {
			Vec2f p0 = new Vec2f(localVertices[i]).mult(finalRotation).add(finalPos);
			Vec2f p1 = new Vec2f(localVertices[i < numVerts - 1 ? i + 1 : 0]).mult(finalRotation).add(finalPos);
			drawLine(p0.x, p0.y, p1.x, p1.y, color);
		}

Problem solved.

This topic is closed to new replies.

Advertisement