Generate "normal noise"

Hi, all

At the moment i am working on a shader based on an SSAO article in an pdf about Starcraft2’s rendering and effects and such. There seems to be someone that has come up with a GLSL version, but i’m doing mine in HLSL.

Now, i dont want any help writing the darned thing, i’d be happy to figure it out myself but in the explanation of the GLSL shader a picture came up. First i did not really know what it was because of alot of grey tones in there, but i’m starting to think it is an object-space normal map. It is supposed to be a random normals texture, used to get a more even look to the SSAO. Now i want to know, how can i make such a texture:?:

The texture example:


No2 vaporizer

The texture is used to jitter the screen space texture taps. It is quite literally a texture that encodes a field of random vectors. Nothing more, nothing less. I believe that some of those algorithms benefit from actually having unit vectors (perhaps why the term “normal” was used). They are definitely not object space, but depending on your implementation they may be view or screen space normals. But like I said, it is just a random field for the shader to play with.

You can probably make them in Photoshop somehow, but for me it is much more clear in Python:


from PIL import Image, ImageDraw
from random import uniform
from math import sqrt

def drawRandomImage( filename="", width=128, height=128, normal=False ):

    print "Creating Image"
    im = Image.new( "RGB", (width, height) )
    pixels = im.load()

    print "Populating Pixel Array"    
    for y in xrange(im.size[0]):
        for x in xrange(im.size[1]):
            pixels[x, y] = getRandomNormal( normal )

    if ( filename != "" ):
        print "Saving File"
        im.save(filename)
    else:
        print "Displaying File"
        im.show()

    print "Done!"

def getRandomNormal( normal=False ):
    vector = uniform(-1, 1), uniform(-1, 1), uniform(-1,1)
    if normal:
        vector = normalize( vector )
    return normalToColor( vector )

def normalToColor( vec ):
    f = lambda x: int( 255 * ( ( x + 1 ) * .5 ) )
    return ( f(vec[0]), f(vec[1]), f(vec[2]) )
    
def normalize( vec ):
    length = sqrt( (vec[0] * vec[0]) + (vec[1] * vec[1]) + (vec[2] * vec[2]) )
    vec = (vec[0]/length, vec[1]/length, vec[2]/length );
    return vec
    

if __name__ == "__main__":
    drawRandomImage( "C:/storage/normalNoise.png", 128, 128, True )

You should be able to use this to generate a nice little random field of your own, although your example is pretty much perfect, you don’t really need a custom one of these, you could just use that. If someone has a copyright on 8 kb of random data then there are other problems.

Edit: fixed minor typo that caused undefined behavior.

Wow, that is really much more then i hoped for. Your explanation seems to be pretty much spot on and i think i made mistake to say that they are supposed to be normals because they indeed are supposed to be VECTORS.

I really hope hou had fun making that script, because i don’t think many people will use it. I’m eager to see what it exactly does and since i’m a python noob i’m sure i’ll learn from this. Thanks alot.

Were you involved in the creation of the starcraft2 shader?

Edit: I tried it and i found it strange it would only work when i first made the image myself. It threw an error saying it couldn’t save because the file did not exists, so i made a blank image and saved it using the correct name and it worked beautifully, the grey it not really seen in your image but i’m not sure it’s even grey in the example. Anyway thanks again, i learned someting about python too :slight_smile:


YAMAHA RD500LC

[QUOTE=Gungnir;2802]I really hope hou had fun making that script, because i don’t think many people will use it. I’m eager to see what it exactly does and since i’m a python noob i’m sure i’ll learn from this. Thanks alot.
[/QUOTE]

I always have fun doing stuff like that. I hope that it was clear enough. I did some quick and dirty stuff to try and keep it terse, but it is less robust than something you would actually want to use.

[QUOTE=Gungnir;2802]
Were you involved in the creation of the starcraft2 shader?
[/QUOTE]

No, but I’ve read that and some other SSAO papers and generally like the subject.

[QUOTE=Gungnir;2802]
Edit: I tried it and i found it strange it would only work when i first made the image myself. It threw an error saying it couldn’t save because the file did not exists, so i made a blank image and saved it using the correct name and it worked beautifully, the grey it not really seen in your image but i’m not sure it’s even grey in the example. Anyway thanks again, i learned someting about python too :)[/QUOTE]

Sorry about that. That script wasn’t exactly super planned out. What is probably happening is the permissions for python are different on your machine than mine. I’m quite sorry for that bit. Shame on me for being lazy. Also, the image will have more grays in it if you pass the “normal” parameter as false. This will let the vectors be non-unitlength. I didn’t know if that was what you wanted or not. If you are doing a “normalize()” after the read in the shader though, the normalized version of the texture is essentially the same thing.

Cheers! -Lith

thanks for that explanation. I was interested in that too! :):