To make our wind, we need a simple ripple effect. We will create a vec2 and call it "Coord". This will be used for the wind distortion. We will set it to "v_vTexcoord". Now you need to change the texture2D coordinates to our Coord vector. It should look like this:

*vec2 Coord = v_vTexcoord;*

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord);

This is a pass-through shader. If you run the shader applied to a sprite, it shouldn't change anything. To make a ripple we will use a cosine wave. We could do it like this:

* vec2 Coord = v_vTexcoord + vec2(cos(v_vTexcoord.y*30.0)/30.0,0);*

If you run this you will see this (before and after):

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, Coord);

This is a pass-through shader. If you run the shader applied to a sprite, it shouldn't change anything. To make a ripple we will use a cosine wave. We could do it like this:

If you run this you will see this (before and after):

This is closer to what we want, but we need it to be animated. This works by shifting the X coordinates in a cosine wave shape. This makes a nice ripple. You can adjust the frequency by changing the first 30.0 and adjust the amplitude by changing the second 30.0. We'll come back to this at the end of the tutorial

We need to add a uniform float and we'll call it "Time" and we'll add it in the cosine like this:

*vec2 Coord = v_vTexcoord + vec2(cos(v_vTexcoord.y*30.0+Time*6.2831)/30.0,0);*

It is multiplied by 6.2831 (pi times two) because cosine uses angles in radians so that it does a full cycle every second.

We'll set the time uniform in GameMaker like this in the draw event:

* var uTime = shader_get_uniform(shdr_wind,"Time");*

shader_set(shdr_wind)

shader_set_uniform_f(uTime,current_time/1000)

draw_self()

* shader_reset()*

This will set "Time" to the number of seconds since the game started.

If you run this it will be animated. You may notice a problem where the base of the grass moves

just as much as the top.

It is multiplied by 6.2831 (pi times two) because cosine uses angles in radians so that it does a full cycle every second.

We'll set the time uniform in GameMaker like this in the draw event:

shader_set(shdr_wind)

shader_set_uniform_f(uTime,current_time/1000)

draw_self()

This will set "Time" to the number of seconds since the game started.

If you run this it will be animated. You may notice a problem where the base of the grass moves

just as much as the top.

So to fix the problem I just mentioned we will multiply cosine by the" (1.0-v_vTexcoord.y)". This will make the distortion decrease as it approaches the bottom of the sprite. Here is what I did:

*vec2 Coord = v_vTexcoord + vec2(cos(v_vTexcoord.y*30.0 + Time*6.2831)/30.0,0)*(1.0-v_vTexcoord.y);*

It looks much better now. This shader is currently proportion to the sprite size. If it's long it will stretch the waves, but if it's short it will shrink the waves. That is because the waves are based off of the v_vTexcoord which is between 0 and 1. To fix this we can use the position attribute from the vertex shader because it uses the vertex coordinates rather than the texture coordinates.

We need to add a varying vec2 called "v_vPosition" in the vertex and fragment shaders by the other varying vectors. Set it in the vertex shader like this:

*v_vPosition = in_Position.xy;*

And back to the fragment shader use this for the coordinates:

*vec2 Size = vec2(256,128);*

vec2 Wave = vec2(48,5);

vec2 Coord = v_vTexcoord +vec2(cos((v_vPosition.y/Wave.x+Time)*6.2831)*Wave.y,0)/Size*(1.0-v_vTexcoord.y);

**"Size" should be the size of the texture. Use a uniform if necessary. "Wave" is for adjusting the wave shape. The first number is the height of the wave and the second number is the amplitude.

This works by making a cosine wave of the chosen size with time added (multiplied by 6.2831 because of radians) and then multiplied by the amplitude; then divided by "Size" to get it between 0 and 1 and finally multiplied by the code I mentioned above to fix the bottom.

Thanks for reading.

DOWNLOAD EXAMPLE

Basic tutorials used:

#4 Vertex Shader

#2 Black and White Shader

#1 Shader Basics

]]>

It looks much better now. This shader is currently proportion to the sprite size. If it's long it will stretch the waves, but if it's short it will shrink the waves. That is because the waves are based off of the v_vTexcoord which is between 0 and 1. To fix this we can use the position attribute from the vertex shader because it uses the vertex coordinates rather than the texture coordinates.

We need to add a varying vec2 called "v_vPosition" in the vertex and fragment shaders by the other varying vectors. Set it in the vertex shader like this:

And back to the fragment shader use this for the coordinates:

vec2 Wave = vec2(48,5);

vec2 Coord = v_vTexcoord +

This works by making a cosine wave of the chosen size with time added (multiplied by 6.2831 because of radians) and then multiplied by the amplitude; then divided by "Size" to get it between 0 and 1 and finally multiplied by the code I mentioned above to fix the bottom.

Thanks for reading.

DOWNLOAD EXAMPLE

Basic tutorials used:

#4 Vertex Shader

#2 Black and White Shader

#1 Shader Basics

We will first try making a shader that flattens the 3d shapes. To do this we will simply set the z position to 0 for all vertices while leaving x and y positions unchanged. Make sure to comment out the normal attribute and use the default pass through fragment shader.

An important variable is "object_space_pos". It is the variable we can use for setting the position.

We will use the x and y components but will use 0 instead of z.

Here is the result:

An important variable is "object_space_pos". It is the variable we can use for setting the position.

We will use the x and y components but will use 0 instead of z.

Here is the result:

As you can see the shapes are properly flattened. Because you now know how to change the vertex position we'll try making water.

Before we begin with the water shader, we will need something to apply the shader to. We will make a plane instead of our basic shapes. In GameMaker, this may be a little tricky, because we need to generate one with enough vertices. Here is the code I used:

**water = d3d_model_create();**

cells = 64;//Number of cells

cell = 8;//Cell width

height = 32;//Water max height

for(var X = -cells/2;X<cells/2;X++)

{

d3d_model_primitive_begin(water,pr_trianglestrip)

for(var Y = -cells/2;Y<cells/2-1;Y++)

{

d3d_model_vertex(water,X*cell,Y*cell,height)

d3d_model_vertex(water,(X+1)*cell,Y*cell,height)

}

d3d_model_primitive_end(water)

}

This generates a plane model with many vertices to create higher quality water.

Apply your shader to this model instead of the basic shapes using "d3d_model_draw()".

