8
\$\begingroup\$

I'm trying to do resolution independent rendering of moving sprites in a 2D game. My plan is work in a fixed coordinate system in my world (for example 960x540) and use orthographic projection to scale that up or down to fit the viewport. I do letterboxing to handle different aspect ratios.

According to most tutorials, I am free to use whatever dimensions I like for the view frustum, but I found that in many cases that leads to the problem that I end up using subpixel values on the viewport. For example a vertex at (62,62) in a coordinate system of 960 x 540 ends up at (51.6666667,51.6666667) on a viewport with the dimensions 800 x 450.

I noticed two kinds of problems with that:

  • the texture sampling changes all the time for objects that are in motion depending on where the vertices are in relation to a pixels center
  • my objects get stretched horizontally or vertically by a pixel from time to time due to rounding

What is the best practice to avoid this (while maintaining resolution independence in terms of movement speeds and so on)? And where would be the best place to do address this? Before passing the vertices to the shaders or inside the vertex shader?

\$\endgroup\$
  • \$\begingroup\$ How are you doing the resizing and the translations to fit in the new viewport? Matrices? Manually scaling and moving object positions? \$\endgroup\$ – Emir Lima Aug 28 '14 at 11:50
  • \$\begingroup\$ @EmirLima I'm multiplying the coordinates by a combined model-view-projection-matrix inside my vertex shader. All scaling is done by the orthographic projection matrix. \$\endgroup\$ – Eric Aug 28 '14 at 13:24
  • \$\begingroup\$ you could round or floor the coords, (maybe in vert shader) \$\endgroup\$ – t123 Sep 3 '14 at 20:57
  • \$\begingroup\$ @tm1rbrt Thanks for your comment. I think I'd have to either always floor or ceil to avoid the 1 pixel more or less in width or height. I tried doing that inside the vertex shader, but the imprecision in calculations there makes that hard if not impossible. I ended up flooring what should have been perfect integers to the previous integer. \$\endgroup\$ – Eric Sep 4 '14 at 22:50
1
\$\begingroup\$

To get to your main question, whether or not to influence the vertices before or during the shader, using a shader is preferred. If you know how to write a routine that can take into account the viewport and coordinate system, using a shader is preferred as it allows many sprites to be adjusted in parallel. Also, it ensures the "cosmetic" coordinates stay separate from in-game coordinates in the CPU code so one doesn't influence the other.

You can do this either in the vertex OR pixel shader. In the pixel shader it is possible to shift texels to lock them to the pixels on the display.

In DirectX9 I needed to do this with HLSL in order get around the quirk that texel corners were located at 0.5, 0.5 relative to the pixel, making crisp textures look semi-blurry. Correcting this changes the physical location of the texels without moving the vertices.

In your case, the offset will vary from frame to frame, so pass the true coordinates of the sprite to the shader to calculate the decimal offset. Remember to CLAMP the texture sampling to avoid wrapping in the textures.

\$\endgroup\$
3
\$\begingroup\$

I think I would store two sets of coordinates.

  1. One used for drawing your objects DISPLAY POSITION and
  2. a second used for keeping a TRUE POSITION.

This way you can draw sprites with rounded coordinates to eliminate the distortion caused by fixed size of your view area.

But this also allows you to keep the exact location without influencing any of your game logic. because of the nature of sub-pixels I also think you will not even notice any discrepancies between the view and the game logic.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.