Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example demonstrating how to zoom orthographic cameras #2580

Closed
alice-i-cecile opened this issue Aug 1, 2021 · 7 comments · Fixed by #15092
Closed

Add example demonstrating how to zoom orthographic cameras #2580

alice-i-cecile opened this issue Aug 1, 2021 · 7 comments · Fixed by #15092
Labels
A-Rendering Drawing game state to the screen C-Docs An addition or correction to our documentation D-Trivial Nice and easy! A great choice to get started with Bevy

Comments

@alice-i-cecile
Copy link
Member

How can Bevy's documentation be improved?

Zooming an orthographic camera is surprisingly tricky; unlike ordinary cameras moving them further away from the object doesn't cause the size of the objects displayed to change as all their projection is parallel.

@TheRawMeatball provided this initial solution in #help:

fn zoom_system(
    mut whl: EventReader<MouseWheel>,
    mut cam: Query<(&mut Transform, &mut OrthographicProjection), With<MainCamera>>,
    windows: Res<Windows>,
) {
    let delta_zoom: f32 = whl.iter().map(|e| e.y).sum();
    if delta_zoom == 0. {
        return;
    }

    let (mut pos, mut cam) = cam.single_mut().unwrap();

    let window = windows.get_primary().unwrap();
    let window_size = Vec2::new(window.width(), window.height());
    let mouse_normalized_screen_pos =
        (window.cursor_position().unwrap() / window_size) * 2. - Vec2::ONE;
    let mouse_world_pos = pos.translation.truncate()
        + mouse_normalized_screen_pos * Vec2::new(cam.right, cam.top) * cam.scale;

    cam.scale -= ZOOM_SPEED * delta_zoom * cam.scale;
    cam.scale = cam.scale.clamp(MIN_ZOOM, MAX_ZOOM);

    pos.translation = (mouse_world_pos
        - mouse_normalized_screen_pos * Vec2::new(cam.right, cam.top) * cam.scale)
        .extend(pos.translation.z);
}

This should be straightforward to verify and clean up. Adding panning or rotation might also be worth including in the same example.

@alice-i-cecile alice-i-cecile added C-Docs An addition or correction to our documentation D-Trivial Nice and easy! A great choice to get started with Bevy A-Rendering Drawing game state to the screen labels Aug 1, 2021
@Matthew-Maclean
Copy link

I think this should also note that if the scale is less than one then you may have to modify the far component on the projection, as per #239.

@BlackPhlox
Copy link
Contributor

BlackPhlox commented Aug 1, 2021

@alice-i-cecile I also think zoom for PerspectiveProjection (3D View) might be good for consistency.
Here's the PerspectiveProjection version (Based on my bevy_config_cam implementation)

fn zoom_3d_system(
    mut whl: EventReader<MouseWheel>,
    mut query: Query<(&mut Camera, &mut PerspectiveProjection)>,
	windows: Res<Windows>,
){
    let delta_zoom: f32 = whl.iter().map(|e| e.y).sum();
    if delta_zoom == 0. {
        return;
    }

    let prim = windows.get_primary().unwrap();
    for (mut camera, mut project) in query.iter_mut() {
        project.fov = (project.fov - delta_zoom * 0.01).abs();
        
        //Calculate projection with new fov
        project.update(prim.width(), prim.height());

        //Update camera with the new fov
        camera.projection_matrix = project.get_projection_matrix();
        camera.depth_calculation = project.depth_calculation();

        println!("FOV: {:?}", project.fov);
    }
}

@bas-ie
Copy link
Contributor

bas-ie commented Sep 5, 2024

I might take a crack at this one. I'm aware of related PR #11022 and will adopt that if the author doesn't clear the conflicts.

@bas-ie
Copy link
Contributor

bas-ie commented Sep 7, 2024

Hrm. Quite a bit has changed in OrthographicProjection since this issue's sample code was written. We now have area, for example. I'll see what I can come up with.

@bas-ie
Copy link
Contributor

bas-ie commented Sep 7, 2024

I notice that in 2024 I'm able to happily scroll without needing to modify the transform at all, take into account mouse position etc. Am I missing something? For example, this seems to work fine:

fn camera_controls(
    mut camera: Query<&mut Projection, With<Camera>>,
    mut mouse_wheel_input: EventReader<MouseWheel>,
) {
    let delta_zoom: f32 = mouse_wheel_input.read().map(|e| e.y).sum();
    if delta_zoom == 0. {
        return;
    }

    let mut projection = camera.single_mut();
    if let Projection::Orthographic(cam) = &mut *projection {
        let ScalingMode::FixedVertical(current) = cam.scaling_mode else {
            return;
        };
        let zoom_level = (current + CAMERA_ZOOM_SPEED * delta_zoom)
            .clamp(CAMERA_ZOOM_RANGE.start, CAMERA_ZOOM_RANGE.end);
        cam.scaling_mode = ScalingMode::FixedVertical(zoom_level);
    }
}

@bas-ie
Copy link
Contributor

bas-ie commented Sep 7, 2024

Quick demo: https://youtu.be/OVUyaQ0a8Ss

@bas-ie
Copy link
Contributor

bas-ie commented Sep 7, 2024

If we didn't need to clamp, we could just

cam.scaling_mode *= CAMERA_ZOOM_SPEED * delta_zoom;

and be done with it.

github-merge-queue bot pushed a commit that referenced this issue Sep 9, 2024
# Objective

Add examples for zooming (and orbiting) orthographic and perspective
cameras.

I'm pretty green with 3D, so please treat with suspicion! I note that
if/when #15075 is merged, `.scale` will go away so this example uses
`.scaling_mode`.

Closes #2580

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
github-merge-queue bot pushed a commit that referenced this issue Sep 9, 2024
# Objective

Hello! I am adopting #11022 to resolve conflicts with `main`. tldr: this
removes `scale` in favour of `scaling_mode`. Please see the original PR
for explanation/discussion.

Also relates to #2580.

## Migration Guide

Replace all uses of `scale` with `scaling_mode`, keeping in mind that
`scale` is (was) a multiplier. For example, replace
```rust
    scale: 2.0,
    scaling_mode: ScalingMode::FixedHorizontal(4.0),

```
with
```rust
    scaling_mode: ScalingMode::FixedHorizontal(8.0),
```

---------

Co-authored-by: Stepan Koltsov <stepan.koltsov@gmail.com>
github-merge-queue bot pushed a commit that referenced this issue Sep 9, 2024
# Objective

Add examples for zooming (and orbiting) orthographic and perspective
cameras.

I'm pretty green with 3D, so please treat with suspicion! I note that
if/when #15075 is merged, `.scale` will go away so this example uses
`.scaling_mode`.

Closes #2580
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Docs An addition or correction to our documentation D-Trivial Nice and easy! A great choice to get started with Bevy
Projects
None yet
4 participants