cells = 64;//Number of cells

cell = 8;//Cell width

height = 32;//Water max height

for(var X = -cells/2;X<cells/2;X++)

{

d3d_model_primitive_begin(water,pr_trianglestrip)

for(var Y = -cells/2;Y<cells/2-1;Y++)

{

d3d_model_vertex(water,X*cell,Y*cell,height)

d3d_model_vertex(water,(X+1)*cell,Y*cell,height)

}

d3d_model_primitive_end(water)

}

This generates a plane model with many vertices to create higher quality water.

Apply your shader to this model instead of the basic shapes using "d3d_model_draw()".

We will use our knowledge to make detailed 3d water using perlin noise and height displacement. You should see the Vertex shader tutorial. We will be using the rand and noise functions to determine the height of the water for each vertex so put them in the vertex shader. Now we'll create a variable called height. This will be used to set the height of the water per vertex. Use this code:

**float height = noise(in_Position.xy/64.0)*0.4+noise(in_Position.xy/32.0)*0.3+noise(in_Position.xy/16.0)*0.2+noise(in_Position.xy/8.0)*0.1;**

That code generates a perlin noise pattern to make waves in the water.

Instead of setting the z position to 0 we'll set it to "height * in_Position.z". This makes it so we can determine the wave height by setting z position. And now finally we'll make a varying float called "v_vHeight" and pass our height variable through it. Now set the color in the fragment shader:

**gl_FragColor = vec4(mix(vec3(0.1,0.2,0.4),vec3(0.1,0.1,0.3),v_vHeight),1.0);**

This is the result:

]]>That code generates a perlin noise pattern to make waves in the water.

Instead of setting the z position to 0 we'll set it to "height * in_Position.z". This makes it so we can determine the wave height by setting z position. And now finally we'll make a varying float called "v_vHeight" and pass our height variable through it. Now set the color in the fragment shader:

This is the result:

Lighting shader usually use normals. As you may remember from the last tutorial, normals are the vectors which are perpendicular to each triangle. I will explain them in better detail.

Normal vector information can be received using the "in_Normal" attribute. This is only processed for each vertex (because it's in the vertex shader). So we'll create a varying vector called "v_vNormal" and we'll add it to both shaders (fragment and vertex). This way the normal can processed per pixel rather than per vertex. To test this shader we'll set the color to the normals so we can see what the normals look like. This is the code I used:

**gl_FragColor = vec4(v_vNormal*0.5+0.5,1.0);**

Because normals are in the range of -1 and 1 we'll multiply it be 0.5 and add 0.5 to put it in the range of 0 to 1 (since we can't see negative colors).

Here is what it looks like (downloads at the bottom):

Because normals are in the range of -1 and 1 we'll multiply it be 0.5 and add 0.5 to put it in the range of 0 to 1 (since we can't see negative colors).

Here is what it looks like (downloads at the bottom):

That is a simple scene with a sphere, cube and cone. You can see the normals with our shader. When you make your own models, you'll want to make sure the normals are correct.

Now we'll move on to a simple lighting shader.

Now we'll move on to a simple lighting shader.

Now that we get normals we'll make some simple directional lighting. To do this we will need to create a few vectors. We'll create a vec3 called "dir" and set it to something like "vec3( 0.6, 0.1, -1.0)".

This will be the direction of our light. Next create another vec3 called "col". This will be for the light color. We'll set this to a nice blue color (I used "vec3( 0.5, 0.8, 1.0)").

Now create a float called "lighting". Since this will be for the brightness of the pixel we'll need to calculate how much light it is receiving. We'll use the dot product function. This function finds the difference between two vectors in the range of -1 to 1 (if used properly). The vectors should be normalized. When you normalize a vector it sets the length of the vector to 1 while keeping it in proportion. If you do not do this to the vectors of a dot product, then it will return something in a range larger (or smaller) than -1 to 1 and in this case, ruin the lighting.

So now we'll set lighting to the dot product of "v_vNormal" and "dir" (make sure their both normalized). This will find the difference of the normal and the light (between -1 and 1).

To convert this to a visible value we multiply it by 0.5 and add 0.5. Now mulitply the "lighting" float and "col" vector to the texture color (making sure it is a vec4). Your code should look like this:

**vec3 dir = vec3( 0.6, 0.1, -1.0);//Light direction**

vec3 col = vec3( 0.5, 0.8, 1.0);//Light color

float lighting = (dot( normalize(v_vNormal), normalize(dir)) * 0.5 + 0.5);//Calculate

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord) * vec4( lighting * col, 1.0);

This gets the desired light direction and color, then calculates it with "lighting" and finally applies it to the texture. This is the result (downloads below):

This will be the direction of our light. Next create another vec3 called "col". This will be for the light color. We'll set this to a nice blue color (I used "vec3( 0.5, 0.8, 1.0)").

Now create a float called "lighting". Since this will be for the brightness of the pixel we'll need to calculate how much light it is receiving. We'll use the dot product function. This function finds the difference between two vectors in the range of -1 to 1 (if used properly). The vectors should be normalized. When you normalize a vector it sets the length of the vector to 1 while keeping it in proportion. If you do not do this to the vectors of a dot product, then it will return something in a range larger (or smaller) than -1 to 1 and in this case, ruin the lighting.

So now we'll set lighting to the dot product of "v_vNormal" and "dir" (make sure their both normalized). This will find the difference of the normal and the light (between -1 and 1).

To convert this to a visible value we multiply it by 0.5 and add 0.5. Now mulitply the "lighting" float and "col" vector to the texture color (making sure it is a vec4). Your code should look like this:

vec3 col = vec3( 0.5, 0.8, 1.0);//Light color

float lighting = (dot( normalize(v_vNormal), normalize(dir)) * 0.5 + 0.5);//Calculate

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord) * vec4( lighting * col, 1.0);

This gets the desired light direction and color, then calculates it with "lighting" and finally applies it to the texture. This is the result (downloads below):

As you can see, our nice scene now has lighting. Lets take this farther by creating a point light.

Now that you have a basic understanding of 3D lighting we can create point lights.

We want the point lights to have a radius. So we can add a float called "rad".

Since these lights cast shine in all directions, we'll need to change the "dir" vector.

This is actually simple to set, but we'll need the position of each pixel, so we'll add another varying vec3 and call it "v_vPosition". In the vertex shader, set it to "in_Position".

