Sprite Rotation

Started by
9 comments, last by Haytil 12 years, 9 months ago
Well hello again, I get the feeling that this is a simple question, but still not matter hwat I did I couldn't get it to work... anyways here's the code: ... D3DXMatrixTransformation2D(&SpriteM, NULL, 0.0f, NULL, &D3DXVECTOR2(SpriteFocus.x, SpriteFocus.y), Index, NULL); ... D3DSprite->Begin(NULL); D3DSprite->SetTransform(&SpriteM); D3DSprite->Draw(ClearBallT, NULL, &SpriteFocus, &SpritePos, D3DCOLOR_XRGB(SpriteColR, SpriteColG, SpriteColB)); D3DSprite->End(); ... This should make the sprite rotate around its axis, but it doesn't so I'm clearly at fault here. Instead I get the sprite rotating around something at the top left. If you have any ideas on what may be the problem please post. If you need more code... or explanations, please do not hesitate to ask. Thanks, Fissure.
Advertisement
Are you sure you rotation center is at the actual center of the texture? One common mistake is that people will load images D3DXCreateTextureFromFile, which automatically resizes images to power-of-2 dimensions. Then when they set their rotations they think they're dealing with a 40x50 texture, but they're actually dealing with a 64x64 texture. You can fix this by using D3DXCreateTextureFromFileEx and specifying D3DX_DEFAULT_NONPOW2 as the width and height parameters.

Yeah well I already knew about the whole 'to the power of 2' thing, haha, but what I didn't know is that D3DXCreateTextureFromFileEx allowed you to use a custom size... could you please tell me if there are any draw backs to doing that? I mean there must be! Otherwise they wouldn't be doing... 'to the power of 2'.

Well my texture has a size of 128x128, so 64x64 is the centre right :). Well if that's true... then the centre part ain't got nothing to do with it, most likely. I guess I should go check out more tutorials but they are getting harder to find, if you guys can help out please do so :).

I can't believe so many of you old guys are still here, LOL, I still remember you lot. Must be dedicated, good for you ;).

Thanks,
Fissure.
don't use the rotate in D3DSprite->Draw(), it's bugged. Instead, use a rotate at origin(the top left corner of screen) followed by a translation to your sprite location.

here is a sample of how I'm doing a rotation with Sprite (in C#):
Matrix finalMatrix;finalMatrix = Matrix.Multiply(Matrix.RotationZ(angle), Matrix.Translation(pos));then when drawing the sprite,public void DrawSprite(Sprite sp){ if (isRotate) {      sp.Transform = finalMatrix;      sp.Draw(texture, ctr, Vector3.Empty, unchecked((int)spcolor));                      isRotate = false; } else {      sp.Draw(texture, ctr, pos, unchecked((int)spcolor)); }}

