Understanding the libGDX Projection Matrix - java

Over the past few weeks I've been attempting to learn the libGDX library. I'm finding it hard, especially for my first endeavor toward game development, to comprehend the system of Camera/viewport relationships. One line of code that I've been told to use, and the API mentions, is:
batch.setProjectionMatrix(camera.combined);
Despite a good 4 hours of research, I'm still lacking a complete understanding of the functionality of this code. It is to my basic understanding that it "tells" the batch where the camera is looking. My lack of comprehension is depressing and angering, and I'd appreciate if anyone could assist me. Another issue with the code snippet is that I'm unsure of when it's necessary to implement (in the render method, create method, etc).

Consider taking a picture with a camera. E.g. using your smartphone camera taking a picture of a bench in the park. When you do that, then you'll see the bench in the park on the screen of your smartphone. This might seem very obvious, but let's look at what this involves.
The location of the bench on the picture is relative to where you were standing when taking the photo. In other words, it is relative to the camera. In a typical game, you don't place object relative to the object. Instead you place them in your game world. Translating between your game world and your camera, is done using a matrix (which is simply a mathematical way to transform coordinates). E.g. when you move the camera to the right, then the bench moves to the left on the photo. This is called the View matrix.
The exact location of the bench on the picture also depends on the distance between bench and the camera. At least, it does in 3D (2D is very similar, so keep reading). When it is further away it is smaller, when it is close to the camera it is bigger. This is called a perspective projection. You could also have an orthographic projection, in which case the size of the object does not change according to the distance to the camera. Either way, the location and size of the bench in the park is translated to the location and size in pixels on the screen. E.g. the bench is two meters wide in the park, while it is 380 pixels on the photo. This is called the projection matrix.
camera.combined represents the combined view and projection matrix. In other words: it describes where things in your game world should be rendered onto the screen.
Calling batch.setProjectionMatrix(cam.combined); instruct the batch to use that combined matrix. You should call that whenever the value changes. This is typically when resize is called and also whenever you move or otherwise alter the camera.
If you are uncertain then you can call that in the start of your render method.

The other answer is excellent, but I figure a different way of describing it might help it to click.
You generally deal with your game in "world space", a coordinate system that is analogous to the real world. In linear algebra, you can convert points in space from one coordinate system to another by multiplying the point's coordinates by a matrix that represents the relation between two coordinate systems.
The view matrix is multiplied by a point to convert it from world space to camera space (the camera's point of view). The projection matrix is used to convert a point from camera space to screen space (the flat 2D rectangle of your device's screen). When you call update() on a camera in Libgdx, it applies your latest changes to position, orientation, viewport size, field of view, etc. to its view and projection matrices so they can be used in shaders.
You rarely need to deal with stuff in camera space in 2D, so SpriteBatch doesn't need separate view and projection matrices. They can be combined into a single matrix that converts straight from world space to screen space, which is already done automatically in the Camera, hence the camera.combined matrix.
SpriteBatch has a default built-in shader that multiplies this projection matrix by all the vertices of your sprites so they will be properly mapped to the flat screen.
You should call setProjectionMatrix whenever you have moved the camera or resized the screen.
There is a third type of matrix called a model matrix that is used for 3D stuff. A model matrix describes the model's orientation, scale, and position in world space. So it is multiplied by coordinates in the model to move them from local space to world space.