With the position we can calculate the direction from the light to each pixel. We simple put in the desired position for the point light (I used "vec3( 0.0, 32.0, -96.0)") and then subtract the pixel position ("v_vPoisiton"). That gets the direction for the light.

Now the last thing we'll add is a radius. This will make the light fade the farther the it is from the surface of each object. This is called Attenuation so we'll make a variable called "attenuation". Set this variable to the length of "dir" (so we get the distance from the light) and divide it by "rad" (so the brightness equals one when it is at the radius distance and 0 when at the light). This is opposite of what we want so we'll have it 1 minus are current code. To keep this from going negative we'll put the max function around our code with the second argument to 0 (which keeps it from going below 0).

The fragment code should look like this:

**vec3 dir = vec3( 0.0, 32.0, -96.0) - v_vPosition;//Light direction**

float rad = 128.0;//Light radius

vec3 col = vec3( 0.5, 0.8, 1.0);//Light color

float attenuation = max( 1.0 - length(dir)/rad, 0.0);//Calculate brightness

float lighting = (dot( normalize(v_vNormal), normalize(dir)) * 0.5 + 0.5) * attenuation;//Calculate lighting

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord) * vec4( lighting * col, 1.0);

When running the code, the result should look like this (downloads at the bottom):

We want the point lights to have a radius. So we can add a float called "rad".

Since these lights cast shine in all directions, we'll need to change the "dir" vector.

This is actually simple to set, but we'll need the position of each pixel, so we'll add another varying vec3 and call it "v_vPosition". In the vertex shader, set it to "in_Position".

With the position we can calculate the direction from the light to each pixel. We simple put in the desired position for the point light (I used "vec3( 0.0, 32.0, -96.0)") and then subtract the pixel position ("v_vPoisiton"). That gets the direction for the light.

Now the last thing we'll add is a radius. This will make the light fade the farther the it is from the surface of each object. This is called Attenuation so we'll make a variable called "attenuation". Set this variable to the length of "dir" (so we get the distance from the light) and divide it by "rad" (so the brightness equals one when it is at the radius distance and 0 when at the light). This is opposite of what we want so we'll have it 1 minus are current code. To keep this from going negative we'll put the max function around our code with the second argument to 0 (which keeps it from going below 0).

The fragment code should look like this:

float rad = 128.0;//Light radius

vec3 col = vec3( 0.5, 0.8, 1.0);//Light color

float attenuation = max( 1.0 - length(dir)/rad, 0.0);//Calculate brightness

float lighting = (dot( normalize(v_vNormal), normalize(dir)) * 0.5 + 0.5) * attenuation;//Calculate lighting

gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord) * vec4( lighting * col, 1.0);

When running the code, the result should look like this (downloads at the bottom):

There's a simple light in the center of the screen which properly fades. You can easily add a uniform for changing light position, radius, direction, or color if you want, but that is up to the developer.

DOWNLOAD NORMALS EXAMPLE

DOWNLOAD DIRECTIONAL LIGHT EXAMPLE

DOWNLOAD POINT LIGHT EXAMPLE

]]>DOWNLOAD NORMALS EXAMPLE

DOWNLOAD DIRECTIONAL LIGHT EXAMPLE

DOWNLOAD POINT LIGHT EXAMPLE

In order to make a shader for 3D you will most likely need to no 3d information such as position and normals. In the Vertex Shader Tutorial I explained in briefly how to get the position with the "in_Position" vector (only in the vertex shader). In order to add this to the fragment shader you'll need a varying vec3 for position. Create one and call it "v_vPosition". Make sure it's in the fragment shader also.

To get the position in 3D we will simply use the Z component along with the X and Y components. You can also get the normals (which is essentially a vector perpendicular to the currently processed triangle) of the triangles as they are set (d3d_draw functions have the normals already). When you apply the shader to a 3D object then you can retrieve the normal which is useful for lighting.

To get the position in 3D we will simply use the Z component along with the X and Y components. You can also get the normals (which is essentially a vector perpendicular to the currently processed triangle) of the triangles as they are set (d3d_draw functions have the normals already). When you apply the shader to a 3D object then you can retrieve the normal which is useful for lighting.

For our first example we'll make a simple shader which makes all 3D objects below a certain height turn black. This is rather simple to do. In the fragment shader we can check if "v_vPosition.z" is less than your desired height, then set it to black if it is. Because the vertex shader is only run for every vertex it's not precise enough for this shader. That is why we passed it to the fragment shader so that we can check each pixel rather than each vertex. For my example I used:

**if (v_vPosition.z>0.0)**

{

gl_FragColor = vec4(0.0,0.0,0.0,1.0);

}

Here is a screenshot of a simple 3D demo scene:

{

gl_FragColor = vec4(0.0,0.0,0.0,1.0);

}

Here is a screenshot of a simple 3D demo scene:

As you can see the parts below 0 Z are black.

DOWNLOAD EXAMPLE

]]>DOWNLOAD EXAMPLE

Shaders on GLSL Sandbox have a few differences from shaders in GameMaker. Like on ShaderToy there are no textures most of the time. However GLSL Sandbox only supports frame buffers. If a shader uses theses, there will be a uniform sampler2D with the other uniforms. It can be named anything, but it is most often called "backbuffer" or "bb". Frame buffers must be made in GameMaker outside of the shader. These can be done with surfaces in GameMaker, but because these are very rarely used I will not get in too much detail.

Check out tutorial 4 if you haven't already for information about varying vectors. You will need to create a varying vec2 called "fragCoord". Then set it in the vertex shader to "in_Position.xy". You can also remove v_vColour and v_vTexcoord because they won' be used in this shader.

Some shaders also have a varying vec2 called "surfacePosition" (although it is not in this shader). This is used to make shaders where you can scroll and zoom. To make this in GameMaker you should another varying vector in vertex shader called "surfacePosition". Then you should be set like this:

**surfacePosition = in_Position.xy*Scroll.zw+Scroll.xy;**

"Scroll" will be a vec4 uniform that we'll add next. That code will zoom with z and w components and offset with the x and y.

Some shaders also have a varying vec2 called "surfacePosition" (although it is not in this shader). This is used to make shaders where you can scroll and zoom. To make this in GameMaker you should another varying vector in vertex shader called "surfacePosition". Then you should be set like this:

