macroquad icon indicating copy to clipboard operation
macroquad copied to clipboard

Camera2D.render_target is upside-down

Open brianwp3000 opened this issue 4 years ago • 12 comments

The render_target field of a Camera2D is upside-down. I have included a repro--the gist is that if you draw a texture to a render_target and then draw that render_target to the screen the texture appears upside-down.

use macroquad::prelude::*;

#[macroquad::main("Texture")]
async fn main() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture: Texture2D = load_texture("examples/ferris.png").await;

    loop {
        // draw Ferris to the render_target texture
        set_camera(render_target_camera);

        clear_background(RED);
        draw_texture(
            ferris_texture,
            0.,
            0.,
            WHITE,
        );

        // draw the render_target texture to the screen
        set_camera(Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));

        draw_texture(
            render_target_camera.render_target.unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

image

brianwp3000 avatar Mar 16 '21 23:03 brianwp3000

I have the same issue in macroquad version 0.3.0-alpha.15.

For now I am using:

draw_texture_ex(
      TEXTURE,
      0.0,
      0.0,
      WHITE,
      DrawTextureParams {
        flip_y: true,
        ..Default::default()
      },
    );

As a temporary solution works.

nicolas-sabbatini avatar Mar 23 '21 02:03 nicolas-sabbatini

The behavior depends on whether there's a render target or not.

use macroquad::prelude::*;

#[macroquad::main("Camera bug")]
async fn main() {
    let render_target = render_target(600, 400);
    let rect = Rect::new(0.0, 0.0, 600.0, 400.0);
    let mut camera = Camera2D::from_display_rect(rect);
    //camera.zoom.y = -camera.zoom.y; // uncomment this to fix
    camera.render_target = Some(render_target); // or comment out this to fix

    loop {
        set_camera(&camera);

        clear_background(BLANK);
        draw_text("test", 50.0, 50.0, 32.0, GREEN);
        draw_line(0.0, 0.0, 300.0, 300.0, 1.0, GREEN);

        set_default_camera();
        draw_texture(render_target.texture, 0.0, 0.0, WHITE);

        next_frame().await
    }
}

When using a camera without a render_target set, from_display_rect works correctly. When there is a render target, however, it needs to be flipped (either when rendering it to screen or when setting up the camera).

I thought the culprit is the minus sign in zoom: vec2(1. / rect.w * 2., -1. / rect.h * 2.), in Camera2D::from_display_rect but and reported it on Discord but was dismissed - i didn't know at the time it only happened when using a render target. It seems the fix needs to be somewhere else because removing the minus sign would break rendering to screen directly.

martin-t avatar Jul 15 '21 10:07 martin-t

This is definitely an issue, but yeah you can just work around it :)

eboatwright avatar Jan 05 '22 20:01 eboatwright

I have experienced the same issue but you can just set the camera rotation to 180 degrees (or +180 degrees if you want to rotate it around in the game)

GreenSlimeStudios avatar Aug 24 '22 16:08 GreenSlimeStudios

The problem here - there are way too many projects already that have this scale: vec2(1, -1)(or flip_y: true) in their cameras.

So we are waiting for the fix for some major macroquad update, to break all the things altogether.

not-fl3 avatar Aug 24 '22 16:08 not-fl3

@not-fl3 That makes sense

eboatwright avatar Aug 24 '22 20:08 eboatwright

I just runned the OP code in macroquad 0.4

use macroquad::prelude::*;

#[macroquad::test]
async fn test_camera_y() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture = load_texture("examples/ferris.png").await.unwrap();

    for _ in 0..100 {
        // draw Ferris to the render_target texture
        set_camera(&render_target_camera);

        clear_background(RED);
        draw_texture(&ferris_texture, 0., 0., WHITE);

        // draw the render_target texture to the screen
        set_camera(&Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));

        draw_texture(
            &render_target_camera.render_target.as_ref().unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

and the ferris is not upside down:

image

But there are reports on discord that the issue still persists? If someone knows how I can reproduce it in 0.4 - please, post it here :)

not-fl3 avatar Jul 19 '23 01:07 not-fl3

