views:

45

answers:

1

For a simple 2d game I'm making I'm trying to rotate sprites around the z axis using matrices. I'm clearly doing something wrong as when I attempt to rotate my sprite it looks like it's being rotated around the screen origin (bottom, left) and not the sprite origin. I'm confused as my quad is at the origin already so I didn't think I need to translate -> rotate and translate back. Here's a code snippet and a small video or the erroneous transformation

void MatrixMultiply(
MATRIX      &mOut,
const MATRIX    &mA,
const MATRIX    &mB);
/*!***************************************************************************
@Function           TransTransformArray
@Output         pTransformedVertex  Destination for transformed vectors
@Input              pV                  Input vector    array
@Input              nNumberOfVertices   Number of vectors to transform
@Input              pMatrix             Matrix to transform the vectors of input vector (e.g. use 1 for position, 0 for normal)
@Description        Transform all vertices in pVertex by pMatrix and store them in
                pTransformedVertex
                - pTransformedVertex is the pointer that will receive transformed vertices.
                - pVertex is the pointer to untransformed object vertices.
                - nNumberOfVertices is the number of vertices of the object.
                - pMatrix is the matrix used to transform the object.
*****************************************************************************/
void TransTransformArray(
VECTOR3     * const pTransformedVertex,
const VECTOR3   * const pV,
const int     nNumberOfVertices,
const MATRIX    * const pMatrix);


RenderQuad CreateRenderQuad(
    const Texture2D & texture,
    float x,
    float y,
    float scaleX, 
    float scaleY,
    float rotateRadians,
    int   zIndex,
    const Color & color,
    const Quad2 & textureCoord,
    const char * name
) {
    MATRIX mT;
    MATRIX mS;
    MATRIX concat;  
    MATRIX mR;

    MatrixTranslation(mT, x, y, 0.0f);
    MatrixRotationZ(mR, rotateRadians);
    MatrixScaling(mS, scaleX, scaleY, 1.0f);

    VECTOR3 quad[] = {
        {-0.5f, 0.5f, 0.f}, //tl
        {0.5f, 0.5f, 0.f}, //tr
        {-0.5, -0.5f, 0.0f}, //bl
        {0.5f, -0.5f, 0.0f}, //br
    };

    MatrixMultiply(concat, mR, mT);
    MatrixMultiply(concat, concat, mS);
    // apply to all the points in the quad
    TransTransformArray(quad, quad, 4, &concat);

== Update:

here's the structs and render code:

I'm using the matrix class from the oolongengine code.google.com/p/oolongengine/source/browse/trunk/Oolong%20Engine2/Math/Matrix.cpp

I transform all the quads then later render them using OpenGL. Here are my data structs and render code:

typedef struct _RenderData {
    VECTOR3        vertex;
    RenderColor3D      color;
    RenderTextureCoord textureCoord;
    float              zIndex;
    GLuint             textureId;
} RenderData;

typedef struct _RenderQuad {
    //! top left
    RenderData  tl;
    //! top right
    RenderData  tr;
    //! bottom left
    RenderData  bl;        
    //! bottom right
    RenderData  br;

    float zIndex;

    Texture2D * texture; // render quad draws a source rect from here

    ESpriteBlendMode blendMode;

} RenderQuad ;

/// Draw
class QuadBatch {
   GLushort *              m_indices;
   const Texture2D *       m_texture;
   GLuint                   m_vbos[2];
   RenderData *            m_vertices; 
};

QuadBatch::Draw () {
    int offset = (int)&m_vertices[startIndex];

            // vertex
            int diff = offsetof( RenderData, vertex);
            glVertexPointer(3, GL_FLOAT, kRenderDataSize, (void*) (offset + diff) );

            // color
            diff = offsetof( RenderData, color);
            glColorPointer(4, GL_FLOAT, kRenderDataSize, (void*)(offset + diff));

            // tex coords
            diff = offsetof( RenderData, textureCoord);
            glTexCoordPointer(2, GL_FLOAT, kRenderDataSize, (void*)(offset + diff));

            // each quad has 6 indices

            glDrawElements(GL_TRIANGLES, vertexCount * elementMultiplier, GL_UNSIGNED_SHORT, m_indices);
+1  A: 

'Rotation', by definition, is around the origin (0,0,0). If you want a different axis of rotation, you have to apply a Translation component. Say you want to apply a rotation R around an axis a. The transformation to apply to an arbitrary vector x is:

x --> a + R(x - a) = Rx + (a - Ra)

(This might take some staring to digest). So, after applying your rotation - which, as you observed, rotates around the origin - you have to add the constant vector (a - Ra).

[Edit:] This answer is language and platform agnostic - the math is the same wherever you look. Specific libraries contain different structures and API to apply transformations. Both DirectX and OpenGL, for example, maintain 4x4 matrix transforms, to unify rotations and translations into a single matrix multiplication (via an apparatus called homogeneous coordinates).

Ofek Shilon