How to convert lerp to cubic easing in? - c#

I need to convert the following code from using lerp to using cubic easing in, but I don't know what to do with the returned float value from the cubic easing in function, because I'm using Vector3 instead of floats. Can someone please give me a hint?
if (Vector3.Distance(activeTween.Target.position, activeTween.EndPos) > 0.1f)
{
float fraction = (Time.time - activeTween.StartTime) / activeTween.Duration;
activeTween.Target.position = Vector3.Lerp(activeTween.StartPos, activeTween.EndPos, fraction);
}

You should probably just use it in place of your fraction in the Vector3.Lerp.
Lerp is just the linear interpolation of vectors, i.e. 0.3 means 30% from one and 70% from the other. If we want non linear interpolation we can just apply some arbitrary function to the input value. For example, that 0.3 may be transformed to 0.027, and that can then be used as the input to Lerp to get 2.7% / 97.3% blend instead.

You need a cubic function that is 0 at the start and 1 and the end.
I would try something like:
public float EaseIn(float t)
{
return t * t * t;
}
if (Vector3.Distance(activeTween.Target.position, activeTween.EndPos) > 0.1f)
{
float fraction = (Time.time - activeTween.StartTime) / activeTween.Duration;
activeTween.Target.position = Vector3.Lerp(activeTween.StartPos, activeTween.EndPos, EaseIn(fraction));
}
Assuming that fraction was already going from 0 to 1.

Related

How do I get the original number to calculate the sin and cos for a point on a circle?

I got this to move an object in a circle:
currentAngle += Time.deltaTime * angularSpeed;
offset = new Vector3(Mathf.Sin(currentAngle), 0, Mathf.Cos(currentAngle)) * circleRad;
transform.position = fixedPoint + offset;
Is there a way to get the original currentAngle (used to calculate a point) from a position on this circle, like backtrack the function?
The atan2 function is what you are looking for.
In C# it is available as Math.Atan2, which takes double arguments. In addition, Unity (which you are probably using given the code sample in your question) has Mathf.Atan2 which takes float arguments.

Lerp alpha based on distance between 2 objects

So I am trying to increase an image alpha channel based on the fact that an object is getting closer and closer to the player. I am using Vector3.Distance()
to get the distance from the player to the object but I don't know how should I convert the distance so that the value of color.a will get bigger and bigger as the distance get's smaller and smaller.
Please point me in the right direction;
How can I make a number bigger based on the fact that another number is getting smaller?
See this post that explains how to lerp a color based on distance between two GameObjects. The only difference is that you want to lerp the alpha instead so everything written on that post should still be relevant to this. Just few modifications need to be made.
You just need to use Mathf.Lerp instead of Color.Lerp. Also, you need to enable fade mode on the material. You can do that from the Editor or script. The code below is a modified code from the linked answer that should accomplish what you are doing. It also enables fade mode from code in the Start function.
public GameObject obj1;
public GameObject obj2;
const float MAX_DISTANCE = 200;
Renderer mRenderer;
void Start()
{
mRenderer = GetComponent<Renderer>();
//ENABLE FADE Mode on the material if not done already
mRenderer.material.SetFloat("_Mode", 2);
mRenderer.material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
mRenderer.material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
mRenderer.material.SetInt("_ZWrite", 0);
mRenderer.material.DisableKeyword("_ALPHATEST_ON");
mRenderer.material.EnableKeyword("_ALPHABLEND_ON");
mRenderer.material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
mRenderer.material.renderQueue = 3000;
}
void Update()
{
//Get distance between those two Objects
float distanceApart = getSqrDistance(obj1.transform.position, obj2.transform.position);
UnityEngine.Debug.Log(getSqrDistance(obj1.transform.position, obj2.transform.position));
//Convert 0 and 200 distance range to 0f and 1f range
float lerp = mapValue(distanceApart, 0, MAX_DISTANCE, 0f, 1f);
//Lerp Alpha between near and far color
Color lerpColor = mRenderer.material.color;
lerpColor.a = Mathf.Lerp(1, 0, lerp);
mRenderer.material.color = lerpColor;
}
public float getSqrDistance(Vector3 v1, Vector3 v2)
{
return (v1 - v2).sqrMagnitude;
}
float mapValue(float mainValue, float inValueMin, float inValueMax, float outValueMin, float outValueMax)
{
return (mainValue - inValueMin) * (outValueMax - outValueMin) / (inValueMax - inValueMin) + outValueMin;
}
I don't know how you want the effect to look, but it's basically a math question.
Something like:
color.a = 1.0 / distance
should get you started. Basically, the further from 1 distance gets (increasing), the closer to 0 color.a gets (decreasing). The opposite is thus true if distance decreases (color.a then increases).
You have to deal with values for distance getting inferior to 1 (if applicable), as it won't increase color.a anymore.
You also have to deal with color.a max possible value: is it 1.0 or 255 (or something else)? Replace the 1.0 in the formula with this max value. You may have to multiply distance by an arbitrary value so the effect isn't too fast or too slow.
Sounds like you want a function (in the mathematical sense) f(x) that maps an input (distance) value in the domain [0, infinity) to the output (alpha) range [1, 0]. One simple such function is 1/(1+x) (click the link to see an interactive graph).
You can use the interactive graph and online math resources to play with the equation to find one that looks good to you. Once you have that figured out, implementing it in code should be easy!

