Jump to content
IGNORED

Rotating a sprite by Shearing


Recommended Posts

I came into this topic because of a comment in another thread: Sprite rotation by three shears. "Shearing"? What is to shear? I don't know if there is a Spanish word for that.

 

The method is simply explained at Rotation by Shearing and it is based on matrices, but those could be represented by bitmaps.

 

Then I wanted to see how that works and programmed a simple Atari BASIC program to do the shears. As BASIC is slow, it was perfect to show how pixels move when building a rotated image.

 

I needed a sprite to rotate and I thought that the starship from Gyruss was the right one. Obviously, I copied the one from Parker Brother's official A8 release, but I added a cockpit to give more details and to better follow the pixels movement:

 

starship.png.75646e2983f821cafeee2574d4d90d37.png

 

This sprite is 15x8 pixels, so it could fit in a 16x16 area. But I immediately found that a bigger area is needed, because the diagonals require more than 16 pixels when rotated; at 45°, a diagonal requires SQRT(2) of a square sprite heigh. Then, the working area should be 1.44 ~ 1.5 of the sprite size: 24x24 pixels.

 

Graphics mode 5+16 (80x48) seemed to be the right one to get a big sprite and to follow the process. The result is shown in the following video (using 30° as the rotation), and it repeats the process up to 90° and then to 360° (it takes 10 minutes) and then starts again, forever...

 

 

The following animation shows the result of each iteration when 22.5° is used (to get 16 different orientations):

 

demo-22.5.gif.0493109d26b94994fdee51b5d75fee2f.gif

 

The screen has the following elements:

 

  • The top row has the original sprite at the right and the working sprite at the left. The working sprite is the base image for the rotation process.
  • The bottom row has the result of the three shears in sequence:
    • The left one is the first horizontal shear from the base image.
    • The middle one is the vertical shear from the left one.
    • The right one is the second horizontal shear from the middle image. This is the final new sprite rotated at a given degree.

 

Lessons of this experiment:

 

  • All the pixels are moved, none of them are removed or created. The blank area (margin or frame) surrounding the sprite is also shifted with wraparound in the corresponding row or column.
  • I expected a symmetric bitmap when rotated to 45° but I got something different. I guess it is because the image was not evenly centered: it uses only 15 of the 16 pixels. I'll try with a 16 pixels width image later.
  • In order to get continuous rotation, the angle argument must be a divisor of 90, and it works with negative degrees.
  • To get a rotated image to an angle out of the range of -90 and 90, first perform both an horizontal and vertical flip of the original sprite to get a new base image that is rotated by 180°.
  • At some angles, the wings break off the starship. I guess it is because the wings are too thin and I'm not using any interpolation or antialiazing method. Probably a "fat" sprite won't suffer from this issue.
  • When computing a new image, always use the base image with a different angle. Never use a previously rotated image as it might be using pixels left in the frame, and those might wrap around to the other side of the sprite.
  • If there is a hardware limit for the sprite size, be sure to make it small enough in order that every rotated image fit inside the sprite and don't loose pixels or get pixels from the other side.
  • Atari BASIC does not have trigonometric TAN function, so I used SIN/COS expression.
  • Atari BASIC does not have MOD function, so I used a couple of IF statements to keep coordinates between 0 and 23 (24 pixels per row or column) and wraparound in each new image.
  • In order to see what was going on, I added an extra PLOT inside the loops of the shear and copy routines as a cursor. In the shear routines it moves a bit weird because of the offsets and warparound.
  • At the required rotation, the program iterates to the next step by adding the same amount of degrees to the parameter. After it reaches 90°, it copies the resulting image to the base image area and repeats again from the initialy required angle.
  • Instead of loading a bitmap, I used a simple rutine with PLOT and DRAWTO to draw the starship for the initial sprite, with coordinates that are READed from DATA statements. This was just for fun!!!

 

A final comment:

 

I was surprised about this simple procedure to rotate a bitmap. It does not require a powerful CPU or complex routine to get the rotated sprite, just a simple table with precomputed trigonometric factors for the desired angles. Of course, if you have enough ROM/RAM, you can store every rotated bitmap of your sprite, just like in Gyruss, in order to fine tune each image and get a nice looking game.

 

Have fun with the attached code...

 

rotademo.atr

  • Like 20
  • Thanks 3
Link to comment
Share on other sites

  • 5 weeks later...

This looks great, but my one observation about the ship rotating above is that it seems slightly OFF-AXIS.  But if the box that it was in had one more column of blanks, so that it had an exact center, this would not happen...

Link to comment
Share on other sites

Very interesting video... and fun!

 

On 10/29/2024 at 8:30 AM, glurk said:

but my one observation about the ship rotating above is that it seems slightly OFF-AXIS.  But if the box that it was in had one more column of blanks, so that it had an exact center, this would not happen...

I tried using a spaceship with even number of pixels, without sucess on getting a symmetric image when rotated to 45°. I should have tried modifying some changes in the formulas and other combinations, but I didn't have enough time and then I forgot this...

 

Edited by vitoco
  • Like 1
Link to comment
Share on other sites

The thing is, while I've seen this three-shear trick be useful for computing rotation matrices, I've never seen it be useful for rotating images over just a plain 2D mapping. The benefits that you get from the simpler shear pass are outweighed from having to do three of them. The step math for direct 2D mapping is just adding fractional X and Y coordinates.

 

Modified version attached; the white pixels that occasionally show up on the border are due to wraparound issues with the float-to-int pixel coordinate conversion, too lazy to fix them. The problem is that by default BASIC rounds coordinates to integer, but rejects coordinates that are negative prior to rounding instead of after.

 

rotademo2.atr

  • Like 4
Link to comment
Share on other sites

I also found isues when rounding and/or truncating negative values in BASIC and included a fix in the formulas, but I discarded that because it didn't seem to fix anything.

 

I'm not sure how that single shear works, but something is not right as some pixels are lost or changed. Look at this 45° rotation:

 

phaeron.png.1da4d4e3d7900ef08a984271d46f30a9.png

 

Just count the number of blue pixels: 5 instead of 6. Same with red ones: 13 instead of 15.

 

Might this be related to BASIC and/or FP package?

 

Anyway, it is interesting that this method allows any angle instead of just between the -90° to 90° range.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...