Take for example a basic sidescrolling game. As the player moves to the side, the camera pans to follow them. This means that where objects are in the world doesn't necessarily correspond to where they are on the screen, since the screen and the world move relative to each other.
Here's an example: say your screen is 100px*100px square (for some reason). You place an object at position (50, 0), so it's now in the middle and at the bottom of the screen. Now say you move your player over to the right, and the whole screen pans to follow the player. This means that the object you placed earlier should have moved left on the screen. So it's still at (50, 0) in the world, since it didn't actually move relative to the rest of the scenery, but it should now be drawn at, say, (10, 0) on the screen, since which part of the world the screen is looking at has changed. This is the difference between "worldspace" (where an object is in the world) and "screenspace" (where the object is drawn on the actual display).
When you try to draw with a SpriteBatch, it is by default going to assume worldspace coordinates are the same as screenspace coordinates: when you say "draw at (50, 0)", it's going to draw the object at (50, 0) on the screen. Even if the camera moves, it's always going to draw at (50, 0) on the screen, so as the camera pans, the object will follow and stay stuck to the same place on the screen.
Since you usually don't want that, you give the SpriteBatch a projection matrix, which is a transformation matrix that tells how to convert screenspace coordinates to worldspace coordinates, and vice versa. This way, when you tell the batch "draw at (50, 0)", it can look at the matrix it got from the camera and see that, since the camera has moved, (50, 0) in the world actually means (10, 0) on the screen, and it will draw your sprite in the right place.

Related

Understanding different coordinate systems, Tiled, Stage, Screen,

I am very confused about all the different coordinate systems.
I am using LibGDX with Tiled.
These all have their own coordinate system (sortof).
LibGDX screen
Tiled map
UIcamera
Orthogonal TiledMapCamera
UIStage
TiledMapStage
It's too many concepts and I can no longer mentally understand how they affect each other in complex scenarios, like
having different screen dimensions than the tiled map dimensions
when resizing the screen.
Can someone shed some light on this?
Many thanks!
In a 2D game, you really only have to think about the coordinate system of the orthographic camera. Whatever is drawn with a certain camera's combined matrix is fit to the rectangle of the screen (and if you set up the camera correctly, it will not be distorted).
LibGDX provides the Viewport classes for helping to set up your camera. You can think of them as camera managers that will size the camera to meet the arrangement you want. You instantiate them with a desired size "window" you want to see of the game world. And the only place you have to consider the actual screen dimensions is in the resize method, where you pass the dimensions to the Viewport class and let it handle sizing your camera for you so the scene won't be distorted.
You might have more than one camera. Typically your UI will have its own, and the gameplay world will have another (because you want it to move around in the world).
When it comes to input, the raw X and Y are given in screen pixel coordinates, but you just pass these coordinates to the camera.unproject method to have them converted to the same coordinates as your game world.
I don't use tiles, so I can't get specific there, but the same principles should apply.

box2d on different positions of the sprites on libgdx

I create a class for the DynamicBody balls and other for the walls, every class are according to tutorials and they work, the balls fall, but the problem is that the geometric shape use by box2d are not at the same place as the sprites, for what I search on google has something to do with the world of box2d not been using the camera or the camera vewport
other point is that when I create the world I use this
world = new World(new Vector2(0, -9.8f), true);
I was expecting that aggravation behaves like in the real world but appears much slower.
When creating box2d objects the origin is in the centre so a 2 wide object will have 1 unit left of the position set and one right. Textures are usually drawn with the lower left corner at the position so a 2 unit wide texture would have both units to the right of the position.
To fix this you just need to draw the image 1/2 the width to the left and 1/2 the hight to the bottom. e.g
draw(texture, position.x-(width/2),position.y-(height/2));
For your second question: the box2d world uses meters and kilograms for the calculations.
So if you give the physical world data in pixel space, like an impulse vector (100px, 100px), the world sees this as (100m, 100m). Then everything behaves like it's gigantic and from a far away view. So it seems slow from that point of view.
What you have to do is define a conversion rate (like 100px = 1m) and apply the conversion everywhere you like to move screen objects with box2d.
EDIT: See also: https://github.com/libgdx/libgdx/wiki/box2d#creating-a-world:
"In Box2D 1 unit = 1 meter."

Finding A World Space Vector Using Unproject