"Scroll" will be a vec4 uniform that we'll add next. That code will zoom with z and w components and offset with the x and y.

Make sure you see tutorial 5 part 2 for details about uniforms.

GLSL Sandbox shaders already have the uniforms setup. As long as you set them to the right values it should work fine. If the shader has "surfacePosition" then only thing you need to add is a vec4 uniform called "Scroll". This can be used in GameMaker to scroll and zoom.

GLSL Sandbox shaders already have the uniforms setup. As long as you set them to the right values it should work fine. If the shader has "surfacePosition" then only thing you need to add is a vec4 uniform called "Scroll". This can be used in GameMaker to scroll and zoom.

Here's a final summary of what we have learned:

**#ifdef GL_ES**

precision mediump float;

#endif

uniform float time;

uniform vec2 resolution;

void main( void ) {

vec2 uv = ( gl_FragCoord.xy / resolution.y );

vec3 color = vec3(fract(sin(dot(floor(uv.xy*32.0+time*2.0),vec2(5.364,6.357)))*357.536));

gl_FragColor = vec4( color, 1.0 );

**Converted GameMaker fragment code:**

**#ifdef GL_ES**

precision mediump float;

#endif

varying vec2 FragCoord;

uniform float time;

uniform vec2 resolution;

void main( void )

{

vec2 uv = ( FragCoord.xy / resolution.y );

vec3 color = vec3(fract(sin(dot(floor(uv.xy*32.0+time*2.0),vec2(5.364,6.357)))*357.536));

gl_FragColor = vec4( color, 1.0 );

}

Converted vertex code:

**attribute vec3 in_Position; // (x,y,z)**

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

//attribute vec4 in_Colour; // (r,g,b,a) unused in this shader.

//attribute vec2 in_TextureCoord; // (u,v) unused in this shader.

varying vec2 FragCoord;

void main()

{

vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);

gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

FragCoord = in_Position.xy;

}

Here is the example file:

DOWNLOAD EXAMPLE

]]>- Change "gl_FragCoord" to "fragCoord"
- Add "fragCoord" and "surfacePosition" (if needed) to vertex shader
- Add "Scroll" vec4 uniform if needed
- Set all uniforms (may include time, resolution or mouse)

precision mediump float;

#endif

uniform float time;

uniform vec2 resolution;

void main( void ) {

vec2 uv = ( gl_FragCoord.xy / resolution.y );

vec3 color = vec3(fract(sin(dot(floor(uv.xy*32.0+time*2.0),vec2(5.364,6.357)))*357.536));

gl_FragColor = vec4( color, 1.0 );

precision mediump float;

#endif

varying vec2 FragCoord;

uniform float time;

uniform vec2 resolution;

void main( void )

{

vec2 uv = ( FragCoord.xy / resolution.y );

vec3 color = vec3(fract(sin(dot(floor(uv.xy*32.0+time*2.0),vec2(5.364,6.357)))*357.536));

gl_FragColor = vec4( color, 1.0 );

}

Converted vertex code:

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

//attribute vec4 in_Colour; // (r,g,b,a) unused in this shader.

//attribute vec2 in_TextureCoord; // (u,v) unused in this shader.

varying vec2 FragCoord;

void main()

{

vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);

gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

FragCoord = in_Position.xy;

}

Here is the example file:

DOWNLOAD EXAMPLE

Note that because the shaders are designed for Shadertoy.com, they won't always be fully optimized for GameMaker. It can often be best to just design a shader yourself. This tutorial may not cover all the differences, but it should help you convert most shaders from Shadertoy.com.

The shaders on Shadertoy.com don't need textures and most of them don't even use textures (my shader does not use any textures either). If a shader does use textures it will show the textures at the bottom right (at the iChannel0-iChannel3). In GameMaker: Studio, shaders must be applied to something, so most of the shaders designed for GameMaker, are applied to sprites, backgrounds, or in 3D they can be applied to planes. That means shaders in GameMaker must have at least one texture (although that texture can be a blank rectangle). Another difference is Shadertoy shaders recently started using fragColor for gl_FragColor. To remove errors simply change those back to gl_FragColor. Also "void mainImage( out vec4 fragColor, in vec2 fragCoord )" should be replaced with this "void main( void)".

Check out tutorial 4 if you haven't already for information about varying vectors. You will need to create a varying vec2 called fragCoord. Then set it in the vertex shader to "in_Position.xy". You can also remove v_vColour and v_vTexcoord because they won' be used in this shader.

To see all the uniforms you may need, click the "Shader inputs" menu above the shader code. This will show all the uniforms ShaderToy uses. You should copy all the uniforms the specific shader uses in to the shader in GameMaker. Make sure you see tutorial 5 part 2 for details about uniforms.

If a shader does not use textures, then you just apply the shader to a rectangle or blank texture. In order to get textures, you must use uniform samplers (unless it's just one texture). With one texture you could just use the base texture (which is whatever you applied it to). For now we won't worry about textures since we're not using them.

So to make things easier I'll make a list for you. So when converting shaders you'll most likely need to change all these things:

{

return fract(abs(sin(dot(n,vec3(4.3357,-5.8464,6.7645))*52.47))*256.75+0.325);

}

void mainImage( out vec4 fragColor, in vec2 fragCoord )

{

vec3 p = vec3(fragCoord.xy+vec2(iGlobalTime)*64.0,0.0);

float b = (rand(floor(p/64.0))*0.5+rand(floor(p/32.0))*0.3+rand(floor(p/16.0))*0.2);

fragColor = vec4(vec3(b*0.6),1.0);

} float rand(vec3 n)

Here's the converted fragment code:

**uniform float iGlobalTime;**

**varying vec2 fragCoord;**

float rand(vec3 n)

{

return fract(abs(sin(dot(n,vec3(4.3357,-5.8464,6.7645))*52.47))*256.75+0.325);

}

void main(void)

{

vec3 p = vec3(fragCoord.xy+vec2(iGlobalTime)*64.0,0.0);

float b = (rand(floor(p/64.0))*0.5+rand(floor(p/32.0))*0.3+rand(floor(p/16.0))*0.2);

gl_FragColor = vec4(vec3(b*0.6),1.0);

}

Now here is the vertex code:

**attribute vec3 in_Position; // (x,y,z)**

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

//attribute vec4 in_Colour; // (r,g,b,a) unused in this shader.

//attribute vec2 in_TextureCoord; // (u,v) unused in this shader.

varying vec2 fragCoord;

void main()

{

vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);

gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

fragCoord = in_Position.xy;

}

