Passing time value into a shader

Started by
11 comments, last by Krohm 16 years, 1 month ago
I have a shader which uses a time value for a sin() calculation to create a pulsing effect. The time value is measured as the # of seconds since the program started and is passed in as a float to the shader. The problem is that after a certain number of seconds (say, 10000), the time value starts to become imprecise due to the limitations of floating point. To prevent the time value from becoming too large, I have to do something stupid like this: if (shaderTime > 10000.0f) shaderTime = 0.0f; So once every 10000 seconds, you might notice the pulse suddenly flicker for a split second. I know this bug would happen very rarely so in theory this is an acceptable workaround, but it is a sloppy solution I'd prefer to avoid... If I knew the period of the function was 2PI, I could do something like this: if (shaderTime > SomeVeryLargeMultipleOfTwoPi) shaderTime -= SomeVeryLargeMultipleOfTwoPi; This would prevent that flicker from happening, but then if you ever changed the period of the function in the shader (e.g. sin(1.5 * PI)) then I think this wouldn't work. Sorry for the long post, hope that makes sense! Thanks Kuro
Advertisement
I doubt you'll ever run into any precision issues using a 32-bit floating point number. They're imprecise, but not that imprecise.

If it really becomes a problem, you could try using an integer and express program time in milliseconds.
NextWar: The Quest for Earth available now for Windows Phone 7.

I have used the sine effect. By pulsating effect, you mean in a vertex shader?. I didn't run into floating point problems... ?!?

Quote:Original post by Kuro, slightly modified
if (shaderTime > 10000.0f)
shaderTime -= 10000.0f; <-- changed!


So once every 10000 seconds, you might notice the pulse suddenly flicker for a split second.

Well, it would just take to subtract a number instead of setting it...
Because of the inner workings of CPU FP implementation, you shouldn't allow your value to go too big just to restart it once in a while. It's better to to this often - say at 10 seconds instead of 10.000, although it probably makes unnoticeable differences in this context.
Quote:Original post by Kuro, slightly modified
This would prevent that flicker from happening, but then if you ever changed the period of the function in the shader (e.g. sin(1.5 * PI)) then I think this wouldn't work.
This is an important issue and a good question: how do you figure out your period mod doesn't mess up the normal appearance?

I have to say current shader implementations are a bit weak with this regard. Some higher-level shader implementations have explicit notion of "waveforms" and can extract their period for tracking. I like this solution pretty much but obviously the amount of machinery required can quickly go out of control.

Previously "Krohm"

Why not calculate the sin(value) outside the shader? Not only will you have more control, but it should save the shader work.
The sine effect most likely depends on some interpolated value from the vertex shader (like texture coordinates), so he can't do that.
It sounds like you have an issue that has nothing to do with the time value passed to the shader. I don't believe for a minute that you're losing precision at floating-point values on the order of 10000. That's only 5 significant digits and floats should have no problem up to 15 significant digits.

I would suggest looking into other possible problems that may be occurring after your program has run for two and a half hours. For instance, a small memory leak once per frame would be dangerously large after 3 hours, particularly if, for some reason, GPU memory is involved.

Do you see the same problem if you pass the shader fake large time values after just a few seconds of real runtime and then increment that large value each frame?

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I would tend to agree with Buckeye, I've seen this behavior on platforms that support half-precision floating point (and where I was using that explicitly), but when switching to the default "float" in the shader (which, bear in mind, isn't necessarily always 32 bits), I didn't have any issues.

Assuming precision WERE the issue, you could always extract your period values onto the cpu and set them as shader constants; this would allow you to offset the time value on the cpu for each shader that needed it, and would keep your those two values (the shader time and the period) synced up better.
Thanks for the replies guys.

I think emeyex's solution is the only way that would completely fix the precision problem. It would be more work because you need to pass in separate shader constants for each shader that uses a different period in its effects but it would get the job done.

Assuming you wanted just 1 global time constant that's used for all the effects, it would be really nice if you could define the time variable in your program as a double (64-bit float). However, is it possible for shaders to work with double precision?

Btw, the reason I am doing the sin() inside the shader is like Stereo said, it has a dependency on both time and some other variable which is interpolated from the vertex shader.

Also some people were wondering how I ended up getting myself into a situation where I hit the limits of floating point precision. The truth is, I haven't- I'd have to leave a game running for days, and even if I didn't bother fixing it, the worst that would happen would be that the screen might flicker for a split second and then go back to normal. So yes, I'm being really nitpicky, it just feels really sloppy to write code that has a glitch in it and saying "that will never happen!"

[Edited by - Kuro on February 20, 2008 7:38:23 PM]
Quote:Original post by Kuro
Assuming you wanted just 1 global time constant that's used for all the effects, it would be really nice if you could define the time variable in your program as a double (64-bit float). However, is it possible for shaders to work with double precision?
I'll try to say again what we're written above. It is unlikely this is an issue of insufficient precision.
Your initial "quirk" issue happened because your method was essentially calling for it.
Note that range (number of digits) isn't the only thing that takes major importance in FP processing. There are various kinds of FP errors and one depends on operation sequence.
As said, this probably doesn't make sense for extracting colors but I am uncertain this is not a problem at all (for example, you can tell the difference from old-interpolation noise to the more recent interpolator when applying reflection operators).
Quote:Original post by Kuro
So yes, I'm being really nitpicky, it just feels really sloppy to write code that has a glitch in it and saying "that will never happen!"
Just subtract instead of setting and it'll be reduced by a factor of 100.

Previously "Krohm"

This topic is closed to new replies.

Advertisement