[SOLVED] How translateLocal(), getLocalPosition(), and setLocalPosition() actually work

Hello,
I want to implement camera zoom for my project (https://playcanvas.com/editor/project/853115). The following script works perfectly for Sphere, but doesn’t work for camera, despite these two objects have the same parent in the hierarchy tree (none of these objects has additional scripts):

var Chase = pc.createScript('chase');

Chase.prototype.initialize = function() {
    this.app.mouse.on(pc.EVENT_MOUSEWHEEL, this.test, this);
};

Chase.prototype.test = function(event) {
    position = new pc.Vec3().copy(this.entity.getLocalPosition());
    translation = new pc.Vec3()
                    .copy(position)
                    .normalize()
                    .mulScalar(-event.wheelDelta);
    this.entity.translateLocal(translation);
};

Chase.prototype.update = function(dt) {
};

Thus my question is, how is this behavior even possible? Is there some difference between primitive entity and camera entity?

Thanks in advance

Hi there @SeniorRedstoneDev, and welcome!

Well, the camera moves when you scroll the mousewheel, right?
The issue here is the way you are using space coordinates.

Zooming in and out usually relies on moving the camera along it’s local Z axis. But in your project you are moving it along a normalized vector you are getting from the local position of the entity.

If you take a look in the editor, the sphere is at position -4,-4,0. So when you normalize that vector, you get something like -0.7,-0.7,0. You are moving the camera along that direction.

What you really want to do is move the camera along it’s local Z axis.

There are plenty example projects that provide this kind of behaviour, here’s one!
https://developer.playcanvas.com/en/tutorials/orbit-camera/

Hi @Francisco_Bozzo!
Thanks for reply, yes, I want to move camera by mouse wheel, but I am quite sure that camera have to move not along Z axis. As I wrote in the initial post, this script works for a sphere, so my formula must be correct. The question is only: what is the difference between camera and sphere?

Theres no difference between camera and sphere at the entity level, they are both entites and can be transformed in the same way.

The relevant difference in your case is their positioning in space because your script moves entities depending on their positioning in local space. So it’s only logic that they’ll behave differently if they have different local positions.

For the sphere it looks like it works ok, BUT IT DOES NOT WORK RIGHT FOR EVERY USE CASE. Just try moving the sphere near the camera in the editor and you’ll notice it won’t work any more. So it doesn’t work because the entity is a sphere… it works because of it’s position.

Try switching the position of the sphere and the camera and see what happens

No.

Obviously, yes.

It works correct, exactly as expected, because sphere coordinates were chosen randomly.
But it works in a different way when I set another rotation for the sphere. Therefore the translateLocal() method depends on the rotation of the object and I have to use global version (with applying the rotation of parent).

The final version, if someone needs:

var Zoom = pc.createScript('zoom');

Zoom.attributes.add('zoomSpeed', {type: 'number', default: 1});

Zoom.prototype.initialize = function() {
    this.app.mouse.on(pc.EVENT_MOUSEWHEEL, this.cameraZoom, this);
};

Zoom.prototype.cameraZoom = function(event) {
    position = new pc.Vec3().copy(this.entity.getLocalPosition());
    translation = new pc.Vec3()
                    .copy(position)
                    .normalize()
                    .mulScalar(-event.wheelDelta * this.zoomSpeed);
    this.entity.translate(this.entity.parent.getRotation().transformVector(translation));
};

Zoom.prototype.update = function(dt) {    
};
1 Like

Do you just need the camera to move along it’s local Z axis?

If so, this would work:

var Chase = pc.createScript('chase'); 
Chase.prototype.initialize = function() { 
  this.app.mouse.on(pc.EVENT_MOUSEWHEEL, this.test, this); 
}; 

Chase.prototype.test = function(event) { 
  this.entity.translateLocal(0, 0 -event.wheelDelta); 
};

Now, when I understand what “local” means in terms of translateLocal(), I think it is also correct. The problem is that getLocalPosition() and translateLocal() both has “local” in the name, but work in different coordinate systems for the same object (hard to understand the reason for this naming).
To be honest, I didn’t ask “how to implement”, however thank you for the different approach.

translateLocal will move the entity along on its local axis (ie whatever its forward, right and up directions are)

localPosition is its position relative to the parent along its local axis.

translateLocal is the same as adding to its localPosition

For example, if its localPosition was 0, 1, 0 and we call translateLocal(0,0, 10)

It would be the same as though if called set setLocalPosition (0, 1, 10)

Edit: This is wrong, localPosition is relative to the parent’s orientation, not it’s own

It is true, if the object is not rotated. In general most likely not. I sketched how it works according to my test, which you can find in the project linked above, script Test.js

translate

Ah yes, you are right. The localPosition is relative to the parent’s orientation, not it’s own. My bad.

For reference, the naming convention is the same for other engines and frameworks like Unity