Perlin Noise Pixel Shader Error

Started by
4 comments, last by born49 10 years, 7 months ago

Hello,

I am attempting to use perlin noise in a pixel shader as described here: http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter26.html

I believe my look up textures are correct yet this is the result of the noise output:

As one can see this doesn't look very much like perlin noise..

Here is the code used to produce that:

Screen_Shot_2013_09_04_at_10_22_17_PM.pn

Lookup texture generation:


long seed = new Random().nextLong();
		Random r = new Random(seed);
		 permutation = new int[256];
		for(int i = 0; i<permutation.length; i++){
			permutation[i] = -1;
		}
		
		for(int i = 0; i< permutation.length; i++){
			while(true){
				int iP = Math.abs(r.nextInt()) % permutation.length;
				if(permutation[iP] == -1){
					permutation[iP] = i;
					break;
				}
			}
		}
		ImageRaster rP = ImageRaster.create(permImage);
		for(int x = 0; x < 256; x++){
			for(int y = 0; y < 256; y++){
				int A = perm2d(x) + y;
                int AA = perm2d(A);
                int AB = perm2d(A + 1);
                int B = perm2d(x + 1) + y;
                int BA = perm2d(B);
                int BB = perm2d(B + 1);
                ColorRGBA c = new ColorRGBA((float)AA/255f, (float)AB/255f, (float)BA/255f, (float)BB/255f);
                rP.setPixel(x, y, c);
				
			}
		}

ImageRaster rG = ImageRaster.create(gradImage);
		for(int x = 0; x<256; x++){
			for(int y = 0; y < 1; y++){
				ColorRGBA c = new ColorRGBA(grads[permutation[x]%16][0], 
				grads[permutation[x] % 16][ 1], 
				grads[permutation[x] % 16][2], 1);
				rG.setPixel(x, y, c);
			}
		} 
		
		Texture2D permutationTable = new Texture2D(permImage);
		permutationTable.setWrap(WrapMode.Repeat);
		permutationTable.setMagFilter(MagFilter.Nearest);
		permutationTable.setMinFilter(MinFilter.NearestNoMipMaps);
		
		Texture2D gradientTable = new Texture2D(gradImage);
		gradientTable.setWrap(WrapAxis.S, WrapMode.Repeat);
		gradientTable.setWrap(WrapAxis.T, WrapMode.Clamp);
		gradientTable.setMagFilter(MagFilter.Nearest);
		gradientTable.setMinFilter(MinFilter.NearestNoMipMaps);

Pixel Shader:


uniform sampler2D permSampler2d;
uniform sampler2D permGradSampler;

varying vec4 pos;

vec3 fade(vec3 t)
{
	return (t * t * t * (t * (t * 6.0 - 15.0) + 10.0)); 
}
vec4 perm2d(vec2 p)
{
	return texture2D(permSampler2d, p);
}
float gradperm(float x, vec3 p)
{
	return dot(vec3(texture2D(permGradSampler, vec2(x,0.0)).xyz), p);
}

float inoise(vec3 p)
{
	vec3 P = mod(floor(p), 256.0);	
  	p -= floor(p);                      
	vec3 f = fade(p);                 

	P = P / 256.0;
	const float one = 1.0 / 256.0;
	  
	vec4 AA = perm2d(P.xy) + P.z;
 
  	return mix( mix( mix( gradperm(AA.x, p ),  
                             gradperm(AA.z, p + vec3(-1.0, 0.0, 0.0) ), f.x),
                       mix( gradperm(AA.y, p + vec3(0.0, -1.0, 0.0) ),
                             gradperm(AA.w, p + vec3(-1.0, -1.0, 0.0) ), f.x), f.y),
                             
                 mix( mix( gradperm(AA.x+one, p + vec3(0.0, 0.0, -1.0) ),
                             gradperm(AA.z+one, p + vec3(-1.0, 0.0, -1.0) ), f.x),
                       mix( gradperm(AA.y+one, p + vec3(0.0, -1.0, -1.0) ),
                             gradperm(AA.w+one, p + vec3(-1.0, -1.0, -1.0) ), f.x), f.y), f.z);
}

void main(void){
float n = (inoise(vec3(pos.xyz/20.0)) + 0.5) * 0.5 ;

gl_FragColor = vec4(n,n,n,1.0);
}

If anyone can spot any errors with this I would be extremely appreciative. Thanks for any help.

Advertisement

Looks fine to me (the picture), but it seems you're just not sampling over a large enough area. Can you try increasing the range of your test render, such as pos.xyz / 4 or something? And after all, perlin noise "as is" is pretty dull. You typically want to implement something like fBm which is just a summation of octaves of perlin noise (aka a fractal).

I also recall perlin noise returning values between -1 and 1, so your scaling code might not be correct (don't quote me on this though), as it puts your "n" in (-0.25.. 0.75). Try doing "(noise + 1) * 0.5" and see if that gives you gradients between black and white as expected. I could be wrong on that part though.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Looks fine to me (the picture), but it seems you're just not sampling over a large enough area. Can you try increasing the range of your test render, such as pos.xyz / 4 or something? And after all, perlin noise "as is" is pretty dull. You typically want to implement something like fBm which is just a summation of octaves of perlin noise (aka a fractal).

I also recall perlin noise returning values between -1 and 1, so your scaling code might not be correct (don't quote me on this though), as it puts your "n" in (-0.25.. 0.75). Try doing "(noise + 1) * 0.5" and see if that gives you gradients between black and white as expected. I could be wrong on that part though.

Hmm well decreasing 20 to 4 returned the following image:

Screen_Shot_2013_09_04_at_11_33_09_PM.pn

Which looks far too...ordered.

Especially compared to this, which is output from this same function:

texquad.png

Also I ran a few tests and I think you are right about (noise + 0.5) * 0.5...changing it to what you suggested returns values dispersed through -1 - 1

UPDATE:

Looks fine to me (the picture), but it seems you're just not sampling over a large enough area. Can you try increasing the range of your test render, such as pos.xyz / 4 or something? And after all, perlin noise "as is" is pretty dull. You typically want to implement something like fBm which is just a summation of octaves of perlin noise (aka a fractal).

I also recall perlin noise returning values between -1 and 1, so your scaling code might not be correct (don't quote me on this though), as it puts your "n" in (-0.25.. 0.75). Try doing "(noise + 1) * 0.5" and see if that gives you gradients between black and white as expected. I could be wrong on that part though.

I found that the problem was how the textures were being passed to the shaders. Once that was fixed it began to work! Thanks for the help (and the tip about normalizing the range).

Here is the end result (for comparisons sake):

Screen_Shot_2013_09_05_at_12_50_58_AM.pn

Glad you got it fixed, and yeah the second picture didn't look at all right. smile.png

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

You can also use 'texture-less' GPU noise, which can save you lot of pain :-) For inspiration you can look at

Brian Sharpe's high quality + high performance GPU noise lib here: https://github.com/BrianSharpe/GPU-Noise-Lib.

This topic is closed to new replies.

Advertisement