Hi all, I’m using the zappar API to do some AR stuff.
For now I’m trying to move some objects through waypoints using the Z axis, but when I use the LookAt method it rotates with the camera, I don’t understand why. If anyone has any clues as to what might be going on, it would help me a lot.
You can see the issue in the sample project I’m using HERE
I’ll also leave the code here to see if I’m doing something wrong:
var MoveObjectWaypoints = pc.createScript('moveObjectWaypoints');
MoveObjectWaypoints.attributes.add('waypoints', {
type: 'entity',
title: "points",
array: true
});
MoveObjectWaypoints.attributes.add('speed',{
type: 'number',
default: 0.5
});
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
function GetWaypointDist(a,b)
{
var dist = a.sub(b);
return dist.normalize();
}
function GetNextPoint(currentPoint)
{
var rand = getRandomInt(currentPoint.script.waypointScript.connections.length);
return currentPoint.script.waypointScript.connections[rand];
}
// initialize code called once per entity
MoveObjectWaypoints.prototype.initialize = function() {
this.nextWaypoint = GetNextPoint(this.waypoints[0]);
console.log(this.nextWaypoint);
this.nextPosition = GetWaypointDist(this.entity.getPosition(), this.nextWaypoint.getPosition());
this.entity.lookAtReverse(this.nextWaypoint.getPosition());
};
pc.GraphNode.prototype.lookAtReverse = function(target) {
this.lookAt(target);
this.rotateLocal(0, 180, 0);
};
// update code called every frame
MoveObjectWaypoints.prototype.update = function(dt)
{
if(this.nextWaypoint != null)
{
var entityPos2D = new pc.Vec2(this.entity.getPosition().x, this.entity.getPosition().z);
var targetPos2D = new pc.Vec2(this.nextWaypoint.getPosition().x, this.nextWaypoint.getPosition().z);
console.log(entityPos2D.distance(targetPos2D));
if(entityPos2D.distance(targetPos2D) < 0.05)
{
this.nextWaypoint = GetNextPoint(this.nextWaypoint);
console.log(this.nextWaypoint);
this.nextPosition = GetWaypointDist(this.entity.getPosition(), this.nextWaypoint.getPosition());
}
this.entity.lookAtReverse(this.nextWaypoint.getPosition());
this.entity.translateLocal(0,0, this.speed * dt);
}
};
Most likely this isn’t related to Zappar/AR, just lookAt() not finding the right angle (gimbal lock?). I can’t debug this visually, the object seems to be moving not only in one direction but two?
By the way this example project may be of help, it uses lookAt and passes a second value for the up axis direction to allow for rolling and gimbal lock prevention:
Trying to move an object from point A to point B
used the example to try and see if its something with the example code or with zappar, but its with zappar indeed
I copy the classes from the example, and put on a Cube with a pointing direction, when i set with zappar, the cube just float around the camera, not following the points. If I change in the class where says “getPosition” or "setPosition to “getLocalPosition”/“setLocalPosition”, the cube moves in the area, but looking in a wrong direction
Without zappar, the cube follow as should be, if I change to getLocalPostion/setLocalPosition, the cube just look at the oposite direction of the point.
I set four different scenes on this project, two with zappar, with “getPosition” and “getLocalPosition”, and without zappar with “getPosition” and “getLocalPosition” test to see what happens
Sorry if it’s not possible to do a double post, but I created 2 new scene as examples using only LookAt
One with zappar, and other without
Without zappar works as should be, the only thing weird is that i need to invert position on lookat at X and Z positions, to make the object using his Forward
WITH zappar the thing is different… even looking in a different direction, when I move the camera, the object move together the camera…
this is really weird…
Lol @yaustar, I’m a Zappar client as well. They don’t answer these questions, and instead tell us to reach out to the devs of the framework we’re using. So now poor @femoreti is probably running in circles
But now I finally managed to solve this problem, not the way I would like, but it worked.
Basically I decided to do an math to find the angle between two points and based on that angle I apply the rotation at point A to make the object look at point B, that way it stopped rotating along with the camera when using Zappar.
I’ll leave the code here for those who want to know more:
function GetNextPointAngle(source,target)
{
const angle = (anchor, point) => Math.atan2(anchor.y - point.y, anchor.x - point.x) * 180 / Math.PI + 180;
var a = {
x: target.x,
y: target.z
};
var p = {
x: source.x,
y: source.z
};
//console.log(target, source);
//console.log(a,p);
angle(a, p); // 225
// angle in degrees, from example, same data
angleDeg = Math.atan2(a.y - p.y, a.x - p.x) * 180 / Math.PI; // 45
return angleDeg;
}
function LookToTarget(source, target)
{
var entityPos = source.getLocalPosition().clone();
var targetPos = target.getLocalPosition().clone();
var angleToRotate = GetNextPointAngle(entityPos, targetPos);
//console.log(angleToRotate);
if(angleToRotate < 0)
{
angleToRotate = -((angleToRotate + 360)) + 90;
}
else
{
angleToRotate = 90 - angleToRotate;
}
//console.log(angleToRotate);
source.setLocalEulerAngles(0,angleToRotate,0);
}
And the link to the project with the code working ~here~
It would be interesting to find out how to make it work using the native LookAt along with Zappar api, but as I had a deadline to finish it, I managed to do it this way.
See below for Office Hours video on this. Jump to 11:59 for the answer
What is happening is that Zappar is orientating the Instant Tracker entity to match the orientation of the thing it is tracking.
When that happens, the Char entity local up vector no longer matches the world up vector so when lookAt is used with just a pointer vector to look at, it looks like it is rotated on the local Z axis because the lookAt function uses the world up vector by default to rotate the Char entity with.
To fix this, we can pass the Instant Tracker’s up vector to the lookAt function to rotate the Char entity with and orientate it correctly to match the Instant Tracker’s orientation.