Skip to main content
GameDev.net gamedev.net
🔒 Locked

How to generate a random int in HLSL pixel shader?

Started by sogetsu Apr 25, 2006 at 9:43 PM 12 replies 12.7k views
Original Post
sogetsu
sogetsu
Thanks for help!
RenderTarget
RenderTarget
There is no random function in a pixel shader. For a single triangle, the entire shader state is the same for each pixel shader run, except what gets passed in from the vertex pipe, and that state can't be changed for the next pixel. That means that no matter what random function you write, it will always be seeded the same if you're just using registers.

You can do some things though: One method, you can have a screen-space texture that the shader can look up. The texture can contain random number values, which you can use to seed a generator (if you need several random numbers in one shader pass). Obviously you have to generate the texture. Then for each vertex, you can have the u,v coordinates modified, maybe by a similar random method or maybe by randomized vshader variables, which would ensure that no two frames would give you the same random noise.

Or, more simply (and maybe just as good?), just use interpolated texture coordinates as your random number seed, and find a good quick random number generation function. If you scale things up well, it might result in usable values.
[sub]My spoon is too big.[/sub]
Armadon
Armadon
For a simple random value in the pixle shader. You can easily set a global such as int random; and then from your application calculate a random value and set the global from within your application ID3DXBaseEffect::SetInt()...


I hope this helps.
Take care.
Nik02
Nik02
Quote:
Original post by Armadon
For a simple random value in the pixle shader. You can easily set a global such as int random; and then from your application calculate a random value and set the global from within your application ID3DXBaseEffect::SetInt()...


I hope this helps.
Take care.


However, this value is the same across all pixel shader invocations in a single pass, so it doesn't change per-pixel.

I recommend using two or more noise textures, sampled at different texture coordinate scales, so as to introduce entropy to essentially non-random series.
Niko Suni
sogetsu
sogetsu
Thank you very much!
I want to generate serval random ints for each fragment(pixel), so I think I will try the "seed texture" or the "noise texture".
XiotexStudios
XiotexStudios
I have a 3D noise texture loaded for this reason exactly. I then combine that with a global which in turn is a random value which acts as an offset into the noise texture to provide yet another level of apparent 'randomness' - otherwise a repeating pattern can be seen through a number of passes.
Byron Atkinson-JonesXiotex Studioswww.xiotex.com
smitty1276
smitty1276
Create a texture full of random numbers, then use it to texture whatever your polygon is. The trick then is to randomly generate TEXTURE COORDINATES to randomly index into the random texture.

It's much faster than generating random numbers every pass for every fragment.
sogetsu
sogetsu
So all the random works will be done by CPU instead of GPU, right?

Quote:
Original post by smitty1276
Create a texture full of random numbers, then use it to texture whatever your polygon is. The trick then is to randomly generate TEXTURE COORDINATES to randomly index into the random texture.

It's much faster than generating random numbers every pass for every fragment.


smitty1276
smitty1276
Well, the random stuff is just initialized ONCE when you are setting up all of your resources. After that you just have to generate like 6 random numbers per frame (for the texture coordinates). The GPU then does the texture lookup to retrieve the random numbers.

My point is that if you need different random numbers each frame, then it is quicker to just generate 6 numbers for tex coords each frame than 4 million (for a 1024x1024 RGBA texture). You are reducing the work involved in random number generation to the point of irrelevance.
Jonas B
Jonas B
I have no experience with this, but it seems only offsetting coordinates might give a non-random feel at times (you can see the pattern moving)?

One way of solving it could be using two random textures at half intensity, and using different random offsets for them, then adding the pixel values together. That would look a bit better.

Are there other simple ways that don't require too many resources or cycles?
smitty1276
smitty1276
Quote:
but it seems only offsetting coordinates might give a non-random feel at times (you can see the pattern moving)?
If you randomly index into a randomly generated texture, you won't see any pattern at all, let alone a moving one. I used this technique for a recent project, and it looks like TV static. I would make the texture as large as is feasible, though. You called it an "offset"... it isn't an offset. It is actually randomly generated texture coordinates.
FBMachine
FBMachine
The majorly underdocumented texture shaders give you access to a perlin noise() function in hlsl, but I suspect texture shaders are run on the cpu and the results copied to a texture, so performance probably isn't great. I haven't used them myself so I'm not sure. Search for D3DXCreateTextureShader in the docs.
Jonas B
Jonas B
Quote:
Original post by smitty1276
If you randomly index into a randomly generated texture, you won't see any pattern at all, let alone a moving one.

Hmm... With carefully chosen random numbers, and a large enough texture, it could work.
The problem in its simplest form is what happens if your offset (what's wrong with that word?) happens to be the same on two consecutive frames? Or two frames apart? Or almost the same?
The patterns that can give a feeling of non-randomness are many.

Or did I miss something in the technique?
smitty1276
smitty1276
Quote:
Original post by Jonas B
Hmm... With carefully chosen random numbers, and a large enough texture, it could work.
The problem in its simplest form is what happens if your offset (what's wrong with that word?) happens to be the same on two consecutive frames? Or two frames apart? Or almost the same?
The patterns that can give a feeling of non-randomness are many.

Or did I miss something in the technique?


Well, an offset implies that the texture coordinates are translated by some offset. That isn't correct.

You question about the "offset" being the same for two consecutive frames comes from the fact that you are thinking of it as an offset. Think of it as generating texture coordinates. For the texture lookup at a particular fragment to produce the same values for two consecutive frames, one of 3 incredibly unlikely scenarios would have to occur:

1) You generate the VERY SAME pair floating point texture coordinates for EACH of the triangles 3 vertices. If you are indexing into a 1024x1024 texture, the resolution is about 1/1000 on each axis so there is about a 1/1000^2 probability of reproducing one coordinate. You would have to do this 3 times in a row (for each vertex), so there is roughly a 1 in 10^18 chance of this happening on any given frame.

Or...

2) You would have to generate completely different coordinates, which happen to cause the fragment to index into a texel which has the same value. There is nothing wrong with this, it's essentially a random number which happens to be the same... for an RGBA tuple this should happen about once every 255^4 times.

Or...

3) You random generate completely different set of coordinates, which just happen to represent a version of the original triangularly arranged texture coordinates which is scaled perfectly around the fragment in question.

Note, though, that these last two only affect a single fragment (potentially of thousands or millions), while all others would index into different values. The only way you would have problems is if you happen to generate the original texture coordinates consecutively, or translated versions of the previous frames coordinates. And even int that ridiculously unlikely scenario, it would occur as an imperceptible blip in any app running at a reasonable framerate, because it certainly wouldn't happen twice in our lifetimes.

You may get some weird effects if you generate two coordinates that are very, very close to each other. But it is easy to put some minor constraints to avoid this.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.