0
\$\begingroup\$

I have a problem with with camera usage. I use camera and a virtual coordinate system because I want to scale my game screen to whatever the actual system resolution is.

If I set camera viewport size to 1200, 1600 for example and real application pixel resolution is 600x800 then this problem happens. I want to draw a 62x62 image to the horizontal center of screen. when I use draw function with x equals (1200/2 - 62 / 2) this problem happens.

600 - 31 = 569. Since i draw 62 units wide in virtual coordinate space, its actually 31 pixels in this example. The problem is 31 pixels is impossible to center on a even numbered x axis (600 actual pixels in this example). But camera tries to solve this very badly by default. It just cuts last vertical line from my image and it's rendered wrong!

Ofc in this example I can change app resolution to whatever I want but I want to focus on mobile and support many different screen resolutions and I just wanna think in virtual coordinate space and its units not the pixels resolution of the device. What's the point of using camera when I think about the resolution? How can I prevent such problems?

If I put image to elsewhere (some even number) in x axis for example x=0 the image scales perfectly well and no missing pixels. If I don't use camera at all it also scales perfectly (using only pixel based units).

If there is no solution I feel like camera and viewport classes are useless and everyone must use pixels.

Screenshot of the problem:

SS of the problem

Code for my game class:

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class MyGame extends ApplicationAdapter
{
   private SpriteBatch batch;
   private OrthographicCamera camera;
   private Texture myTexture;

   @Override
   public void create ()
   {
      batch = new SpriteBatch();
      batch.enableBlending();
      batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);

      camera = new OrthographicCamera(1200, 1600);
      camera.translate(camera.viewportWidth / 2, camera.viewportHeight / 2);

      myTexture = new Texture(Gdx.files.internal("circle.png"), true);
      myTexture.setFilter(TextureFilter.MipMapLinearLinear, TextureFilter.MipMapLinearLinear);
   }

   @Override
   public void render ()
   {
      Gdx.gl.glClearColor(1f, 1f, 1f, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

      camera.update();

      batch.setProjectionMatrix(camera.combined);
      batch.begin();
      batch.draw(myTexture, 569, 150, 62, 62);
      batch.end();
   }

   @Override
   public void dispose () {
      batch.dispose();
      myTexture.dispose();
   }
}

Code for its desktop launcher:

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;

public class DesktopLauncher {
   public static void main (String[] arg) {
      LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
      config.width = 600;
      config.height = 800;
      new LwjglApplication(new MyGame(), config);
   }
}

Image asset I've used in this example:

example asset

\$\endgroup\$
1
  • \$\begingroup\$ Resizing looks great when I don't use camera (ofc I can't perfectly center like that in this case) \$\endgroup\$ Commented Feb 1, 2018 at 20:11

1 Answer 1

0
\$\begingroup\$

The problem isn't the location of the image -- it's the scaling of the image. The width of the graphic is 62x62. The system needs to know how to represent it as 31x31 image.

The filter that determines how to scale it is a combination of anti-aliasing and the texture filter defined as TextureFilter.MipMapLinearLinear.

You can play around with different filters, but I will add that having a higher resolution texture (e.g. 128x128) will produce better results when filtered down to 31x31.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ No. When i put it elsewhere in x axis (an even number) it scales greatly well and no missing pixels. Problem is about location. \$\endgroup\$ Commented Feb 1, 2018 at 20:28
  • \$\begingroup\$ If you are centering an image of width=31 (left shift from center of 15.5px), then you end up on a half step. The filtering would be different. Have you tried flooring the value before draw? (although it wont be centered). I still recommend using a higher resolution texture, and using aliasing/filtering to your advantage. \$\endgroup\$
    – Kyy13
    Commented Feb 1, 2018 at 20:38
  • \$\begingroup\$ Yeah I know about halfstep and it's the cause of the problem. I ask the best way to deal with it. I can't also understand if I need to know pixel resolution of every device I work with and use that, what's the point of using camera and virtual coordinates? \$\endgroup\$ Commented Feb 1, 2018 at 20:42
  • \$\begingroup\$ It may fix this one issue, nice. But I want to support many different resolutions. I can't know which coordinates/sizes I used throughout the game will have problems. Putting round function for every number i write seems impractical. Am I wrong? \$\endgroup\$ Commented Feb 1, 2018 at 20:50
  • \$\begingroup\$ 1. Floor the value so it's not on a half step, 2. Increase the resolution of the texture, 3. Turn off anti-aliasing, 4. scale the texture so it is always even width e.g. int(width/2.0) & ~1. The main advantage of higher res. texture is that you can filter it so that it's percieved to be centered even though it isn't \$\endgroup\$
    – Kyy13
    Commented Feb 1, 2018 at 20:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .