- Home /
What does mathf.repeat actually do?
I was reading the unity 3d documentation and there is a math function called mathf.repeat.
It says it loops the value t so its value is between 0 and the length you enter...
What could this be used for and what exactly does it mean to "loop the value t"?
Answer by aldonaletto · Jun 21, 2012 at 12:50 PM
This function returns the remainder of the division firstArgument/secondArgument. It's like the modulo (%) operator, but works for float numbers as well. Actually, the modulo operator also works with floats in Unity - these two alternatives print the same result:
print(Mathf.Repeat(2.45, 2.0).ToString("F2")); // prints 0.45
print((2.45 % 2.0).ToString("F2")); // also prints 0.45
Two of the most frequent uses of Mathf.Repeat or % in Unity are:
1- Keep angles in the 0..360 range for eulerAngles or localEulerAngles (an angle 375 becomes 15, which is the same thing):
transform.eulerAngles = Vector3(0, curAngle % 360, 0);
2- Keep texture offset inside the 0..1 range (shaders may render ugly artifacts when big values are passed as texture offsets):
renderer.material.mainTextureOffset = Vector2 (Time.time % 1, 0);
The %
operator cannot handle negative input values correctly, it will keep the sign.
Woops, of course, I just realized the (int)
cast has the same problem with negative values.
Note, as with the approach suggested by me, you can fix the problem of negative values with the %
operator by either using (curAngle % 360 + 360) % 360
(which is a bit more expensive, but still faster than $$anonymous$$athf.Repeat), or by using curAngle = curAngle % 360; if (curAngle<0) curAngle += 360;
(which is fastest).
I ran some benchmarks on my Windows Desktop in the Editor in C# (so I can't tell how these will behave on different platforms, but chances are it's similar), and using your idea of the float-`%` operator is actually the fastest variant:
(sorted by time factor, fastest first. used 1e8 samples, compensated for loop overhead)
val%mod x1.0 (NOTE: incorrect for val<0)
val-((int)(val/mod))*mod x1.17 (NOTE: incorrect for val<0)
val%mod; if(result<0) result+=mod; x1.19
val-((int)(val/mod))*mod; if(result<0) result+=mod; x1.55
(val%mod+mod)%mod x1.76
val-$$anonymous$$athf.Floor(val/mod)*mod x4.4 (!)
$$anonymous$$athf.Repeat(val,mod) x4.5 (!)
Answer by Wolfram · Jun 21, 2012 at 12:49 PM
Simple example is an angle: If you want to make sure your angle is always between 0..360 (because your algorithm required it), but your input value can be anything (because the user can input anything), you can use it. For example, -100 and 260 and 620 all represent the same angle, which is 260. This will map your arbitrary value back to the 0..360 interval:
actualAngle=Mathf.Repeat(inputAngle,360);
Note that this is a nice convenience function, but if you need to evaluate it several thousand times per frame for some reason, you will be much faster implementing it by hand:
actualAngle=((inputAngle/360f)-(int)(inputAngle/360f))*360f;
EDIT: even more optimized, thanks @Bunny83:
actualAngle=inputAngle-((int)(inputAngle/360f))*360f;
EDIT2: somehow I missed that (int)
will not handle negative values correctly. So when using that optimization, you'd need to catch that case (which will still be much faster than Mathf.Repeat() or using Mathf.Floor()):
actualAngle=inputAngle-((int)(inputAngle/360f))*360f;
if(actualAngle<0)
actualAngle+=360f;
You're right ;) It's implemented like this:
public static float Repeat(float t, float length)
{
return t - $$anonymous$$athf.Floor(t / length) * length;
}
The first "/360" can be removed when you pull the first term out of your outer bracket ;)
actualAngle = inputAngle - ((int)(inputAngle/360f))*360f;
What should be $$anonymous$$athf.Repeat(-0.005, 30)? Is this same as -0.005 % 30 but keeping the value above 0. so i would expect the result of $$anonymous$$athf.Repeat(-0.005, 30) = 0. What do you think?
Well, yes and no ;-) It is the "same as -0.005 % 30 but keeping the value above 0", i.e., -0.005 % 30 = -0.005 due to the inability to handle negative values "correctly". So "keeping the value above 0" means +30, which is 29.995, which is the result $$anonymous$$athf.Repeat will give you. What you describe is $$anonymous$$athf.Clamp, which maps everything below 0 to 0 (and above 30 to 30). Repeat will map everything into the interval, keeping the value itself intact. This is true for both >30 and <0. If you need to clamp negative values, but "repeat" values >30, you'd have to combine this yourself, for example using: if(val<0) return 0; else return val%length;
Thanks wolfram for detailed explanation, what i'm unable to understand is why does the method add the length into t if t is less than 0? public static float Repeat(float t, float length)
i.e -0.005 + 30. Why not the value of -0.005 becomes 0.1?
Answer by IJM · Jun 21, 2012 at 12:55 PM
That method looks something like this:
return t - Mathf.Floor(t/length) * length;
Example:
Mathf.Repeat(253.22f, 250f) = 3.22f // You can fit one 250 in 253.22f, and the rest is 3.22f
Mathf.Repeat(503.22f, 250f) = 3.22f // You can fit two 250 in 503.22f, and the rest is 3.22f
You can use it to get the proper Euler angle, 'Mathf.Repeat(someAngle, 360.0f);'. If 'someAngle' is 362, it will return 2. (And you know that when it comes to Euler angles, 362 is same as 2)
Your answer
Follow this Question
Related Questions
MathF clamp not working 1 Answer
Getting an object to rotate back to zero after key is released 2 Answers
Trying to move an object between two points 2 Answers
Setting Scroll View Width GUILayout 1 Answer
MathF.SmoothDamp 2 Answers