AR, Object jiggle. Trying to interpolate

Hi,

I’m experimenting with this package (GitHub - playcanvas/playcanvas-ar: Fast and Easy Augmented Reality for the Web). I’m trying to make the tracking a little less nervous and jittery by interpolating the position the tracked object accepts from ARToolkit. @will you mentioned that as a feasable solution to a similar issue on github.

Did I understand it right if an event called getMarker is received from the ARToolkit whenever a marker is read. Which should be every frame unless the Track alternate frame option is enabled, in case it’s every other frame.

Then my take would be to try and store the position and rotation received in some targetRotation/targetRotation and then use Vector3.lerp to move the actual transform of the entity towards the target over time (let’s say half a second of similar).

First question: Would that even remedy what I’m referring to as the wobbly movement in my screengrab?

Second question: I’ve tried for hours trying to implement the simplest lerp algorithms I’ve found on various places around here, but just can’t get my head around it. I’d be happy to share code, or if someone has done something along this line and could chirp in and help me out, I’d be very thankful.

What I’ve tried basically goes along the lines of this:

Instead of updating position directly like in the original:

entity.setPosition(self.finalMatrix.getTranslation());
entity.setEulerAngles(self.finalMatrix.getEulerAngles());

I’ve tried variations of this:

//entity.setPosition(self.finalMatrix.getTranslation());
//entity.setEulerAngles(self.finalMatrix.getEulerAngles());
                
// Add Lerping of object towards target position and rotation. 
self.targetPosition = self.finalMatrix.getTranslation();
self.targetRotation = self.finalMatrix.getEulerAngles();
                
self.lerpAlpha = Math.min(self.lerpedTime/self.LERP_SPEED,1);
                
self.lerpedPosition.lerp(self.startPosition, self.targetPosition, self.lerpedTime);
self.lerpedRotation.lerp(self.startRotation, self.targetRotation, self.lerpedTime);
                
entity.setPosition(self.lerpedPosition);
entity.setEulerAngles(self.lerpedPosition);
                
// When new tracking data appears, also reset startPosition and lerpedTime
//self.lerpedTime = 0;
//self.startPosition = entity.getPosition();
//self.startRotation = entity.getEulerAngles();

btw, I increase lerpedTime in Update() since it’s the only one that has access to dt:

        this.lerpedTime += dt;

But I’m confused how and when to update my alpha and when to reset startPosition and currentLerpTime. (I guess on every getMarker event?)

Well. I’m confused. :slight_smile:

Hi,

Generally, you don’t need to convert a quaternion to euler angles only to do an interpolation on them and afterwards converting back to quats. It will give you an issue with gimbal lock. You should be fine with lerping a quaternion directly.

const lerpAmount = 0.1; // we can affect how quickly the lerp would reach the target
const current = entity.getRotation();
const target = new pc.Quat().setFromMat4(self.finalMatrix);
const inter = new pc.Quat().slerp(current, target, 1.0 - Math.pow(lerpAmount, dt));
entity.setRotation(inter);
// homework: create quats only once and re-use

Alpha should be gradually increasing from 0 to 1, where 0 would mean the rotation will equal to the current and 1 would be the final target rotation.

You can make alpha to be a fixed value, for example 0.1. That would mean 10% towards the target on the first frame, then 10% of remaining 90% (not 100%) on the second frame, etc. Thus we need a Math.pow(). If you always keep changing target rotation, it would kind of keep running towards it, until the target stops changing and after a few frames the lerp would reach it.

@slimbuck once gave a nice link, if you are interested on the subject:
http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/

1 Like

Thank you for that very insightful remark! I learned a lot!

1 Like

Please let me know the final version. I hope You can make it