Leap Motion Get Finger Bending (C#)

Hello I tried a lot diffrent ways to get bending angle in Leap Motion. But I couldn't get true values. I used this method for reading. Thanks in advance.
Bone bone1 = finger.Bone(Bone.BoneType.TYPE_INTERMEDIATE);
Bone bone2 = finger.Bone(Bone.BoneType.TYPE_PROXIMAL);
double angle = 180 - ((bone1.Direction.AngleTo(bone2.Direction) / Math.PI) * 180) * 2;
In this example I'll use array accessors as a quicker way of accessing bones from Finger objects.
For reference, bone indices are: 0 = metacarpal, 1 = proximal, 2 = intermediate, 3 = distal. You can validate this by looking at the definition of BoneType.
(Careful, the thumb has one fewer bone than the other fingers.)
Vector3 bone0Dir = finger.bones[0].Direction.ToVector3();
Vector3 bone1Dir = finger.bones[1].Direction.ToVector3();
float angle = Vector3.Angle(bone0Dir, bone1Dir);
This example retrieves the angle in degrees between the metacarpal bone and the proximal bone of the finger object.
Note that Vector3.Angle returns the unsigned angle between the two bones; if you desire a signed angle, you can use the SignedAngle function instead. You'll need to pass it a reference axis; Vector3.Cross(hand.PalmarAxis(), hand.DistalAxis()) would be suitable for this.
EDIT: Ah, apologies, the answer is a bit different if you're outside of the Unity engine. In that case, Leap.Vector.AngleTo is sufficient, but there's a simpler way to convert radians to degrees:
Vector bone0Dir = finger.bones[0].Direction;
Vector bone1Dir = finger.bones[1].Direction;
float angle = bone0Dir.AngleTo(bone1Dir) * Vector.RAD_TO_DEG;
Again, this will return the unsigned angle, but fingers don't usually bend backwards, so this should be sufficient for your use-case. You can also use Math.Asin((bone0Dir.Cross(bone1Dir).Magnitude)) * RAD_TO_DEG to get a (right-handed) signed angle.

How to "round" a 2D Vector to nearest 15 degrees

I'm working on a simple game and I'm trying to simplify part of the 2D collision reaction in the game. When certain objects hit walls, I'm calculating a collision normal (collisionPoint - objectCenter) and reflecting based on that normal. I'm interested in rounding that normal vector to its nearest 15° but I'm not sure of a good way to go about that.
My current thought is doing something like this
float angle = atan2(normal.Y, normal.X) * Rad2Deg;
float newAngle = ((int)(angle + 7.5f) / 15) * 15.0f * Deg2Rad;
vector2 newNormal = vector2(cos(newAngle), sin(newAngle));
Is this a reasonable way to do it? Is there a better way?
Try this:
float roundAngle = 15 * Deg2Rad;
float angle = (float)Math.Atan2(normal.Y, normal.X);
Vector2 newNormal;
if (angle % roundAngle != 0)
{
float newAngle = (float)Math.Round(angle / roundAngle) * roundAngle;
newNormal = new Vector2((float)Math.Cos(newAngle), (float)Math.Sin(newAngle));
}
else
{
newNormal = Vector2.Normalize(normal);
}
You don't need to add 7.5, take this example:
// 4 degrees should round to 0
(4 + 7.5) / 15 == 11.5 / 15 == 0.77
// When this gets rounded up to 1 and multiplied by 15 again, it becomes 15 degrees.
// Don't add 7.5, and you get this:
4 / 15 == 0.27
// When rounded, it becomes 0 and, as such the correct answer
// Now how about a negative number; -12
-12 / 15 == -0.8
// Again, when rounded we get the correct number
actually this is more correct if you want the nearest 15 degree angle :
do this:
newangle% = INT(((angle%+7.5)/15)*15)
INT ALWAYS rounds DOWN by default this should properly give you the nearest angle in any case that is positive or negative have fun!!
and add the part where you use degree to rad and rad to degree if needed INSIDE the parens (like right next to angle% if that angle is not given in degrees then use some sort of rad2deg multiplier inside there
this is more like how you would do this in basic, with some modification It will work in c code or such, well good luck!!

What's wrong with this XNA RotateVector2 function?

I know this is probably a very simple question, but I can't seem to figure it out. First of all, I want to specify that I did look over Google and SO for half an hour or so without finding the answer to my question(yes, I am serious).
Basically, I want to rotate a Vector2 around a point(which, in my case, is always the (0, 0) vector). So, I tried to make a function to do it with the parameters being the point to rotate and the angle(in degrees) to rotate by.
Here's a quick drawing showing what I'm trying to achieve:
I want to take V1(red vector), rotate it by an angle A(blue), to obtain a new vector (V2, green). In this example I used one of the simplest case: V1 on the axis, and a 90 degree angle, but I want the function to handle more "complicated" cases too.
So here's my function:
public static Vector2 RotateVector2(Vector2 point, float degrees)
{
return Vector2.Transform(point,
Matrix.CreateRotationZ(MathHelper.ToRadians(degrees)));
}
So, what am I doing wrong? When I run the code and call this function with the (0, -1) vector and a 90 degrees angle, I get the vector (1, 4.371139E-08) ...
Also, what if I want to accept a point to rotate around as a parameter too? So that the rotation doesn't always happen around (0, 0)...
Chris Schmich's answer regarding floating point precision and using radians is correct. I suggest an alternate implementation for RotateVector2 and answer the second part of your question.
Building a 4x4 rotation matrix to rotate a vector will cause a lot of unnecessary operations. The matrix transform is actually doing the following but using a lot of redundant math:
public static Vector2 RotateVector2(Vector2 point, float radians)
{
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);
return new Vector2(
point.X * cosRadians - point.Y * sinRadians,
point.X * sinRadians + point.Y * cosRadians);
}
If you want to rotate around an arbitrary point, you first need to translate your space so that the point to be rotated around is the origin, do the rotation and then reverse the translation.
public static Vector2 RotateVector2(Vector2 point, float radians, Vector2 pivot)
{
float cosRadians = (float)Math.Cos(radians);
float sinRadians = (float)Math.Sin(radians);
Vector2 translatedPoint = new Vector2();
translatedPoint.X = point.X - pivot.X;
translatedPoint.Y = point.Y - pivot.Y;
Vector2 rotatedPoint = new Vector2();
rotatedPoint.X = translatedPoint.X * cosRadians - translatedPoint.Y * sinRadians + pivot.X;
rotatedPoint.Y = translatedPoint.X * sinRadians + translatedPoint.Y * cosRadians + pivot.Y;
return rotatedPoint;
}
Note that the vector arithmetic has been inlined for maximum speed.
So, what am I doing wrong? When I run the code and call this function with the (0, -1) vector and a 90 degrees angle, I get the vector (1, 4.371139E-08) ...
Your code is correct, this is just a floating point representation issue. 4.371139E-08 is essentially zero (it's 0.0000000431139), but the transformation did not produce a value that was exactly zero. This is a common problem with floating point that you should be aware of. This SO answer has some additional good points about floating point.
Also, if possible, you should stick with radians instead of using degrees. This is likely introducing more error into your computations.

Categories