I'm experimenting with LibGDX and 3D in a projection view. Right now I'm looking at how to determine the outermost bounds of my viewport in world space at z=0.0, in order to draw coordinate grid no larger than necessary. However, I seem to have outpaced my education in that I haven't taken a formal linear algebra class and am still a little fuzzy on matrix math.
Is there a way to determine where I should start and stop drawing lines without resorting to using picking and drawing a transparent plane to intersect with?
LibGDX's unproject function takes screen coordinates in a Vector3 and returns a Vector3 in world space from the near clipping plane to the far, given the provided z. However, given that I have a translated and rotated Camera (an encapsulation of the viewprojection matrix and a slew of convenience methods), it occurs to me that I can't pick an arbitrary z to put in the window coordinate vector and just set it to 0.0 after unprojection, as that point probably won't be the furthest viewable point in the viewport. So how do I know what z value to use in the window coordinate that will give the the x and y I need in world space that's at z=0.0?
EDIT (UPDATE):
So apparently it looks like the problem I'm looking at is plane intersection, which would require ray tracing. So now I suppose my question is this: is ray tracing 4 times per render loop (or, I suppose whenever the camera has moved) worth the payoff of being able to dynamically draw a worldspace coordinate grid no larger than the viewport? If not, is there a cheaper algorithm I can use to estimate where I should start and stop drawing lines?

box2dlights set scale from box2d

I'm making a game in libGDX and I decided to use box2dlights to render the lights. I did not used cameras so much up to this point, because I already had most of the code done in pure LWJGL. There are two main operations that I need to do with the coordinates of everything.
The first is to translate the screen to the position of the map (the map is bigger than the screen, and the position of the player defines what portion of the map is visible). So for example, if the player is at (50, 30), I translate everything by (-50, -30), so that the player is in the middle.
The second thing is to multiply everything by a constant, that is the conversion from box2d meters to pixels on screen.
However, since I do not have access to box2dlights rendering, I need to pass these two information to the ray handler, and the only way to do that is via Camera. So I created an Orthographic Camera and translate it in deltaS every tick before drawing, instead of manually subtracting deltaS from every coordinate. That part works perfectly. On the other hand, the zoom thingy does not seem to work, because it zooms in and out based in the middle of the screen. For example, if I set zoom = 2, the screen is reduced twice, but it is centered on the screen. The coordinate (0,0) is not (0,0), as I would expect, but instead is screen.width/4.
Is there any way to set the camera so that it multiplies every coordinate by a number, you would assume zoom function should do OR is there any way to do it directly on box2dlights?
I don't know if my problem is very clear or common, but I can't find anything anywhere.
I finally figured it out! The problem was that I needed to set the zoom before I used
camera.setToOrtho(true, SCREEN_WIDTH, SCREEN_HEIGHT);
Because that method uses the current zoom to set its properties. Hope this helps!

Libgdx: Infinity world. How to?

I write simple game with libGdx. I have a hero, which always is in screen center and I must move my background sprite (or region?) to make move illusion. But my background sprite isn't infinity.
How can I create illusion of seamless infinity world?
Of course I can add several background sprites to try to cover all empty space of screen. But I must to draw out of the sceen a lot of all another objects: Houses, monsters, others heroes, etc. So I have a second question:
When I try to draw other object (a lot of objects!) out of the screen, how badly it affects memory? How to draw it correctly?
I know that OrthographicCamera in libgdx draw only viewportWidth-viewportHeight area. If it's right, then I must to move my camera and all my sprites too. I think it's not correctly.
How can I render infinity world in libgdx with OrthographicCamera?
How can I create illusion of seamless infinity world?
Create a tile background. Tile background means that if it was besides or top or bottom of itself, the edges of sticking line will not be visible to viewer.
To do this open your background image in photoshop and go to Filters > Other > Offset.
Set the offset filter to offset the background to center then try using photoshop tools to hide the edges (the + shape in image). Now again go to offset and return to 0, 0 and save your background.
When I try to draw other object (a lot of objects!) out of the screen,
how badly it affects memory? How to draw it correctly?
I have checked this and that was not much fps loosing on my test. So don't worry about it.
How can I render infinity world in libgdx with OrthographicCamera?
Move camera where-ever you want any x, y. Every time see where is camera and calculate needing tile backgrounds to draw (for example every time draw 3x3=9 backgrounds sticking together).

Categories