Making fog with shaders?

Is there a way to make a fog effect with shaders, where the farther away a mesh is, the more fuzzy and less visible it is?

Could you specify a bit more, do you mean the device, or a part of the program

I think he means the picture gets less clear, into the distance, if the air is foggy - like in real life

This needs a shader that uses the distance to set the strength of the fuzzy effect. Unfortunately, I don’t know how to do that.

I am not sure how to use shaders yet but from what I know I made this code it does work like fog.
You could do the beautification of it if you want but here’s the concept. I have one question how can we post videos out here? BTW this ones for 3D I don’t think there can be fog for 2D. I copy pasted from shader demo and added a moving effect but I have no idea how it works.


--# Main
function setup()
    img = readImage("Cargo Bot:Codea Icon")
    w,h = img.width/2,img.height/2
    m = mesh()
    m.vertices = {vec3(-w,-h,0),vec3(-w,h,0),vec3(w,-h,0),
                  vec3(-w,h,0),vec3(w,-h,0),vec3(w,h,0)}
    m.texCoords = {vec2(0,0),vec2(0,1),vec2(1,0),vec2(0,1),vec2(1,0),vec2(1,1)}
    m.texture = img
    w,h = WIDTH/2,HEIGHT/2
    fogg = readImage("Platformer Art:Cloud 3")
    fog = mesh()
    fog.vertices = {vec2(0,0),vec2(0,h),vec2(w,0),vec2(w,0),vec2(0,h),vec2(w,h)}
    fog.texCoords = {vec2(0,0),vec2(0,1),vec2(1,0),vec2(1,0),vec2(0,1),vec2(1,1)}
    fog.texture = fogg
    Ex,Ey,Ez = 0,0,0
    parameter.watch("dist")
end

function draw()
    --fog,Position = vec3(0,0,-2000)
    --ourPosition = vec3(Ex,Ey,Ez)
    distance = vec3(Ex,Ey,Ez) - vec3(0,0,-2000)
    dist = distance:len()/8
    background(0, 0, 0, 255)
    fill(255)
    perspective(45,WIDTH/HEIGHT)
    Ez = Ez-5
    camera(Ex,Ey,Ez,0,0,-2000,0,1,0)
    pushMatrix()
    translate(0,0,-2000)
    m:draw()
    popMatrix()
    ortho()
    viewMatrix(matrix()) 
    fog:setColors(255,255,255,dist)
    pushMatrix()
    translate(WIDTH-200,HEIGHT/2)
    rotate(180)
    fog:draw()
    popMatrix()
    pushMatrix()
    translate(WIDTH/2-200,HEIGHT/2)
    fog:draw()
    popMatrix()

end

Or an Easier method. I think this one looks better if you don’t want to put much effort make the fog look better and you know more foggy with patches here and there. But I don’t know how to make the mesh blurry with distance.


--# Main
function setup()
    img = readImage("Cargo Bot:Codea Icon")
    w,h = img.width/2,img.height/2
    m = mesh()
    m.vertices = {vec3(-w,-h,0),vec3(-w,h,0),vec3(w,-h,0),
                  vec3(-w,h,0),vec3(w,-h,0),vec3(w,h,0)}
    m.texCoords = {vec2(0,0),vec2(0,1),vec2(1,0),vec2(0,1),vec2(1,0),vec2(1,1)}
    m.texture = img
    m.shader = shader("Effects:Ripple")
    Ex,Ey,Ez = 0,0,0
end

function draw()
    --fog,Position = vec3(0,0,-2000)
    --ourPosition = vec3(Ex,Ey,Ez)
    distance = vec3(Ex,Ey,Ez) - vec3(0,0,-2000)
    dist = distance:len()/8
    background(0, 0, 0, 255)
    fill(255)
    perspective(45,WIDTH/HEIGHT)
    Ez = Ez-5
    camera(Ex,Ey,Ez,0,0,-2000,0,1,0)
    pushMatrix()
    translate(0,0,-2000)
    m:setColors(255,255,255,255-dist)
    m.shader.time = ElapsedTime
    m.shader.freq = dist/600
    m:draw()
    popMatrix()
end

No, I had double pasted by mistake so the code got messed up I edited it and I couldn’t use the shader effect in first code where there was fog so I wrote it in the second code. Shader effect is only in second code. And how can I post a video out here?

I think you left out the fog class, and the shader

iif you record it in Codea and save it to your photo album, you can post it to Youtube straight from there

But how should I post it here on the forum?

YouTube will give you a link to your video which you can post on the forum

The way I do it is to upload the video to Youtube from the photo library, then when I’m asked if I want I share it, I choose email, which gives me a draft email with the link in it, then I copy the URL out of there.

Thanks Saurabh!

So, it appears that shaders are unique to each individual mesh.

That means you couldn’t have a generic “fog shader” in a certain location, and any mesh that passes behind it looks like it’s in fog. Right?

Yeah that’s the way I know about. Hope it helped.

Guess what, my first shader - for fog

