zoomToMouseLocation issue after camera.setTarget()

Sometimes we need to manually focus on an element;
and after that,zoomToMouseLocation has no effect

After looking at the source code, I think it is necessary to update the target of the camera when using this feature

What do you think?

cc @PolygonalSun, but please be patient as most of the team are currently on vacation.

I will do some tests locally first, and I will post any new progress
But vacation is the first thing, and have a good vacation :wink:

It seems that the command missing

It does work for me locally.

However, I can see that “build:declaration” is defined in all package.json files but for the main one… Try to add "build:declaration": "build-tools -c pud --config ./config.json" in the “scripts” section of the package.json file located in the main directory and see if that fixes it.

I calculated the real camera target that fits the current mode when the mouse rolls
It only needs to be updated when the mouse wheel is rolling

It has been verified that the current bug can be fixed

1 Like

Hey, so I’m looking at this PR and the issue but I’m not sure that I follow what the bug is here.

From what I’m understanding here, the current behavior of zoomToMouseLocation is to take a point on a given _hitPlane (perpendicular to the camera direction, with a center at the camera’s target), set the target to the point of intersection, and change the radius.

In this PR, it looks like if the targetSetManually is set by the user, the target will be calculated and set based off of the XZ plane by taking the point of intersection, adding the ray’s scaled direction to it. If this variable is not true, it will default to the original behavior. Is this accurate?

Normally, the original target of the camera is (0,0,0).
When zoomtomouselocation is enabled,
the target moves toward the intersection and the camera radius is scaled by sliding the mouse

However, when the user forces the target to be set to a certain point,
such as a point that is very close to the camera’s position,
it will not be able to move at this time because it is too close,
which is the problem with this bug

So in order to ensure that zoomtomouselocation mode still works,
you need to recalculate the target (the direction of sight and the focus of the ground).

Also, we need to update the target first and then update the hit plane,
and the latest commit has adjusted this order

@sebavan @PolygonalSun

In order to improve the performance of the code, I try to merge some code and use some common variables;
But there was a very strange problem:

Use “add & scale”

    //Reset the camera's target (the direction of sight and the focus of the ground).
    private _updateCameraTarget() {
        const camera = this.camera;
        const direction = TmpVectors.Vector3[6];
        camera.target.subtractToRef(camera.position, direction);
        this._ray = new Ray(camera.position, direction.normalize(), Number.MAX_SAFE_INTEGER);
        this._hitPlane = Plane.FromPositionAndNormal(Vector3.Zero(), camera.upVector);
        const distance = this._getIntersectionDistance(this._ray, this._hitPlane, false);

        camera.setTarget(this._ray.origin.add(this._ray.direction.scale(distance)));
        // camera.setTarget(this._ray.origin.addInPlace(this._ray.direction.scaleInPlace(distance)));
    }

After recalculating the target, the effect is as expected


Use “addInPlace & scaleInPlace”

    //Reset the camera's target (the direction of sight and the focus of the ground).
    private _updateCameraTarget() {
        const camera = this.camera;
        const direction = TmpVectors.Vector3[6];
        camera.target.subtractToRef(camera.position, direction);
        this._ray = new Ray(camera.position, direction.normalize(), Number.MAX_SAFE_INTEGER);
        this._hitPlane = Plane.FromPositionAndNormal(Vector3.Zero(), camera.upVector);
        const distance = this._getIntersectionDistance(this._ray, this._hitPlane, false);

        // camera.setTarget(this._ray.origin.add(this._ray.direction.scale(distance)));
        camera.setTarget(this._ray.origin.addInPlace(this._ray.direction.scaleInPlace(distance)));
    }


This is a strange result, but i’m not clear what went wrong

I don’t think this problem has anything to do with the _ray variable,