Here's the example file:

DOWNLOAD EXAMPLE

For a challenge you can convert my "Cool Lake"shader.

]]>- Change "fragColor" to "gl_FragColor"

- Change "void mainImage( out vec4 fragColor, in vec2 fragCoord )" to "void main( void)"
- Create the varying vec2 called "fragCoord"
- Remove unneeded attribute vectors
- Add the needed uniforms including the samplers

{

return fract(abs(sin(dot(n,vec3(4.3357,-5.8464,6.7645))*52.47))*256.75+0.325);

}

void mainImage( out vec4 fragColor, in vec2 fragCoord )

{

vec3 p = vec3(fragCoord.xy+vec2(iGlobalTime)*64.0,0.0);

float b = (rand(floor(p/64.0))*0.5+rand(floor(p/32.0))*0.3+rand(floor(p/16.0))*0.2);

fragColor = vec4(vec3(b*0.6),1.0);

}

Here's the converted fragment code:

float rand(vec3 n)

{

return fract(abs(sin(dot(n,vec3(4.3357,-5.8464,6.7645))*52.47))*256.75+0.325);

}

void main(void)

{

vec3 p = vec3(fragCoord.xy+vec2(iGlobalTime)*64.0,0.0);

float b = (rand(floor(p/64.0))*0.5+rand(floor(p/32.0))*0.3+rand(floor(p/16.0))*0.2);

gl_FragColor = vec4(vec3(b*0.6),1.0);

}

Now here is the vertex code:

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

//attribute vec4 in_Colour; // (r,g,b,a) unused in this shader.

//attribute vec2 in_TextureCoord; // (u,v) unused in this shader.

varying vec2 fragCoord;

void main()

{

vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);

gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;

fragCoord = in_Position.xy;

}

Here's the example file:

DOWNLOAD EXAMPLE

For a challenge you can convert my "Cool Lake"shader.

Shaders are for changing the color of pixels. It isn't used for anything more. Shaders can use textures or math to mix colors or blend them, but shaders can't easily be used for clickable or interactive objects in a scene. In general shaders are for recoloring or distorting. If you need textured shapes that can have gravity or motion (like rain for example), then you should use particles.

Particles are for moving and animated, textures or shapes that don't interact with objects or the scene. These are useful for effects like fire, rain, smoke, snow, etc. Blend modes can be applied to them also, so you can have additive blend (brightens the scene). However because particles aren't very interactive, then you may need objects.

Objects should be used for anything interactive. That means that it should be used for things that can collide with other objects and bounce for instance. These however should be used lightly, because the are often the slowest. You probably don't want to use this for rain that can collide unless you don't have much rain.

Shaders are designed for effects like scan lines, vignette or sepia tone. Particles are designed for rain, fire, smoke, etc. Objects are for anything interactive like a bouncing ball. Now this doesn't mean that you can't use shaders for interactive things, but the process is harder and may be slower.

]]>Uniforms are for getting values from outside of the shader, into the shader. Uniforms have many uses. One use is to take the coordinates of the mouse for example. Uniforms can be vectors, floats, float arrays, integers and integer arrays. Setting up uniforms is simple you just put "uniform" before your variables. Like this:

*uniform vec2 pos;*

We will add that code to our blur shader from the last tutorial. Put the code under the varying vectors. We will use these coordinates to tell where to center the radial blur.

We can use this code for the position:

varying vec4 v_vColour;

uniform vec2 pos;//x,y

const int Quality = 16;

void main()

{

vec4 Color;

float v;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range

Color += texture2D( gm_BaseTexture, v_vTexcoord*v+(pos)*(1.0-v));

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

}

This code is just like the last one except with the position uniform is instead of 0.5. Now in order to run this code, we must add the uniforms in GameMaker.

To set these variables in GameMaker, you must get the uniform id.

In the Create event of the control object, put this code:

*upos = shader_get_uniform(shader,"pos");*

That code sets variable "upos" to the id for the uniform "pos" from "shader" (which is the name of our shader). Then, under "shader_set(shader)" add "shader_set_uniform_f(shader,upos)".

"shader_set_uniform_f()" is for floats or vectors. There are types for float arrays, integers, integer arrays, matrices, and matrix arrays, but for now we'll stick with floats.

The whole code should look similar to this:

*shader_set(shader)*

*shader_set_uniform_f(upos,mouse_x/room_width,mouse_y/room_height)*

*draw_self()//any draw code should work*

*shader_reset()*

What that code does, is it applies the shader, sets the uniform pos in the shader to the mouse coordinates (the coordinates are shrunk to a 0 to 1 range), then draws the sprite with the shader applied. When we run the game we get this result:

In the Create event of the control object, put this code:

That code sets variable "upos" to the id for the uniform "pos" from "shader" (which is the name of our shader). Then, under "shader_set(shader)" add "shader_set_uniform_f(shader,upos)".

"shader_set_uniform_f()" is for floats or vectors. There are types for float arrays, integers, integer arrays, matrices, and matrix arrays, but for now we'll stick with floats.

The whole code should look similar to this:

What that code does, is it applies the shader, sets the uniform pos in the shader to the mouse coordinates (the coordinates are shrunk to a 0 to 1 range), then draws the sprite with the shader applied. When we run the game we get this result:

This is the result when the mouse is at the bottom center. Moving the mouse works perfectly.

Next we'll make a motion blur. We will use a loop to get 16 pixels in line and average then to get the blur. Doing this in code is rather simple with the knowledge you have gained so far.

Here is my code:

**varying vec2 v_vTexcoord;**

varying vec4 v_vColour;

uniform vec2 pos;//x,y

const int Quality = 16;

void main()

{

vec4 Color;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

Color += texture2D( gm_BaseTexture, v_vTexcoord+(0.5-pos)*i);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

}

Now what this does is it loops through a number times equal to quality setting "i" from 0 to 1 then it gets the position in a line based off of "pos". Here is a screenshot of the result:

Here is my code:

varying vec4 v_vColour;

uniform vec2 pos;//x,y

const int Quality = 16;

void main()

