Zoom with center on Mouseposition

Hi there,

i have made a clone of the TCastleExamineNavigation class called TCADNavigationClass.
As a first step i tried to change the Zoom Method. In CAD Applications it is a normal behaviour that if i Zoom then the centerpoint of zoom is not the center of the Viewport but the point where the mouseposition is.

My idea was to retrieve the actual worldposition of current mousepoint then make the zoom and after that again retrieve the actual worldposition of current mousepoint and make then a Translation so that both matches again. I failed completely to do that :slight_smile:

can someone please point me in the right direction about that?

thanks Michael

Family of methods PositionFromXxx, PositionToXxx on TCastleViewport ( Castle Game Engine: CastleViewport: Class TCastleViewport ) should be of help here.

E.g. PositionToCameraPlane can convert mouse coordinates (if you set ContainerCoordinates parameter to true, then you can pass there directly e.g. Event.MousePosition) into coordinates in 3D world in the viewport.

PositionFromWorld can convert 3D coordinate inside viewport back into UI coordinates. Note that it doesn’t have ContainerCoordinates parameter (contrary to most other PositionTo/PositionFrom methods) and behaves like ContainerCoordinates was false, so it returns position relative to viewport position. But you can convert it using LocalToContainerPosition to get position in “container coordinates” if necessary.

Thank you for the answer, i was working with an older CGE Version that has not PositionFromXX Methods. Now i downloaded the latest version but it does not compile with latest FPC 3.3.1 There is an error in CastleStringUtils.pas on line 2339.
Result := R.Replace(NamePattern, {$ifdef FPC}@{$endif} C.ReplaceCallback);
castlestringutils.pas(2339,79) Error: Incompatible type for arg no. 2: Got “<procedure variable type of function(TRegExpr):UnicodeString(1200) of object;Register>”, expected “<procedure variable type of function(TRegExpr):AnsiString(0) of object;Register>”

If you use FPC unstable (3.3.1), we assume you use the latest one – you should upgrade your FPC version.

More details:

Of course you can also use stable FPC, 3.2.2, to be more protected from such changes. We support FPC 3.2.0 and 3.2.2 now, and we generally recommend using the latest stable FPC.

Now i use FPC stable with latest CGE and it compiles fine now.
But i can’t get my zoom with center on MousePosition working.
I get Mouseposition with
MPos := ViewPort.Container.MousePosition; // ViewPort is assigned InternalViewport as TCastleViewport
Now i retrieve Position with
ViewPort.PositionToCameraPlane(MPos, true, 1, OldPosition);
After that the scale is made
Camera.Orthographic.Scale := Camera.Orthographic.Scale * Exp(-Factor);
Now i try to get the new position again with
ViewPort.PositionToCameraPlane(MPos, true, 1, NewPosition);
but OldPosition and NewPosition are always the same?

Hm, I suspect here 2 problems on CGE side. They are both possible and easy to fix, I’ll experiment later (if you can submit a reproducible testcase with a problem to https://github.com/castle-engine/castle-engine/issues that would be appreciated though).

My suspicions:

  1. PositionToCameraPlane doesn’t account for Camera.Orthographic.Scale. This camera scaling is done in a special way. If you know you always have orthographic projection, then PositionTo2DWorld will work better, it definitely accounts for Camera.Orthographic.Scale.

  2. You’ll land at a different problem though: PositionToXxx rely on projection parameters that are updated every frame, not immediately after Camera.Orthographic.Scale change in code. You can workaround it temporarily by removing the condition if not FProjection.Initialized then... inside TCastleViewport.PositionToPrerequisites implementation in src/scene/castleviewport.pas. Then PositionTo2DWorld should be fully reliable.

As I emphasize, both problems can be just fixed on CGE side, i.e. to make both PositionToCameraPlane and PositionTo2DWorld reliable automatically in such case. If you can submit a simple testcase showing the problem now, that will make it easier to experiment for me :slight_smile:

thank you very much. I have opened an issue with a little testproject appended.
Normally in CAD applications i use only orthographic view but not 2D

1 Like

Fixed in We need to call PositionToPrerequisites before every PositionToXxx · castle-engine/castle-engine@81659c4 · GitHub , thanks for the testcase – this made testing this easy.

In the end my suspicion AD 1 was incorrect but suspicion AD 2 was correct. PositionToCameraPlane was doing correct calculation, it already took Camera.Orthographic.Scale into account, but it didn’t react to changing Camera.Orthographic.Scale immediately, it was only updating the output next frame. This is now fixed.

Your application now presents a nice zoom to mouse position!

Notes:

  1. If you update to latest CGE, you will have to do some fixes in cadnavigation, some code you copied from TCastleExamineNavigation needs adjusting after Vectors changes, to avoid a trap with modifying a temporary value – Castle Game Engine . In short, just try to compile it, and replace reported places (4, as far as I recall) from

    V[xxx]

    to

    V.InternalData[xxx]

  2. Note that comparing vectors like V1 <> V2 compares them tolerating tiny epsilon differences. Better use TVector3.PerfectlyEquals(....) if you want exact comparison.

    In case of this code, I would actually completely avoid the

    if (OldPosition <> NewPosition) then
    

    check. You can just use Translation := Translation + NewPosition - OldPosition; without any check, changing camera position is really instant. (and this check will usually be true anyway, so you will more often waste a bit of time doing the check, than you will save time by avoiding Translation change.)

  3. I like this modification :slight_smile:

    I think both scaling ways (to screen center, to point under mouse) make sense in general CGE. Looking at authoring software I know, it’s also using various approaches: Blender zooms to center, while Spine (2D animation software) zooms to point under mouse (much like with your CADNavigation). Oh, I can actually change Blender to also do this: “Preferences->Navigation->Zoom To Mouse Position” makes Blender also work like this (and it works in both perspective and orthographic projection). So it’s a confirmation in my eyes that this is a useful feature that we’d like in CGE :slight_smile:

    I’d welcome PR to add this to CGE, as an option to our TCastleExamineNavigation. I’d say this should be activated by a Boolean property TCastleExamineNavigation.ZoomToMousePosition (consistent with Blender name, consistent with our MousePosition field).

    And ideally it should also work in perspective projection. (Though we could allow PR making it working only in orthogonal, documenting that in the long run it should also affect perspective.)

  4. In general, better check PositionToCameraPlane result and abort if any of them returns false. This may happen in perspective and only when camera has extremely wide field of view, like 180 or almost like it.

    So I understand this is not a concern in your case (orthographic), but in general I’d advise to check it, to be secure from this extreme edge-case.

Thank you very much!
It is working