because even after I changed it to a local variable, this problem still occurs

    //Reset the camera's target (the direction of sight and the focus of the ground).
    private _updateCameraTarget() {
        const camera = this.camera;
        const direction = TmpVectors.Vector3[6];
        camera.target.subtractToRef(camera.position, direction);
        // this._ray = new Ray(camera.position, direction.normalize(), Number.MAX_SAFE_INTEGER);
        // this._hitPlane = Plane.FromPositionAndNormal(Vector3.Zero(), camera.upVector);
        // const distance = this._getIntersectionDistance(this._ray, this._hitPlane, false);
        var _ray = new Ray(camera.position, direction.normalize(), Number.MAX_SAFE_INTEGER);
        var _hitPlane = Plane.FromPositionAndNormal(Vector3.Zero(), camera.upVector);
        const distance = this._getIntersectionDistance(_ray, _hitPlane, false);
        camera.setTarget(_ray.origin.addInPlace(_ray.direction.scaleInPlace(distance)));
    }

And when I look at the code,
every time we need to use _ray,
we don’t use it directly, just reassign it,
so ***InPlace here doesn’t have any effect to other places

A fifth parameter(setManually) was added to setTarget to fix this bug

    /**
     * Defines the target the camera should look at.
     * This will automatically adapt alpha beta and radius to fit within the new target.
     * Please note that setting a target as a mesh will disable panning.
     * @param target Defines the new target as a Vector or a transform node
     * @param toBoundingCenter In case of a mesh target, defines whether to target the mesh position or its bounding information center
     * @param allowSamePosition If false, prevents reapplying the new computed position if it is identical to the current one (optim)
     * @param cloneAlphaBetaRadius If true, replicate the current setup (alpha, beta, radius) on the new target
     * @param setManually Defines the target is Automatic calculation through the program or Setting by the user
     */
    button.addEventListener('click',()=>{
        var t = new BABYLON.Vector3(3, 3, 3)
        var cameraPos = t.add(t.clone().normalize().scale(0.8))
        camera.setPosition(cameraPos)
        camera.setTarget(t,false,false,false,true)
    })

@ecojust, why do we need the new parameter ?

setTarget could call for instance _setTarget which has the parameter and internally we only use this one as well so the user do not have to deal with this parameter which should be hidden from them.

Also lets wait on @PolygonalSun review to be sure it is the correct solution.

Firstly,the user modifies the camera target point using setTarget, but this causes the zoomtomouselocation to fail

We need to reset the camera target point the next time the user scrolls the mouse, so that zoomtomouselocation returns to normal

We only need to help the user update this value once

So we need a marker to remember the user’s action and reset the camera target value when the mouse rolls

So, naturally, I came up with the idea of adding this marker to a function called setTarget

If you think it would be better to use a method that does not modify settarget parameters

So when we call it, it’s going to look like this

    button.addEventListener('click',()=>{
        var t = new BABYLON.Vector3(3, 3, 3)
        var cameraPos = t.add(t.clone().normalize().scale(0.8))
        camera.targetSetManually = true
        camera.setPosition(cameraPos)
        camera.setTarget(t)
    })

    //If the user manually set the camera target before
    //in order to ensure the normal use of this function
    //you need to automatically calculate the correct camera in this mode.
    if (camera.targetSetManually && camera.inertialRadiusOffset) {
        this._updateCameraTarget();
    }

    ......

    //Reset the camera's target (the direction of sight and the focus of the ground).
    private _updateCameraTarget() {
        const camera = this.camera;
        const direction = TmpVectors.Vector3[6];
        camera.target.subtractToRef(camera.position, direction);
        this._ray = new Ray(camera.position, direction.normalize(), Number.MAX_SAFE_INTEGER);
        this._hitPlane = Plane.FromPositionAndNormal(Vector3.Zero(), camera.upVector);
        const distance = this._getIntersectionDistance(this._ray, this._hitPlane, false);
        camera.setTarget(this._ray.origin.add(this._ray.direction.scale(distance)));
        camera.targetSetManually = false;
    }

@sebavan @PolygonalSun
Or do you have any good suggestions on where to put this mark

@PolygonalSun is currently looking into it :slight_smile:

1 Like