{

vec4 Color;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

Color += texture2D( gm_BaseTexture, v_vTexcoord+(0.5-pos)*i);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

}

Now what this does is it loops through a number times equal to quality setting "i" from 0 to 1 then it gets the position in a line based off of "pos". Here is a screenshot of the result:

And there you have a working motion blur shader! It takes in position between 0 and 1.

And finally lets make the most used blur shader. Lets make a gaussian blur shader.

And finally lets make the most used blur shader. Lets make a gaussian blur shader.

This is done just like the motion blur shader, but in all directions. Since you can put a for statement inside another for statement we will be one loop to loop through all the directions and the other will loop through magnitudes. That means we'll need another Quality constant. We will call that one Directions. We'll also add a constant float called "Pi" and set it to "6.28318530718" (pi times 2) and change "pos" to "size" and make it a 3D vector (vec3). We'll use "size" for the width, height and radius where width and height are the textures height and width. Now add another loop with a float called "d" and it's range will be from 0.0 to "Pi". Here's how the code should look:

**varying vec2 v_vTexcoord;**

varying vec4 v_vColour;

uniform vec3 size;//width,height,radius

const int Quality = 8;

const int Directions = 16;

const float Pi = 6.28318530718;//pi * 2

void main()

{

vec2 radius = size.z/size.xy;

vec4 Color = texture2D( gm_BaseTexture, v_vTexcoord);

for( float d=0.0;d<Pi;d+=Pi/float(Directions) )

{

for( float i=1.0/float(Quality);i<=1.0;i+=1.0/float(Quality) )

{

Color += texture2D( gm_BaseTexture, v_vTexcoord+vec2(cos(d),sin(d))*radius*i);

}

}

Color /= float(Quality)*float(Directions)+1.0;

gl_FragColor = Color * v_vColour;

}

This code sets radius to 0 to 1 sizes to match with the coordinates.

next it loops through the directions in radians with "d" (0 to "Pi") then loops through the magnitude with "i" (0 to 1). Each loop it gets the color of the texture at that pixel and finally it averages the total after the loops. Next change the "upos" to "usize" and "pos" to "size". Then when setting the uniform set it to 512, 512, and 16 (width, height and radius in pixels).

The final result should look like this:

varying vec4 v_vColour;

uniform vec3 size;//width,height,radius

const int Quality = 8;

const int Directions = 16;

const float Pi = 6.28318530718;//pi * 2

void main()

{

vec2 radius = size.z/size.xy;

vec4 Color = texture2D( gm_BaseTexture, v_vTexcoord);

for( float d=0.0;d<Pi;d+=Pi/float(Directions) )

{

for( float i=1.0/float(Quality);i<=1.0;i+=1.0/float(Quality) )

{

Color += texture2D( gm_BaseTexture, v_vTexcoord+vec2(cos(d),sin(d))*radius*i);

}

}

Color /= float(Quality)*float(Directions)+1.0;

gl_FragColor = Color * v_vColour;

}

This code sets radius to 0 to 1 sizes to match with the coordinates.

next it loops through the directions in radians with "d" (0 to "Pi") then loops through the magnitude with "i" (0 to 1). Each loop it gets the color of the texture at that pixel and finally it averages the total after the loops. Next change the "upos" to "usize" and "pos" to "size". Then when setting the uniform set it to 512, 512, and 16 (width, height and radius in pixels).

The final result should look like this:

Give yourself a pat on the back for completing three useful shaders!

Here are the examples:

DOWNLOAD RADIAL EXAMPLE

DOWNLOAD MOTION EXAMPLE

DOWNLOAD GAUSSIAN EXAMPLE

]]>Here are the examples:

DOWNLOAD RADIAL EXAMPLE

DOWNLOAD MOTION EXAMPLE

DOWNLOAD GAUSSIAN EXAMPLE

You will make radial blur. Motion blur and gaussian blur will be covered in part 2.

Shaders only process one pixel at a time. For bluring, we want the pixel to mix with the surrounding pixels. That is how we would achieve our blur. The easiest way to do this is to use "texture2D()" multiple times with different coordinates. We will make the radial blur first, because it's easier to understand. Radial blur is actually a form of motion blur, but in our case, motion blur will be side to side while radial will give an illusion of depth.

The radial blur effect we are creating will be produced by mixing the texture with different scaled versions of the texture. So the simplest way to do that is to scale the texture coordinates. Doubling the coordinates, makes the texture half the size, while halving it doubles the size. The reason to this is because the texture coordinates are in the 0 to 1 range so halving it would make the range 0 to 0.5 so, the texture is stretched to twice the size. So keep this in mind when scaling multiplying the texture coordinates. We will make our first radial blur have 10 sizes and blur between them.

We will multiply the textures coordinates by numbers less than 1 to make the textures slightly smaller. Then we'll average the values returned at those coordinates. Your code should look like this:

*vec4 Color = (texture2D( gm_BaseTexture, v_vTexcoord )*

+ texture2D( gm_BaseTexture, v_vTexcoord*0.99+0.5*0.01 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.98+0.5*0.02 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.97+0.5*0.03 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.96+0.5*0.04 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.95+0.5*0.05 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.94+0.5*0.06 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.93+0.5*0.07 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.92+0.5*0.08 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.91+0.5*0.09 )) * 0.1;

*gl_FragColor = Color * v_vColour;*

This code may look confusing, but what it does is rather simple. It gets the average of the different coordinates and centers them with the "+0.5" part. The shader looks like this:

We will multiply the textures coordinates by numbers less than 1 to make the textures slightly smaller. Then we'll average the values returned at those coordinates. Your code should look like this:

+ texture2D( gm_BaseTexture, v_vTexcoord*0.99+0.5*0.01 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.98+0.5*0.02 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.97+0.5*0.03 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.96+0.5*0.04 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.95+0.5*0.05 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.94+0.5*0.06 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.93+0.5*0.07 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.92+0.5*0.08 )

+ texture2D( gm_BaseTexture, v_vTexcoord*0.91+0.5*0.09 )) * 0.1;

This code may look confusing, but what it does is rather simple. It gets the average of the different coordinates and centers them with the "+0.5" part. The shader looks like this:

On the left, is the background before the shader, while on the one on the right is after. We will need some knowledge of integers and for statements before we can finish.

Integers have the fraction part. It is much like a float, but should always be without the fraction.