There is only one setting, the z distance at which everything disappears. This is used in DrawMesh to mix the normal image and my fog image (mostly white). A random number is used to create a bit of swirl

The shader mixes the normal image and fog image together, but only for pixels which are not blank.

--# Main

function setup()
    vanishZ=800 --z value at which fog makes things invisible
    fog=CreateFog(128,10,1000)
    m={}
    m[1] = createImageMesh("Planet Cute:Character Princess Girl")
    m[2] = createImageMesh("Planet Cute:Character Boy")
    m[3] = createImageMesh("Planet Cute:Character Pink Girl")
    count=0
end

function CreateFog(s)
    local img=image(s,s)
    setContext(img)   
    fill(220,220,220,240)
    rect(1,1,s,s)
    setContext()
    return img
end
function createImageMesh(i,d)
    local img = readImage(i)
    local w,h = img.width/2,img.height/2
    local m = mesh()
    m.vertices = {vec3(-w,-h,0),vec3(-w,h,0),vec3(w,-h,0),
                  vec3(-w,h,0),vec3(w,-h,0),vec3(w,h,0)}
    m.texCoords = {vec2(0,0),vec2(0,1),vec2(1,0),vec2(0,1),vec2(1,0),vec2(1,1)}
    m.texture = img 
    m.shader= shader(fogShader.vertexShader, fogShader.fragmentShader)
    --m.shader.texture2=fog
    return m
end

function draw()
    count=count+1
    background(220)
    fill(255)
    perspective(45,WIDTH/HEIGHT)
    camera(0,200,200,0,0,-800,0,1,0)
    drawMesh(1,-100,200+count/3)
    drawMesh(2,0,500-count/3)
    drawMesh(3,150,800-count/3)
end

function drawMesh(i,x,z)
    pushMatrix()
    translate(x,0,-z)
    m[i].shader.texture2=fog
    m[i].shader.mixAmount=math.min(1,z/vanishZ+math.random()*.05)
    m[i]:draw()
    popMatrix()
end

--# Fog

fogShader = {
vertexShader = [[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;

    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}

]],
fragmentShader = [[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//This texture will be rendered atop the first
uniform lowp sampler2D texture2;

//This is the amount to mix the two textures
uniform float mixAmount;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col1 = texture2D( texture, vTexCoord );
    lowp vec4 col2 = texture2D( texture2, vTexCoord );

    if (col1.a>0.)
    gl_FragColor = mix(col1, col2, mixAmount);
else gl_FragColor = col1;
}

]]}

That’s awesome @Ignatz!!

@ignatz that is really cool.

Actually, it is just the code for the blend (2 images together) shader, with a one line change (3rd from the bottom above). Instead of blending the two images for every pixel, it only does it if the alpha is non zero (so it only puts fog on the used part of your images, not on the transparent pixels around them, otherwise you get gray rectangles).

Then all you need to do is vary the mix of the two images (which the shader already let you do) in your draw function, so the fog is greater with distance.

So it’s not actually too difficult (or else I couldn’t have done it). I will write this up soon, because I’m starting to think mere mortals like me can maybe write simple shaders. Maybe.

@Ignatz a write up would be great, shaders scare me. Heck your 3d stuff is pushing it for me :slight_smile:

Yeah, all this graphics stuff is a bit scary. But like most things, if you keep working at it, it gets easier.

Darn, that’s awesome

Here’s a shader that flips the image horizontally depending on the parameter value

--# Main
function setup()
    parameter.boolean("Flip",false)
    m = createImageMesh("Planet Cute:Character Princess Girl")
end

function createImageMesh(i,d)
    local img = readImage(i)
    local w,h = img.width/2,img.height/2
    local m = mesh()
    m.vertices = {vec3(-w,-h,0),vec3(-w,h,0),vec3(w,-h,0),
                  vec3(-w,h,0),vec3(w,-h,0),vec3(w,h,0)}
    m.texCoords = {vec2(0,0),vec2(0,1),vec2(1,0),vec2(0,1),vec2(1,0),vec2(1,1)}
    m.texture = img 
    m.shader= shader(flipShader.vertexShader, flipShader.fragmentShader)
    m.shader.flipper=0
    return m
end

function draw()
    background(220)
    fill(255)
    perspective(45,WIDTH/HEIGHT)
    camera(0,200,200,0,0,-400,0,1,0)
    pushMatrix()
    translate(0,0,-300)
    if Flip==true then m.shader.flip=1 else m.shader.flip=0 end
    m:draw()
    popMatrix()
end

function drawMesh(i,x,z)
    
end

--# Flip

flipShader = {
vertexShader = [[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
uniform float flip;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    if (flip == 1.) 
        vTexCoord = vec2(1.-texCoord.x,texCoord.y);
    else
        vTexCoord = texCoord;

    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}

]],
fragmentShader = [[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//uniform float flip;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col1 = texture2D( texture, vTexCoord );
    gl_FragColor = col1;
}

]]}

I am writing a post about the little I know about shaders, I should have it done in the next day with several examples like this