I'm sorry geekman1009, I don't understand what you mean :(. What do you mean when you say don't use rotate in Sprite->Draw?

If possible could someone please provide me with a detailed tutorial? Of fourse there are tutorials online... but most of them do not get in to enough detail for me to understand.

EDIT - I wouldn't mind being recommended a book either :).

Thank you and sorry for the late reply.
Sorry for the bump guys, but I really need to know hopw to work with that function. Could someone please give me a recommendation to ANY book that focuses on this function or 2D in general.

Thank you.
Quote:Original post by GameFissure
I'm sorry geekman1009, I don't understand what you mean :(. What do you mean when you say don't use rotate in Sprite->Draw?

If possible could someone please provide me with a detailed tutorial? Of fourse there are tutorials online... but most of them do not get in to enough detail for me to understand.

EDIT - I wouldn't mind being recommended a book either :).

Thank you and sorry for the late reply.


What I mean is, don't use

D3DXMatrixTransformation2D(&SpriteM, NULL, 0.0f, NULL, &D3DXVECTOR2(SpriteFocus.x, SpriteFocus.y), Index, NULL);

(I didn't read your original post carefully, and since I'm using XNA Game Studio which, the SpriteBatch have incorporated the transformations into the Draw() method, hence the confusion)

since this function always rotate you sprite around the origin (top left of the screen), regardless of how you set your Sprite Center and Position. The bug I mentioned earlier is, D3D will Translate your sprite to its Position BEFORE the Rotation, resulting in what you have been seeing in your current situation - the sprite is rotating around the screen origin. To avoid this bug, multiply 2 transformation matrices together to achieve the effect of rotating a sprite around it's center at given position, in one matrix, you then apply this composition matrix to the sprite.

In other words, rotate the sprite first (regardless of its position, since D3D will rotate the sprite at the world origin or top left of the screen), then translate the rotated sprite to the desired location. This can be achieved by Multiplying a Rotation-around-Z-axis Matrix (the LEFT matrix) and Translation Matrix (the RIGHT matrix). Apply the resulting Matrix from the multiply above and you will get what you want.
Quote:Original post by geekman1009
What I mean is, don't use

D3DXMatrixTransformation2D(&SpriteM, NULL, 0.0f, NULL, &D3DXVECTOR2(SpriteFocus.x, SpriteFocus.y), Index, NULL);

(I didn't read your original post carefully, and since I'm using XNA Game Studio which, the SpriteBatch have incorporated the transformations into the Draw() method, hence the confusion)

since this function always rotate you sprite around the origin (top left of the screen), regardless of how you set your Sprite Center and Position. The bug I mentioned earlier is, D3D will Translate your sprite to its Position BEFORE the Rotation, resulting in what you have been seeing in your current situation - the sprite is rotating around the screen origin. To avoid this bug, multiply 2 transformation matrices together to achieve the effect of rotating a sprite around it's center at given position, in one matrix, you then apply this composition matrix to the sprite.

In other words, rotate the sprite first (regardless of its position, since D3D will rotate the sprite at the world origin or top left of the screen), then translate the rotated sprite to the desired location. This can be achieved by Multiplying a Rotation-around-Z-axis Matrix (the LEFT matrix) and Translation Matrix (the RIGHT matrix). Apply the resulting Matrix from the multiply above and you will get what you want.


No that functions is fine. It will apply scaling first, then rotation, then translation (as indicated in the documentation).

I think the problem might be that he's setting the position in ID3DXSprite::Draw...try setting your position as the pTranslation parameter of D3DXMatrixTransformation2D instead of the pPosition parameter of ID3DXSprite::Draw.

Sorry to bump an old thread - but I'm having the exact same issue, and I would like to understand why the following fix works:


No that functions is fine. It will apply scaling first, then rotation, then translation (as indicated in the documentation).

I think the problem might be that he's setting the position in ID3DXSprite::Draw...try setting your position as the pTranslation parameter of D3DXMatrixTransformation2D instead of the pPosition parameter of ID3DXSprite::Draw.



Like the above poster, I am using D3DXMatrixTransformation2D(...) to rotate my sprite, but I am only performing the translation with the ID3DXSprite::Draw() function. Both D3DXMatrixTransformation2D() and Draw() take translation parameters, but only D3DXMatrixTransformation2D() takes a rotation parameter. Since Draw(...) takes the matrix created by D3DXMatrixTransformation2D(...), I figure I can pass it that matrix for the rotation, and restrict rotation to the Draw() function.

That way, I only need to recalculate a new rotation matrix whenever my sprite rotates (instead of when it rotates OR translates), which should be good because I rotate rarely, but I translate every frame (either the sprite moves or the camera moves). If my sprite hasn't rotated last frame, I can use the previously stored matrix from the last time I called D3DXMatrixTransformation2D(), which was the last time it rotated.

Of course, doing that resulted in the error the OP had - it appeared as if the translation would occur before the rotation. Because rotation is supposed to happen around the origin, this means the sprite rotates around a fixed point and "swings" outward.

My question is - why is this? And can this be avoided somehow (so that I can go with my original plan to only calculate new matrices upon rotations)? My inference is that the Draw(...) function, which takes both a transform matrix and a translation vector, will apply the translation vector (if it's not NULL) before applying the transform matrix.

Is this true? If so, why bother accepting both transform matrices and translation vectors? I can't think of any practical scenarios where you would want both, given how they interfere with one another in such a non-intuitive way.

And what exactly is going on under the hood, when I pass both a transform matrix and a translation vector to Draw()? Is it calculating a translation transform matrix from my translation vector, multiplying that against the transform matrix I passed it, and then using that for the final sprite? Or is it managing some optimized shortcut (which would make it faster than manually calculating each transform matrix - INCLUDING the translation - myself using D3DXMatrixTransformation2D() during every frame?)

And again, is there any way to achieve the effect I desired? The only way that comes to mind is to calculate both rotation and translation matrices independently, and then multiply them when either one changes. That way I'm only calculating rotation matrices when it rotates (which is rare), and translation matrices when it translates (which is every frame) and multiplying them when either changes (which is every frame) - but again, if that's all going on under the hood via D3DXMatrixTransformation2D() and Draw() anyway, I suppose I might as well, right? The only cost is extra storage for the independent rotation and translation matrices.
Draw is not bugged.

I have used many times, with Rotations, Translation and Scaling and it works well.

You have to pay attention to sequence of trasformations... See Mout formula at http://msdn.microsoft.com/en-us/library/bb205366(v=vs.85).aspx

How you can see Traslation is last trasformation ( Mt ).

Mout = (Msc)-1* (Msr)-1* Ms * Msr * Msc * (Mrc)-1* Mr * Mrc * Mt


Remember that Scaling is before Rotation that is before Translation

Regards,
Max.

This topic is closed to new replies.

Advertisement