So if we set a float to 0 it would cause an error, but if we set and integer to 0, it would work as long as you don't mix it with floats. The only way to mix the different variable types is to use their functions (int() converts floats to ints and float() does the opposite). Here is an example:

*int i = 4;*

*float j = 0.5+float(i);*

That code would set i to 4 and j to 4.5. These are used in "for statements" which are particularly useful in blur shaders.

So if we set a float to 0 it would cause an error, but if we set and integer to 0, it would work as long as you don't mix it with floats. The only way to mix the different variable types is to use their functions (int() converts floats to ints and float() does the opposite). Here is an example:

That code would set i to 4 and j to 4.5. These are used in "for statements" which are particularly useful in blur shaders.

Constants are variables that are set once and can't be changed. They are constant and so you want to set them first. They are set outside of "void main()" in the format "const variabletype variable = value". An example could be

**const int Number = 48;**

That sets the integer "Number" to 48 as an unchanging constant.

That sets the integer "Number" to 48 as an unchanging constant.

So to start out this shader you'll need to know how to use a "for statement". The for statement repeats a certain code until specified to stop (they cannot repeat more than 255 times).

So platforms do not run loops well, so keep that in mind when making games. When you use them, you must start with defining a variable (most often an integer), then you check if the variable is less then the number of times we want it to repeat (for our example) , and lastly we add to our variable. Rather than using commas to separate the parts, we use semi-colons.

An example would look like this:

*for(int i = 0;i < 16;i++)*

*{*

*//code that you want to repeat*

*}*

Now what that does is it sets variable i to 0 (an integer), then checks if i is less than 16. If it is, it will add one to i (i++) and will repeat until i is equal to or greater than 16.

So platforms do not run loops well, so keep that in mind when making games. When you use them, you must start with defining a variable (most often an integer), then you check if the variable is less then the number of times we want it to repeat (for our example) , and lastly we add to our variable. Rather than using commas to separate the parts, we use semi-colons.

An example would look like this:

Now what that does is it sets variable i to 0 (an integer), then checks if i is less than 16. If it is, it will add one to i (i++) and will repeat until i is equal to or greater than 16.

Now we will use a for statement to blur more than 10 coordinates. We'll start by adding a constant called "Quality" (make sure it's before the "void main()") and set it to 16, then add this code:

**vec4 Color;**

float v;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range

Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

This code defines the vector "Color" and the float "v" (they are set to 0). Then the for statement repeats the code the number of times defined by "Quality". The final result of color is averaged by dividing the total by "Quality". Your full code should look something like this:

**varying vec2 v_vTexcoord;**

varying vec4 v_vColour;

const int Quality = 16;

void main()

{

vec4 Color;

float v;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range

Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

}

Quality can be changed to any value that suits your purpose. For smaller textures, use smaller numbers and for larger textures, use larger numbers.

DOWNLOAD EXAMPLE

Please share if these help you out!

]]>float v;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range

Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

This code defines the vector "Color" and the float "v" (they are set to 0). Then the for statement repeats the code the number of times defined by "Quality". The final result of color is averaged by dividing the total by "Quality". Your full code should look something like this:

varying vec4 v_vColour;

const int Quality = 16;

void main()

{

vec4 Color;

float v;

for( float i=0.0;i<1.0;i+=1.0/float(Quality) )

{

v = 0.9+i*0.1;//convert "i" to the 0.9 to 1 range

Color += texture2D( gm_BaseTexture, v_vTexcoord*v+0.5-0.5*v);

}

Color /= float(Quality);

gl_FragColor = Color * v_vColour;

}

Quality can be changed to any value that suits your purpose. For smaller textures, use smaller numbers and for larger textures, use larger numbers.

DOWNLOAD EXAMPLE

Please share if these help you out!

Here is the top part of the default vertex code:

*attribute vec3 in_Position; // (x,y,z)*

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

attribute vec4 in_Colour; // (r,g,b,a)

attribute vec2 in_TextureCoord; // (u,v)

//attribute vec3 in_Normal; // (x,y,z) unused in this shader.

attribute vec4 in_Colour; // (r,g,b,a)

attribute vec2 in_TextureCoord; // (u,v)

Below the attributes, we have varying vectors. They look like this:

*varying vec2 v_vTexcoord;*

varying vec4 v_vColour;

These are the vectors that get moved to fragment shader. You must have this code also in the fragment shader or else it will not receive these vectors. These are useful for getting the texture coordinates and vertex colors and sending them to the fragment shader. "void main()" is basically where the processing code goes. Functions, uniforms, (which I explain later) varying vectors, and attributes all must be done before "void main()" is used.

Finally, at the bottom of the shader you'll see these vectors being set to their corresponding attributes. Should appear like this:

*v_vColour = in_Colour;*

v_vTexcoord = in_TextureCoord;

This is the last step before you can access them in the fragment shader. Once they are set, they can then be used.

varying vec4 v_vColour;

These are the vectors that get moved to fragment shader. You must have this code also in the fragment shader or else it will not receive these vectors. These are useful for getting the texture coordinates and vertex colors and sending them to the fragment shader. "void main()" is basically where the processing code goes. Functions, uniforms, (which I explain later) varying vectors, and attributes all must be done before "void main()" is used.

Finally, at the bottom of the shader you'll see these vectors being set to their corresponding attributes. Should appear like this:

v_vTexcoord = in_TextureCoord;

This is the last step before you can access them in the fragment shader. Once they are set, they can then be used.

Attributes in GameMaker: Studio are vectors from outside of the shader which are for getting position, normals, color, and texture coordinate values. Position (in_Position) is a 3-dimensional vector which returns the X, Y, and Z coordinates of the current vertex. In 2D, Z is always 0. Next we have the normal (in_Normal) attribute. This is only for 3D so we won't be messing with it yet. Then we have the Color (in_Colour) attribute. Which I briefly explained was for image_blend or draw_set_color(). And finally we have the texture coordinates (in_TextureCoord). This is always a 2-dimensional vector because GameMaker doesn't support 3D textures. Attributes are only found in the vertex shader. They don't have any use in the fragment shader.

For our example, we will add a 2D varying vector (vec2) to both the vertex and fragment shaders, and we'll call it "v_vPosition" to follow the theme. That line of code should look like this:

*varying vec2 v_vPosition;*

