- Home /
Taking average of multiple Vector3's
So I'm working with a depth-camera that works like kinect. (it's not kinect). and with Nuitrack behind it for skeleton tracking. However, The position it returns for the player is shaky. When standing perfectly still it returns numbers that can go up or down by up to like 10.
Example: User is standing as still as he can and the data returns position 100 the first frame, and the next frame it's 102, then it's 97 then its 100 again, then it's 106 etc. It returns these positions in the update and we use it to move a image with it. (so the user controls the image) But as you might expect this image is moving very shaky because of the inconsistent data. According to Nuitrack this is right, and the user itself needs to find a solution for this.
I tried lerping from one position to another, but this makes it feel less interactive, because once i'm on the point where the lerp is actually smooth, it has a huge delay. I also tried only using the new position data if it differs lets say 4 pixels from the previous position nuitrack gave me, this works a bit better but results in jumping of the image, even if I lerp it as well. Using this function:
foreach (User user in frame.Users)
{
if (Vector3.Distance(_lastPos, user.Proj.ToVector3()) >4f)
{
Vector3 final = ((_lastPos + user.Proj.ToVector3()) /2);
userData.Add(new UserData(user.ID, user.Real.ToVector3(), final));
_lastPos = user.Proj.ToVector3();
}
else
{
userData.Add(new UserData(user.ID, user.Real.ToVector3(), _lastPos));
}
And the Lerp function:
float _userX = user.ProjPosition.x * (_cameraPos.x *2)- _cameraPos.x;
Vector3 _newPos = new Vector3(_userX, _basketPos.y, _basketPos.z);
_basketPrefab.transform.position = Vector3.Lerp(_basketPrefab.transform.position, _newPos, Time.deltaTime * 30f);
Not quite sure I understand the situation but as a general approach to jumpiness you might want to consider thinking of the raw data as just a "target position" and moving your object(s) or whatever towards that target position by a small amount every frame. That way you can completely control the smoothness of movement by tweaking the size of that "small amount".
Answer by Bunny83 · Feb 26, 2019 at 01:07 PM
This is one of the cases where a "non linear lerping" (which is a contradiction in its own ^^) will help. The idea is if the difference is small we want a very slow transition and maybe even a threshold to ignore changes completely. Once the change goes over a certain magnitude we want to speed up the movement. At greater changes we want the changes to be almost instant. One way would be this:
// set the threshold in the inspector
public float threshold = 10;
// controls how fast the speed increases
public float scale = 0.1f;
public float pow = 2f;
// does represent the current position of your object;
Vector3 currentPosition;
// current input position
Vector3 input;
void UpdatePosition()
{
Vector3 dif = input - currentPosition;
float length = dif.magnitude;
float newLength = Mathf.Max(0, length - threshold);
if (newLength < 0.0001f)
return;
dif *= newLength / length;
dif *= scale;
dif *= Mathf.Pow(newLength * scale, pow);
dif = Vector3.ClampMagnitude(dif, length);
currentPosition += dif;
}
Note that theshold always need to be positive. The scale and pow control how fast you home in into the given position. The greater the scale / pow the faster it will be. You can control the non linearity by increasing pow and decreasing scale or the other way round.
Scale probably should be smaller than 1 and pow should be greater than 1 (note that pow is the actual power -1. So a pow of 2 results in a power of 3. A pow of 0 results in a power of 1)
Though keep in mind this is untested and is just based on theory. It would need to be tested with actual data. Since all values are exposed you can tweak them in playmode.
I don't really understand what exactly you mean. I tried this but couldn't get it to work. Could you explain it a bit more in depth if possible? And/Or in another way?
Well, I'm not sure how i should explain it more detailed. I can run through it again. Note i just made a few adjustments like adding a Clamp$$anonymous$$agnitude at the end, just to ensure we do not overshoot the actual displacement. Also the scale should be go into the Pow as well.
The code essentially does this:
calculate the difference between the new input and the current position. This is essentially the vector that brings us from our current position to the new input position. If you add this vector to out current position unchanged it would be the same as directly setting the currentposition to the input value.
The first step we do is to subract a threshold from that vector length. I've set a threshold of "10". So if the length of the dif vector is smaller than 10, it will have no effect at all. If we get past that threshold, for example length 12, we actually get a vector will length 2 (12-10) towards our desired target. This vector you get after line 19.
Next we scale the vector down by a certain factor to get a vector that is relatively small.
Next we take the length of the new vector to a set power. This has the effect that a small vector (smaller than 1) gets even smaller and larger vectors gets larger more quicker. If The pow is 2 (the actual power is 3) and the length of the inco$$anonymous$$g vector is 1.2 we get a vector of length 1.728 (==1.2^3). If the inco$$anonymous$$g vector is 1.5 we get 3.375 and if it's 2 we get 8. So the larger the actual change is, the greater the vector gets. Since we used a power of 3 here it grows very fast. The scale can actually shift that second threshold / border where it accelerates.
Those values has be to fine tuned depending on the value ranges you actually work with. We don't know what the operation range is (what's the $$anonymous$$imum what's the maximum range, also what's the average magnitude of change that the user wants to work with?)
If you say you want to measure changes in the range of 5 upwards but you have a jitter of 10 this isn't going to work since the accuracy of the sensor is too bad.
There isn't a one fits it all solution. input filtering highly depends on the operational range and how much the error / jitter is and how responsive the system should be. If you have a high error / jitter you can not get rid of it if you want high responsiveness. You would always have a trade off between responsiveness and smoothness.
Sometimes it might help to just have an "adaptive threshold". So if the values bounce up and down a lot you just increase the threshold and number of interpolation samples so the jitter completely dissapears. If an actual move is made, that means the average delta over the last few values all are going into one direction you would decrease the threshold and lower the number of interpolation samples (maybe even down to 1, so you actually use the input value). As soon as the movement stopped and your delta values start jumping around again you increase the threshold again.
Thanks a lot, much more clear :). I'm going to try it a second time!