aevyrie / bevy_editor_cam

A camera controller for editors and CAD.
Apache License 2.0
46 stars 5 forks source link

feature suggestion: zoom through objects #12

Closed ghost closed 1 month ago

ghost commented 4 months ago

Motivation

This feature suggestion adds the ability to zoom through objects as a configurable option for the editor cam.

While the philosophy section of this plugin includes the following text:

The camera should zoom in and out in the direction you are pointing. If the user is hovering over something, the speed of the camera should automatically adjust to quickly zoom up to it without clipping through it.

I believe the ability to move through objects easily can be helpful for cases in which objects are behind each other or contained within other objects (such as in the case of architectural models). However I made it optional (disabled by default) so as not to break existing projects.

Demonstration

https://github.com/aevyrie/bevy_editor_cam/assets/117374589/6daeff0b-4af1-451f-a73d-58696499abaa

aevyrie commented 4 months ago

Thanks for the contribution, and taking the time to read through the docs.

I think I need some time to think about how this should work. I've thought about the case you mention, and it also comes up when zooming out from within an enclosed space: as you zoom out, you can zoom through things behind you, then be unable to zoom in because there is now something in front of you.

I think my biggest concern is making sure this doesn't break assumptions or otherwise interact strangely with any other features. The fact that this check only happens when zoom starts will help, but I also wonder if that will lead to confusing behavior, where you need to pause before zooming through an object.

I'd love to hear your thoughts!

ghost commented 3 months ago

Sorry about the big pause in communication, I was away for a couple of weeks.

I have updated the example for bevy 0.14 and taken another look at the points you've laid out in your camera manifesto. Regarding the potential breakage of assumptions:
The change does contradict the point you laid out in "Intuitive Zoom" as this change explicitly does not prevent users from clipping through objects. However the slowdown that occurs when zooming closer to objects does still exist and will prevent users from uncontrollably shooting through objects (unless of course the minimum distance is set very high).

Personally I feel this almost better fulfills the responsiveness criteria than the original implementation, since in the current version, if you zoom very close to an object, the camera speed slows to a crawl and at some point zooming in no longer feels like it has an effect, which in turn feels unresponsive. Apart from this I see no point of your philosophy that might be contradicted by this change.

As for odd interactions with other features (and your concern about having to pause before zooming through an object), the only interaction that can feel slightly strange is the aforementioned slowing of camera movement when getting close to objects. This causes the camera to slow until you are at the minimum distance or below and then to speed up again once you've passed through the object (this effect is somewhat visible in the video of my original post). It does not require the user to stop before zooming through anything but it could feel odd to have these changes in speed.

I don't know of a solution that could solve this problem perfectly. However by having the minimum distance configurable, each developer can fine tune it to be a minimum speed that feels good in their use case, so I don't see this as a particularly major issue.

aevyrie commented 1 month ago

Hey there, I'd like to get this merged. Apologies for the silence, I've been away on parental leave.

After taking another look at this, there is only one change I'd like to make. As-is, when you hit the minimum distance this implementation will continue zooming through the object. The alternative would be to instead halt the camera completely - this is what MCAD camera controllers tend to do, you can only zoom in or out so much.

I think I'd like to change minimum_distance to an enum, to describe what to do when you hit that minimum distance.

/// Define what happens when the camera is zoomed in all the way.
enum ZoomMinimum {
    /// When the camera is zoomed in to `nearest_distance`, clamp the zoom speed, allowing the camera to pass through the object instead of zooming up to the surface.
    PassThrough {
        nearest_distance: f32
    },
    /// When the camera is zoomed in to `nearest_distance`, prevent the camera from zooming in any closer.
    Halt {
        nearest_distance: f32
    }
}

Halt would become the new default, with some small value that prevents the camera from zooming in so far you start to see floating point rendering artifacts - which happens today.

I'll take care of these modifications and get this merged. Thanks for the contribution and discussion!

aevyrie commented 1 month ago

I've added a zoom out limit while I was at it, in a fit of scope creep.

Doing some testing, I found one of those "odd interactions" I was worried about. The PassThrough limits only make sense in perspective. In ortho, the camera cannot zoom through objects, because zoom works through scaling, not moving the camera.

I will also need to compute the ortho equivalent anchor length. The current anchor length calculation when used for zoom limits in ortho doesn't work, because the camera is actually very far from the object, and the anchor is very large even when zoomed in (scaled really).

aevyrie commented 1 month ago

I think I'm satisfied with this solution. Instead of using a distance metric, which does not work for orthographic projections, this is now using a world-units-per-pixel metric, which is consistent across any projection type or FOV.