Now, once we define "v_vPosition", we can use it. So at the bottom of the shader (within the brackets), we will set the shader to "in_Position.xy" to get the x and y components of the position attribute. We don't have to use attributes, but we will in this tutorial. It should look like this:

**v_vPosition = in_Position.xy;**

Now (assuming you put the varying code in the fragment shader also), we can use "v_vPosition" in the fragment shader. For now we'll try setting "gl_Fragment" to our new vector like so:

*gl_FragColor = texture2D( gm_BaseTexture, v_vTexcoord );*

*gl_FragColor *= vec4(vec3(v_vPosition.x/512.0),1.0);*

This will multiply the color to the horizontal position divided by 512 (to increase the color range). It also keeps alpha at 1 so we can see what we're doing. This was the result:

Now, once we define "v_vPosition", we can use it. So at the bottom of the shader (within the brackets), we will set the shader to "in_Position.xy" to get the x and y components of the position attribute. We don't have to use attributes, but we will in this tutorial. It should look like this:

Now (assuming you put the varying code in the fragment shader also), we can use "v_vPosition" in the fragment shader. For now we'll try setting "gl_Fragment" to our new vector like so:

This will multiply the color to the horizontal position divided by 512 (to increase the color range). It also keeps alpha at 1 so we can see what we're doing. This was the result:

Next I'll explain how to make custom functions. As I said earlier, functions are defined before the You start with what vector or float the function will output (in our case, we'll want a float).

Next you put the name of function, with the arguments. We'll name it "rand" with one 2D vector argument called "p" (position). You should have a similar result:

*float rand( vec2 position)*

Now we need to tell what it does. We'll add this code:

**float rand( vec2 p)**

{

return fract( cos( dot( p, vec2(5.237,6.378)))*8463.648);

}

"return" is put before the value you want to return. Here we return this random number generated using the position vector and math (fract gets the fraction part,cos is used for randomizing and dot is used to convert the position to a float). To test this function, we'll try this code:

**gl_FragColor = texture2D( gm_BaseTexture, v_vTexcoord );**

**gl_FragColor *= vec4( vec3( rand(v_vPosition)), 1.0);**

This code uses our random function with our position vector to generate noise:

Next you put the name of function, with the arguments. We'll name it "rand" with one 2D vector argument called "p" (position). You should have a similar result:

Now we need to tell what it does. We'll add this code:

{

return fract( cos( dot( p, vec2(5.237,6.378)))*8463.648);

}

"return" is put before the value you want to return. Here we return this random number generated using the position vector and math (fract gets the fraction part,cos is used for randomizing and dot is used to convert the position to a float). To test this function, we'll try this code:

This code uses our random function with our position vector to generate noise:

Now, for the perlin noise, we'll need to interpolate our noise. This actually quite simple. We'll first interpolate it horizontally. To do this we need another function. We'll use this code:

**float noise( vec2 p)**

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

return mix(x1,x2,fract(p.x));

}

"floor()" returns the number rounded down, while "ceil()" does the opposite. We do this because our function will use fractional positions. Our current rand function does not smooth fractional positions like we'll want. Now we make this 2-dimension (vertically too). We'll use this code:

*float noise( vec2 p)*

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

float top = mix(x1,x2,fract(p.x));

x1 = rand(vec2(floor(p.x),ceil(p.y)));

x2 = rand(vec2(ceil(p.x),ceil(p.y)));

float bottom = mix(x1,x2,fract(p.x));

return mix(top,bottom,fract(p.y));

}

This repeats the horizontal noise, but lower, and mixes the values based off the height.

Now after setting the color to noise instead of rand, we can test it! Here's my result:

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

return mix(x1,x2,fract(p.x));

}

"floor()" returns the number rounded down, while "ceil()" does the opposite. We do this because our function will use fractional positions. Our current rand function does not smooth fractional positions like we'll want. Now we make this 2-dimension (vertically too). We'll use this code:

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

float top = mix(x1,x2,fract(p.x));

x1 = rand(vec2(floor(p.x),ceil(p.y)));

x2 = rand(vec2(ceil(p.x),ceil(p.y)));

float bottom = mix(x1,x2,fract(p.x));

return mix(top,bottom,fract(p.y));

}

This repeats the horizontal noise, but lower, and mixes the values based off the height.

Now after setting the color to noise instead of rand, we can test it! Here's my result:

Looks closer, but we aren't done. We only need to repeat this at different scales (and smooth it).

First I would like to smooth it with "smoothstep()". "smoothstep()" is for cubic interpolation, so it will make it smoother. We'll put this around all the "fract()" functions to smooth them with the arguments 0.0 and 1.0 first, like this:

*float noise( vec2 p)*

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

float top = mix(x1,x2,smoothstep(0.0,1.0,fract(p.x)));

x1 = rand(vec2(floor(p.x),ceil(p.y)));

x2 = rand(vec2(ceil(p.x),ceil(p.y)));

float bottom = mix(x1,x2,smoothstep(0.0,1.0,fract(p.x)));

return mix(top,bottom,smoothstep(0.0,1.0,fract(p.y)));

}

**Finally, we'll repeat the noise like this:**

**float n = (noise(v_vPosition/16.0)*0.2 +noise(v_vPosition/32.0)*0.2 **

+noise(v_vPosition/64.0)*0.3 +noise(v_vPosition/128.0)*0.3 );

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

**This sets n to noise at different scales (the noise is between 0 and 1) then shows the "n", ignoring the texture. It should look like this:**

]]>First I would like to smooth it with "smoothstep()". "smoothstep()" is for cubic interpolation, so it will make it smoother. We'll put this around all the "fract()" functions to smooth them with the arguments 0.0 and 1.0 first, like this:

{

float x1 = rand(vec2(floor(p.x),floor(p.y)));

float x2 = rand(vec2(ceil(p.x),floor(p.y)));

float top = mix(x1,x2,smoothstep(0.0,1.0,fract(p.x)));

x1 = rand(vec2(floor(p.x),ceil(p.y)));

x2 = rand(vec2(ceil(p.x),ceil(p.y)));

float bottom = mix(x1,x2,smoothstep(0.0,1.0,fract(p.x)));

return mix(top,bottom,smoothstep(0.0,1.0,fract(p.y)));

}

+noise(v_vPosition/64.0)*0.3 +noise(v_vPosition/128.0)*0.3 );

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