This works for me with 0.4.1 on a Mac.

It looks like it's flipped when using set_default_camera() though.

use macroquad::prelude::*;

#[macroquad::main("Test")]
async fn main() {
    let mut render_target_camera = Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.));
    render_target_camera.render_target = Some(render_target(800, 600));

    let ferris_texture = load_texture("ferris.png").await.unwrap();

    for _ in 0..100 {
        // draw Ferris to the render_target texture
        set_camera(&render_target_camera);

        clear_background(RED);
        draw_texture(&ferris_texture, 0., 0., WHITE);

        // draw the render_target texture to the screen
        //set_camera(&Camera2D::from_display_rect(Rect::new(0., 0., 800., 600.)));
        set_default_camera();

        draw_texture(
            &render_target_camera.render_target.as_ref().unwrap().texture,
            0.,
            0.,
            WHITE,
        );

        next_frame().await
    }
}

ollej avatar Jul 19 '23 09:07 ollej

Confirming that the issue still happens in ollej's example using set_default_camera but not in not-fl3's example with set_camera.

martin-t avatar Jul 19 '23 12:07 martin-t

I have just updated my project from 0.3.24 to 0.4.5 and ran into this. The y-axis of my program has been reversed.

Here is a minimal example:

use macroquad::prelude::*;

#[macroquad::main("example")]
async fn main() {
    let camera = Camera2D {
        target: vec2(0.0, 0.0),
        zoom: vec2(1.0 / screen_width() * 2., -1.0 / screen_height() * 2.),
        offset: vec2(0., 0.),
        rotation: 0.,
        render_target: None,
        viewport: None,
    };
    let top_left = camera.screen_to_world(vec2(0.0, 0.0));
    println!("top left: {:?}", top_left);
}
# 0.3.24
top left: Vec2(-400.0, -300.0)
# 0.4.5
top left: Vec2(-400.0, 300.0)

mandroll avatar May 08 '24 09:05 mandroll

I have just updated my project from 0.3.24 to 0.4.5 and ran into this. The y-axis of my program has been reversed.

Here is a minimal example:

use macroquad::prelude::*;

#[macroquad::main("example")]
async fn main() {
    let camera = Camera2D {
        target: vec2(0.0, 0.0),
        zoom: vec2(1.0 / screen_width() * 2., -1.0 / screen_height() * 2.),
        offset: vec2(0., 0.),
        rotation: 0.,
        render_target: None,
        viewport: None,
    };
    let top_left = camera.screen_to_world(vec2(0.0, 0.0));
    println!("top left: {:?}", top_left);
}
# 0.3.24
top left: Vec2(-400.0, -300.0)
# 0.4.5
top left: Vec2(-400.0, 300.0)

Ha, I too performed the same upgrade and ended up experiencing the same change not long ago!

It's extra funky because I'm using Camera2D for some render target stuff as well and it seems like just flipping it everywhere doesn't do quite the right thing, for example here: https://github.com/profan/some-macroquad-things/blob/master/territory/src/main.rs

I have my own Camera2DExt::from_display_rect_fixed but use the normal old from_display_rect for my render target case, so I wonder what caused this upstream?

profan avatar May 08 '24 18:05 profan

I have my own Camera2DExt::from_display_rect_fixed but use the normal old from_display_rect for my render target case, so I wonder what caused this upstream?

I'd guess the relevant change was https://github.com/not-fl3/macroquad/commit/38879533526259ead802a56f41dcfef78c273452, as it flips the zoom only for from_display_rect while leaving the default unflipped.

Also just ran into this by accident, playing around with the camera for the first time.

Reminds me of how we broke source rects in draw params between versions back then in ggez. Good times.

EDIT: I also just stumbled over these lines in the matrix function for Camera2D: https://github.com/not-fl3/macroquad/blob/4e27d18a207a55c00e486472ec88a88c63d6e961/src/camera.rs#L96-L100 What they do seems to fit the definition of turning everything upside down if there's a render_target ^^

PSteinhaus avatar Jun 04 '24 15:06 PSteinhaus