locked
Spritebatch.Draw() with an origin

    Question

  • When you use SpriteBatch.Draw() with an origin specified, this moves where the sprite is drawn on-screen depending on the value of the origin vector. Is this supposed to happen? from the helpit appears that the origin is only used in calculating a rotation, is this a bug (in which case I'll nip over to the bugs page) or is there something I'm missing here?
    Tuesday, September 12, 2006 7:56 PM

Answers

  • Yep, it's right the way it works. It draws the sprite relative to the origin, it uses it for scaling too. If it kept the origin at the top left, you would need to try and work out where it had moved to following rotation or scaling and then calculate offsets to keep it in the right place.

    If you know you will rotate or scale a sprite, always draw it with a specified origin of the sprite centre. That way it won't move when you rotate or scale it because the centre should remain constant whatever happens to the sprite.

    Tuesday, September 12, 2006 8:32 PM

All replies

  • Yep, it's right the way it works. It draws the sprite relative to the origin, it uses it for scaling too. If it kept the origin at the top left, you would need to try and work out where it had moved to following rotation or scaling and then calculate offsets to keep it in the right place.

    If you know you will rotate or scale a sprite, always draw it with a specified origin of the sprite centre. That way it won't move when you rotate or scale it because the centre should remain constant whatever happens to the sprite.

    Tuesday, September 12, 2006 8:32 PM
  • It's a bit counter-intuitive, For example if I wan to draw a rectangle in the upper left corner, with the origin set to the middle, i need to use 

    Draw(tex, new Rectangle(50,50,100,100),  .... , new Vector2 ( 50,50) );

    Now those co-ordinates don't make sense, It appears theres a bug in using the origin which subtracts it from the position when it should add it. It also doesn't seem to match any co-ordinate system. If I now want to move this box to the point 100,100 I need to use:

    Draw(tex, new Rectangle(150,150,100,100),  .... , new Vector2 ( 50,50) );

    The co-ordinate system of the rectangle doesn't represent any obvious co-ordinate system (e.g. the world or the object). The co-ordinate system of the Origin is relative to the box co-ordinate system, but also moves where it is in on the screen! A far more intuitive method for that would be

     

    Vector2 Origin = new Vector2(50,50);                            //Origin of the box, for a 100x100 box in the upper left corner I want it to be 50,50

    Rectangle box = new Rectangle ( -50,-50,100,100);    //Rectangle co-ords relative to box origin

    Draw(tex, box,...,Origin,...);

    I don't know if thats a bug or not but its a very unintuitive way of doing it. The co-ordinate system of the rectangle doesn't represent any obvious co-ordinate system (e.g. the world or the object). It also doesn't stop it need a translation, I can set the origin where I like, if I put it in the top left corner (0,0) then it requires a rotation and a translation (which it does). The only time you can get away without a translation would be if it used the geometic centre of the box, which would mean it didn't need the origin property :)

    With the above method you always need to covert the rectangle co-ords to local co-ords and supply an origin, so you could use:

    Vector2 Origin = new Vector2(50,50);                            //Centre of a 100x100 box

    Rectangle box = new Rectangle (0,0,100,100);    //Rectangle co-ords relative to world

    Draw(tex, box,...,Origin,...);

    This would get a bit confusing when you rotated/scaled the box, as you are supplying the original box co-ordinates before you rotated/scaled it.

    What do others think? I'll put it up on the suggestion box anyway.

    Wednesday, September 13, 2006 10:38 AM
  • The origin reference point is based on an unrotated version of the object so its position relative to the object remains constant. The coordinate system therefore is the one used by the unrotated version of that object.

    Your world coordinate would be based on the origin point too. If you had a car, you would keep track of the centre of the car, not the top left corner of the graphic. If you are moving objects round a game world, you don't care where the top left corner is. Your object positioning would be handled by the camera in your world.

    Try it with your Draw routine drawing to a vector2 position rather than a rectangle. I.e. Draw(tex,vector2,....,origin,...) That way, the size of the shape is irrelevant, you are just positioning it on the screen rather than within a predefined rectangle.

    I hope that makes sense, I am trying to answer during my dinner hour and am rushing a bit.

    Wednesday, September 13, 2006 12:32 PM
  • okay, I knew I was being stupid, now I see it, but it still seems wierd setting a rectangle at the wrong co-ordinates. However this is not the end of my problems as im now trying to rotate something. I know this is a bit basic but I've spent days trying to figure this out.

    Lets say I want to draw a texture of original size 100x100 in a 30x80 box with a +1.5 radian rotation about the centre of the visible box, the origin (where it is being rotated) is at 180x180 in screen co-ordinates, what do I pass to SpriteBatch.Draw() to do that. I know I'm asking for a "walkthrough" but I just cannot get my head around it. (for example it appears that using a different texture causes the location of where it is drawn to jump about, but thats a different story.)

    Thursday, September 14, 2006 10:11 PM
  • It's not being stupid, it's just another one of those things that seems overly complicated and could have been made more straight forward.

    Try this project... http://www.digital-essence.co.uk/misc/TextureExample.zip

    See if this makes things any clearer... I have tried to comment it as clearly as possible, I will try and help more if you need it, just shout.

    Friday, September 15, 2006 8:18 PM