kodelife/glsl noise

I had been cluttering up my Unity notes blog with GLSL/Kodelife stuff, so I've made this new page here...

Below is some code that generates some smooth looking noise. It isn't very complex, but it's probably good enough to get you going. Using code from The Art of Code youtube channel. Let's break down the important functions and see how they feed into one another.

float N21(vec2 p){
    return fract(sin(p.x*1000.0+p.y*6832.0)*5224.0);
}

This function takes a vector 2 "p", which is actually going to be our uv coordinate & multiplies each component(x and y) by two arbitrary large numbers , before getting the sine value. This small value is then multiplied by another large number, and then only the fractional part of that value is returned.

On it's own, this will return nice static tv/white noise kinda values. You might call it in the main function like this -

float c= N21(uv*4.0)

 

Next up, is 

float smoothNoise(vec2 uv){
    vec2 lv=fract(uv);
   lv=lv*lv*(3.0-2.0*lv);
   vec2 id=floor(uv);
   
   float bl=N21(id);
   float br=N21(id+vec2(1,0));
   float b=mix(bl,br, lv.x);
   
   float tl=N21(id+vec2(0,1));
   float tr=N21(id+vec2(1,1));
   float t=mix(tl,tr, lv.x);
   
    return mix(b,t,lv.y);

}

The problem with the N21 noise is it isn't actually random  - if you zoom into it (by multiplying the UV by a low number) you'll see a bunch of crappy looking sine waves...which is what we told the computer to produce after all. The smoothNoise function we have here interpolates noise values along the "UV square". First it creates two coordinate spaces - local (lv) and per square (id), using the fract and floor functions.

It calculates the bottom left (bl) of the UV square using our previously made N21 function and passing the id coordinate. Then it calculates the bottom right, by adding (1,0) to the id. We then calculate the mix of bottom left to bottom right, based on the local x value (eg per UV square, if we've multiplied the UV). Lets call this blended value b.
The N21 function is then used again to calculate top left to top right in a similar fashion & then we blend those two values again, using the local x. The blended value is called t.

Once we have those values we can blend b and t, using the local y value. Something we haven't mentioned is the    lv=lv*lv*(3.0-2.0*lv); line. This is an interpolation trick the youtuber used. It's to smooth out the corners of the UV grid. If you omit this, you could get some unwanted (or perhaps you do want it) spiky noise values.

Finally -


float smoothNoise2(vec2 uv){
float c=smoothNoise(uv*4);
   c+=smoothNoise(uv*8)*0.5;
   c+=smoothNoise(uv*16)*0.25;
   c+=smoothNoise(uv*32)*0.125;
   c+=smoothNoise(uv*64)*0.0625;
   return c/=2;

}

This well named function uses the smoothNoise function to make layers of noise on top of itself. These extra layers are what we call "octaves" in some 3d packages. Notice how the UV's are multiplied UP at each stage & the resulting value are multiplied DOWN. We are adding smaller details at each stage.
The divide by two at the end is a way to keep the resultant value below 1. A normalisation. It isn't an accurate number, as the youtuber admitted!

 

#version 150

uniform float time;
uniform vec2 resolution;
uniform vec2 mouse;
uniform vec3 spectrum;

uniform sampler2D texture0;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform sampler2D texture3;
uniform sampler2D prevFrame;
uniform sampler2D prevPass;

in VertexData
{
    vec4 v_position;
    vec3 v_normal;
    vec2 v_texcoord;
} inData;

out vec4 fragColor;

float N21(vec2 p){
    return fract(sin(p.x*1000.0+p.y*6832.0)*5224.0);

}

float smoothNoise(vec2 uv){
    vec2 lv=fract(uv);
   lv=lv*lv*(3.0-2.0*lv);
   vec2 id=floor(uv);
   
   float bl=N21(id);
   float br=N21(id+vec2(1,0));
   float b=mix(bl,br, lv.x);
   
   float tl=N21(id+vec2(0,1));
   float tr=N21(id+vec2(1,1));
   float t=mix(tl,tr, lv.x);
   
    return mix(b,t,lv.y);

}

float smoothNoise2(vec2 uv){
float c=smoothNoise(uv*4);
   c+=smoothNoise(uv*8)*0.5;
   c+=smoothNoise(uv*16)*0.25;
   c+=smoothNoise(uv*32)*0.125;
   c+=smoothNoise(uv*64)*0.0625;
   return c/=2;

}
void main(void)
{
    vec2 uv =  inData.v_texcoord;
   
    float c=smoothNoise2(uv);
   
   
   
   
    vec3 col=vec3(c);
   
    fragColor = vec4(col, 1.0);
}

Comments

Popular posts from this blog

kodelife/glsl drawing a circle (sdf)

OSL - simple UV things and frac fract alternative

step and smoothstep functions, drawing a line