arcade icon indicating copy to clipboard operation
arcade copied to clipboard

arcade.Camera not displaying correctly when position is not 0,0 (left, bottom)

Open alejcas opened this issue 3 years ago • 15 comments

I would like the arcade.Camera left, bottom positions to be configurable. Now 0,0 its hardcoded. That's part one.

As I talked on Discord with Clepto theoretically we just need to change:

class NewCamera(arcade.Camera):

    def __init__(self, left, bottom, viewport_width: int = 0, viewport_height: int = 0):
        self.left = left
        self.bottom = bottom
        super().__init__(viewport_width, viewport_height)

    def set_projection(self):
        """
        Update the projection matrix of the camera. This creates an orthogonal
        projection based on the viewport size of the camera.
        """
        self.projection_matrix = Mat4.orthogonal_projection(
            self.scale * self.left,
            self.scale * self.viewport_width,
            self.scale * self.bottom,
            self.scale * self.viewport_height,
            self.near,
            self.far
        )

    def use(self):
        """
        Select this camera for use. Do this right before you draw.
        """
        self._window.current_camera = self
        self.update()
        self._window.ctx.viewport = int(self.left), int(self.bottom), int(self.viewport_width), int(self.viewport_height)
        self._window.ctx.projection_2d_matrix = self.combined_matrix

But when doing so, If I position the camera at say (600, 0) I got two issues:

  1. The position of the sprites get inverted (right - left)
  2. The sprites are streched

Below you a have an image showing this: One camera set at (0,0) (left one). Sprites are 32x32 and look normal. Also, sprite at left, bottom (0,0) is yellow so you can see the effect when setting the camera away from (0,0). However, at the right you have another camera set at (600,0). You can see that the yellow sprite is at the right (but it's position is still at left, bottom (0,0) and you can see how the 32x32 sprites are distorded.

image

alejcas avatar Jan 31 '22 13:01 alejcas

Any chances this could be somehow fixed? I've no clue why this happens so I can't fix it.

Also this is pretty needed if you want for example a minimap camera and the minimap is not at left, bottom = 0,0.

alejcas avatar Apr 01 '22 08:04 alejcas

I don't understand what the use-case is, or what is being attempted here.

pvcraven avatar Apr 01 '22 16:04 pvcraven

There are two issues:

  1. arcade.Camera is set to begin at 0,0 left bottom. So if you want the camera set at the top right corner you can’t
  2. even if modify the arcade.Camera code to set the camera away from 0,0. The image gets distorded and inversed on the x axis.

alejcas avatar Apr 01 '22 16:04 alejcas

Sorry I'm dense, I still don't get it. You want to invert the Y axis? Put 0,0 in the upper left and then as y gets bigger it should go down?

pvcraven avatar Apr 01 '22 16:04 pvcraven

Just try te set the camera on the top right corner. You will find that this is impossible at the moment.

alejcas avatar Apr 01 '22 16:04 alejcas

F&€@&ck! I explain this very bad.

If you follow the minimap example and instead of setting the minimap at the left bottom corner try to set the minimap at the top right

alejcas avatar Apr 01 '22 16:04 alejcas

Is the goal to not draw over the entire screen?

pvcraven avatar Apr 01 '22 17:04 pvcraven

Let me prepare a mock up so i can explain this better

alejcas avatar Apr 01 '22 17:04 alejcas

Here's something you can play with. It's all about setting viewport and projection vaues. The current camera definitely needs to be more flexible.

  • The viewport decides the poistion and size of the area we want to render into
  • The projections decides what geometry should be projected into the viewport

The example below creates two simple cameras with different viewport and projection setup. We render the same "scene" twice into different parts of the screen. The options here are pretty much endless. We should explain these concepts to users somewhere.

import arcade

class Camera:

    def __init__(self, viewport = None, projection = None):
        self.window = arcade.get_window()
        self.ctx = self.window.ctx
        self.viewport = viewport or (0, 0, self.window.width, self.window.height)
        self.projection = projection or (0, self.window.width, 0, self.window.height)

    def use(self):
        self.ctx.viewport = self.viewport
        self.ctx.projection_2d = self.projection

class CameraTest(arcade.Window):

    def __init__(self):
        super().__init__(800, 600, "Camera Test")
        self.sprite = arcade.Sprite(
            ":resources:images/items/coinGold.png",
            center_x=200, center_y=300,
        )
        self.camera_left = Camera(
            viewport=(0, 0, 400, 600),
            projection=(0, 400, 0, 600)
        )
        self.camera_right = Camera(
            viewport=(400, 0, 400, 600),
            projection=(0, 400, 0, 600)
        )

    def on_draw(self):
        self.camera_left.use()
        self.clear(color=arcade.color.AERO_BLUE)
        self.sprite.draw()

        self.camera_right.use()
        self.clear(color=arcade.color.AMARANTH)
        self.sprite.draw()

CameraTest().run()

einarf avatar Apr 01 '22 19:04 einarf

Here's something you can play with. It's all about setting viewport and projection vaues. The current camera definitely needs to be more flexible.

  • The viewport decides the poistion and size of the area we want to render into
  • The projections decides what geometry should be projected into the viewport

The example below creates two simple cameras with different viewport and projection setup. We render the same "scene" twice into different parts of the screen. The options here are pretty much endless. We should explain these concepts to users somewhere.

Hi @einarf This is really cool. But this is impossible to achieve with arcade.Camera.

alejcas avatar Apr 05 '22 15:04 alejcas

Check this examples:

Both examples subclass arcade.Camera to allow set viewport and projection left, bottom different from 0,0.

  • Example 1: https://gist.github.com/janscas/01b66fa323f03c69ea7618a29f380b4e
  • Example 2: https://gist.github.com/janscas/32f96506cd6c3067166da1fa57da15af

Example 1 just tries to set the game map (and therefore it's camera) 300 pixels to the left of the window. Example 2 just tries to set two cameras with the same map. One starts at 0,0 left, bottom. The other at 600, 0 left, bottom.

alejcas avatar Apr 05 '22 15:04 alejcas

Hi @einarf This is really cool. But this is impossible to achieve with arcade.Camera.

Can you somehow implement this into arcade.Camera. I mean implement the ability to change viewport and projection values as you did in your example?

alejcas avatar Apr 05 '22 15:04 alejcas

Can you somehow implement this into arcade.Camera. I mean implement the ability to change viewport and projection values as you did in your example?

That is the plan. I'm looking into possibly adding this to development OR 2.7 branch. The thing is that the current Camera is a little bit too opinionated and should probably have been called something else. We should have had a simpler camera base class and I'm trying to sort this out. The idea is to split cameras into different types. A simple camera doesn't need the complexity of the current update() method for example.

einarf avatar Apr 07 '22 20:04 einarf

Hi @einarf can we at least release a SimpleCamera object with the code you provided? And then from here improve the arcade camera system without touching the old Camera.

I will like to help with a PR but I'm lacking a ton of knowledge on projections and etc.

alejcas avatar Aug 30 '22 11:08 alejcas

I can try to look at it in the weekend. We could definitely make a SimpleCamera or similar that supports viewport properly. It's not that difficult to make.

  • viewport just decides what area we should render into as if it was the entire screen (x, y, w, h)
  • projection decides what geometry range should be rendered into the viewport (left, right, bottom top)

It can stretch, zoom or flip in any way you want it. it's all just triangles anyway under the hood.

einarf avatar Aug 30 '22 12:08 einarf

Hi this is now fixed in #1320 so I close the issue

alejcas avatar Oct 27 '22 23:10 alejcas