Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Free-to-Use Shaders

in Shaders Posts: 160

Here I'll post simple or complex shaders for those who want to learn from them or those who want to use them. Do what you like with them. Feedback is welcome. Each shader will be accompanied with an example project that uses it.

Comments

  • edited August 2017 Posts: 160

    Sky Gradient

    This is a shader that produces a gradient that looks very similar to the sky and can be used for less boring backgrounds.
    Difficulty: This shader may be confusing for beginners
    Shader

    shader([[ --vertex shader
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
     vColor = color;
     vTexCoord = texCoord;
    
     gl_Position = modelViewProjection * position;
    }]],
    [[ --fragment shader
    precision highp float;
    uniform lowp sampler2D texture;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
        lowp vec4 col;
        lowp vec4 highCol = vec4(0.352,0.745,1,1); //90,190,255
        lowp vec4 lowCol = vec4(0.705,0.862,1,1); //180, 220, 255
            //lowCol = vec4(0.1,0.1,0.1,1); highCol = vec4(0.95,0.95,0.95,1);
        highp float size = 1.9;
        highp float dis = distance(vTexCoord,vec2(0.5,size * -1.0 + 0.40));
        highp float blur = 0.3;
        if (dis < size + blur) {
            lowp float min = size;
            if (dis > min) {
                lowp float bri = (dis - min) / (blur);
                lowp vec4 final = lowCol * (1. - bri) + highCol * bri;
                final.a = 1.;
                col = final;
            }
            else col = lowCol;
        }
        else {col = highCol;}
        gl_FragColor = col;
    }]])
    

    Example Project

    --# Main
    displayMode(FULLSCREEN) -- This function sets it to Fullscreen
    function setup()
        BG = mesh()
        BG.shader = shader([[
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
     vColor = color;
     vTexCoord = texCoord;
    
     gl_Position = modelViewProjection * position;
    }]],[[
    precision highp float;
    uniform lowp sampler2D texture;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
        lowp vec4 col;
        lowp vec4 highCol = vec4(0.352,0.745,1,1); //90,190,255
        lowp vec4 lowCol = vec4(0.705,0.862,1,1); //180, 220, 255
            //lowCol = vec4(0.1,0.1,0.1,1); highCol = vec4(0.95,0.95,0.95,1);
        highp float size = 1.9;
        highp float dis = distance(vTexCoord,vec2(0.5,size * -1.0 + 0.40));
        highp float blur = 0.3;
        if (dis < size + blur) {
            lowp float min = size;
            if (dis > min) {
                lowp float bri = (dis - min) / (blur);
                lowp vec4 final = lowCol * (1. - bri) + highCol * bri;
                final.a = 1.;
                col = final;
            }
            else col = lowCol;
        }
        else {col = highCol;}
        gl_FragColor = col;
    }]])
        BG:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
    end
    
    -- This function gets called once every frame
    function draw()
        BG:draw()
    end
    
    
  • Posts: 160

    Rainbow Circle

    This shader produces a circle with a gradient that goes from red - yellow - green - turquoise - blue - purple and is very easy to use.
    Difficulty: This shader should only be slightly difficult for beginners to understand
    Shader

    shader([[ -- vertex shader (nothing changed)
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
     vColor = color;
     vTexCoord = texCoord;
    
     gl_Position = modelViewProjection * position;
    }
    ]],
    [[ -- fragment shader
    precision highp float;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    vec4 mixCol(vec4 C1, vec4 C2, float i) //To make the mixing easier, We'll have this function
    { // C1 is the 1st colour, C2 is the 2nd colour, i is a float for interpolation
        return C1 * (1.0 - i) + C2 * i;
    }
    
    void main()
    {
        highp vec4 col;
        lowp float dis = distance(vTexCoord,vec2(0.5,0.5)); //get the distance from the texCoord to the center
        if (dis < 0.5) { //0.5 is the size of the circle. It's set to take up the whole rectangle
            //To make a gradient that transitions through each colour of the rainbow, we'll actually need to make
            //5 gradients:
            //red -> yellow, yellow -> green, green -> turqoise, turquoise -> blue, blue -> purple
            if (vTexCoord.y < 0.2) col = mixCol(vec4(1,0,0,1),vec4(1,1,0,1),vTexCoord.y/0.2); //red to yellow
            else if (vTexCoord.y < 0.4) col = mixCol(vec4(1,1,0,1),vec4(0,1,0,1),(vTexCoord.y - 0.2)/0.2);//yel to gre
            else if (vTexCoord.y < 0.6) col = mixCol(vec4(0,1,0,1),vec4(0,1,1,1),(vTexCoord.y - 0.4)/0.2);//gre to tur
            else if (vTexCoord.y < 0.8) col = mixCol(vec4(0,1,1,1),vec4(0,0,1,1),(vTexCoord.y - 0.6)/0.2);//tur to blu
            else col = mixCol(vec4(0,0,1,1),vec4(1,0,1,1),(vTexCoord.y - 0.8)/0.2); // blue to purple
        }
        else {col = vec4(0,0,0,0);}
        gl_FragColor = col;
    }
    ]])
    

    Example Project

    --# Main
    function setup()
        width,height = HEIGHT,HEIGHT
    
        circleM = mesh()
        circleM:addRect(WIDTH/2,HEIGHT/2,width,height) -- add a square to the mesh
        circleM.shader = shader(RBCircle.vertexShader,RBCircle.fragmentShader)
    end
    
    function draw()
        background(0)
        circleM:draw()
    end
    
    function touched(t)
        if t.state ~= ENDED then
            width,height = width + t.deltaX*2, height + t.deltaY*2
            circleM:setRect(1,WIDTH/2,HEIGHT/2,width,height)
        end
    end
    
    RBCircle = {
    vertexShader = [[
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
     vColor = color;
     vTexCoord = texCoord;
    
     gl_Position = modelViewProjection * position;
    }
    ]],
    fragmentShader = [[
    precision highp float;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    vec4 mixCol(vec4 C1, vec4 C2, float i) //To make the mixing easier, We'll have this function
    { // C1 is the 1st colour, C2 is the 2nd colour, i is a float for interpolation
        return C1 * (1.0 - i) + C2 * i;
    }
    
    void main()
    {
        highp vec4 col;
        lowp float dis = distance(vTexCoord,vec2(0.5,0.5)); //get the distance from the texCoord to the center
        if (dis < 0.5) { //0.5 is the size of the circle. It's set to take up the whole rectangle
            //To make a gradient that transitions through each colour of the rainbow, we'll actually need to make
            //5 gradients:
            //red -> yellow, yellow -> green, green -> turqoise, turquoise -> blue, blue -> purple
            if (vTexCoord.y < 0.2) col = mixCol(vec4(1,0,0,1),vec4(1,1,0,1),vTexCoord.y/0.2); //red to yellow
            else if (vTexCoord.y < 0.4) col = mixCol(vec4(1,1,0,1),vec4(0,1,0,1),(vTexCoord.y - 0.2)/0.2);//yel to gre
            else if (vTexCoord.y < 0.6) col = mixCol(vec4(0,1,0,1),vec4(0,1,1,1),(vTexCoord.y - 0.4)/0.2);//gre to tur
            else if (vTexCoord.y < 0.8) col = mixCol(vec4(0,1,1,1),vec4(0,0,1,1),(vTexCoord.y - 0.6)/0.2);//tur to blu
            else col = mixCol(vec4(0,0,1,1),vec4(1,0,1,1),(vTexCoord.y - 0.8)/0.2); // blue to purple
        }
        else {col = vec4(0,0,0,0);}
        gl_FragColor = col;
    }
    ]]
    }
    
  • edited August 2017 Posts: 160

    Green Screen

    This shader can be used to create a very simple green screen that compares a given colour to each pixel in a photo, and replaces the ones that are too similar
    Difficulty: This shader should be fairly easy for beginners
    Shader Inputs
    sens: float (number), determines the sensitivity of the green screen
    texture: sampler2D (image), the main photo (normally the CAMERA)
    overTex: sampler2D (image), the photo in the background
    sample: vec4 (color), the colour of the pixels that will be replaced
    inactive: bool (boolean), while true, the pixels of texture are not changed
    Shader

    shader([[uniform mat4 modelViewProjection; -- vertex shader
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main() { vColor = color; vTexCoord = texCoord; gl_Position = modelViewProjection * position; }]],
    [[ -- fragment shader
    precision highp float; -- This sets the default precision of all float variables
    
    uniform lowp float sens;
    uniform lowp sampler2D texture;
    uniform lowp sampler2D overTex;
    uniform lowp vec4 sample;
    uniform bool inactive;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    void main()
    {
        lowp vec4 col = texture2D( texture, vTexCoord ); -- get the pixel of texture at vTexCoord
        if (inactive == false && col.r > sample.r - sens && col.r < sample.r + sens && col.g > sample.g - sens && col.g < sample.g + sens && col.b < sample.b + sens && col.b > sample.b - sens) {
            col = texture2D( overTex, vTexCoord ); -- get the pixel colour of overTex at vTexCoord
        }
        gl_FragColor = col;
    }
    ]])
    

    Example Project

    --# Main
    
    function setup()
        info = ""
        infoTimer = 0
        sampling = true
        cameraSource(CAMERA_FRONT)
        m = mesh()
        m:addRect(WIDTH/2,HEIGHT/2,0,0)
        m.texture = CAMERA -- 1920 x 1080
        m.shader = shader(Ghost.v,Ghost.f)
        m.shader.inactive = true
        parameter.boolean("Camera_Front",false,function(b)
            cameraSource((b and CAMERA_FRONT) or CAMERA_BACK)
        end)
    
        -- Hooray! Variables for playing with! : )
        replaceTexture = readImage("SpaceCute:Background") -- The texture that will replace certain pixels. (Will be stretched to fit the screen)
        sensitivity = 0.2 -- How different a pixels colour can be from the sample colour before being replaced
    end
    
    function draw()
        background(40, 40, 50)
        camW,camH = spriteSize(CAMERA)
        if CurrentOrientation == LANDSCAPE_LEFT or CurrentOrientation == LANDSCAPE_RIGHT then
            m:setRect(1,0,0,camW*(WIDTH/camW),camH*(WIDTH/camW))
            else
            m:setRect(1,0,0,camW*(HEIGHT/camH),camH*(HEIGHT/camH))
        end
        translate(WIDTH/2,HEIGHT/2)
        noSmooth()
        m:draw()
        if sampling then
            stroke(255, 255, 255, 255)
            strokeWidth(5)
            if sampleC then -- sampleC is the variable that holds the sampled colour
                fill(sampleC)
                else
                noFill()
            end
            ellipse(0,0,30)
            line(-110,0,-10,0)
            line(10,0,110,0)
            line(0,-110,0,-10)
            line(0,10,0,110)
            fill(255)
            fontSize(20)
            smooth()
            text("Tap the center of the screen to sample the colour",0,HEIGHT/2 - 30)
            text("Tap outside of the center to activate the shader",0,HEIGHT/-2 + 30)
            else
            smooth()
            text("Tap anywhere to return to the colour sampler",0,HEIGHT/-2 + 30)
        end
        if infoTimer > 0 then -- This is responsible for the blue text that appears in the center of the screen.
            infoTimer = infoTimer - DeltaTime
            fill(0,200,255)
            fontSize(30)
            text(info,0,-200)
        end
    end
    
    function touched(t)
        if t.state == 0 then
            if sampling and ((t.x - WIDTH/2)^2 + (t.y - HEIGHT/2)^2)^0.5 < 180 then
                if not sampleC then
                    info = "This colour will now be used in the shader"
                    infoTimer = 4
                end
    
                local samCam = image(WIDTH,HEIGHT)
                pushStyle()
                smooth()
                setContext(samCam)
                m:draw()
                setContext()
                popStyle()
                local all = {r=0,g=0,b=0,c=0}
                for x = WIDTH//2 - 10, WIDTH//2 + 10 do
                    for y = HEIGHT//2 - 10, HEIGHT//2 + 10 do
                        if ((x - WIDTH//2)^2 + (y - HEIGHT//2)^2)^0.5 < 10 then--if this pixel is in a 10 pixel radius
                            local r,g,b = samCam:get(x,y)
                            all.r = all.r + r
                            all.g = all.g + g
                            all.b = all.b + b
                            all.c = all.c + 1 
                        end
                    end
                end
                all.r,all.g,all.b = all.r/all.c,all.g/all.c,all.b/all.c
                sampleC = color(all.r,all.g,all.b,255)
    
                samCam = nil
                all = nil
                collectgarbage()
                elseif sampleC then
                sampling = not sampling
                if sampling then
                    m.shader.inactive = true
                    else
                    m.shader.sens = sensitivity
                    m.shader.inactive = false
                    m.shader.overTex = replaceTexture
                    m.shader.sample = sampleC
                end
                else
                info = "You need to sample a colour for the shader, first"
                infoTimer = 4
            end
        end
    end
    
    Ghost = {
    v = [[uniform mat4 modelViewProjection;
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main() { vColor = color; vTexCoord = texCoord; gl_Position = modelViewProjection * position; }]],
    f = [[
    precision highp float;
    
    uniform lowp float sens;
    uniform lowp sampler2D texture;
    uniform lowp sampler2D overTex;
    uniform lowp vec4 sample;
    uniform bool inactive;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    void main()
    {
        lowp vec4 col = texture2D( texture, vTexCoord );
        if (inactive == false && col.r > sample.r - sens && col.r < sample.r + sens && col.g > sample.g - sens && col.g < sample.g + sens && col.b < sample.b + sens && col.b > sample.b - sens) {
            col = texture2D( overTex, vTexCoord );
        }
        gl_FragColor = col;
    }
    ]]
    }
    
  • Posts: 160

    Circular Textures

    This shader takes any texture and draws only pixels that are in a circle, creating a circular texture
    Difficulty: This shader is very easy to follow and is recommended for beginners
    Shader inputs
    texture: sampler2D (image), the texture to make circular
    circleSize: float (number), the distance a pixel must be from the center before being removed
    Shader

    CircleS = {
    shader([[ -- vertex shader
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
        vColor = color;
        vTexCoord = texCoord;
        gl_Position = modelViewProjection * position;
    }
    ]],
    [[ -- fragment shader
    precision highp float;
    
    uniform lowp sampler2D texture;
    uniform lowp float circleSize;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    void main()
    {
        highp vec4 col;
        lowp float dis = distance(vTexCoord,vec2(0.5,0.5)); //get the distance from the texCoord to the center
    
        if (dis < circleSize) { //circleSize is the size of the circle.
            //Turning a rectangular texture into a circle won't actually be that hard. All we have to do is remove
            //the pixels that are distant from the center. It's really that simple!
            col = texture2D(texture, vTexCoord); //sample the pixel in texture at the position vTexCoord
        }
        else {col = vec4(0,0,0,0);} //remove this pixel
        gl_FragColor = col;
    }
    ]])
    

    Example Project

    --# Main
    function setup()
        width,height = HEIGHT*0.9,HEIGHT*0.9 -- the initial width and height of the rect
        textures = {
        readImage("Cargo Bot:Codea Icon"),
        readImage("Platformer Art:Block Grass"),
        readImage("Cargo Bot:Background Fade"),
        readImage("Tyrian Remastered:Brown Capsule 1")
        }
    
        circleM = mesh()
        circleM:addRect(WIDTH/2,HEIGHT/2,width,height) -- add a square to the mesh
        circleM.texture = textures[1]
        circleM.shader = shader(CircleS.vertexShader,CircleS.fragmentShader)
        circleM.shader.circleSize = 1
        parameter.number("Circle_Size",0,1,0.5)
        parameter.integer("Texture",1,#textures)
    end
    
    function draw()
        background(255, 130, 0, 255)
        circleM.texture = textures[Texture] -- update the meshes texture
        circleM.shader.circleSize = Circle_Size -- update the shader's uniform, circleSize
        if circleM.texture.width*circleM.texture.height < 6400 then
            noSmooth()
            else
            smooth()
        end
        circleM:draw()
    end
    
    function touched(t)
        if t.state ~= ENDED then
            width,height = width + t.deltaX*2, height + t.deltaY*2
            circleM:setRect(1,WIDTH/2,HEIGHT/2,width,height)
        end
    end
    
    -- shaders below
    CircleS = {
    vertexShader = [[
    uniform mat4 modelViewProjection;
    
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main()
    {
        vColor = color;
        vTexCoord = texCoord;
        gl_Position = modelViewProjection * position;
    }
    ]],
    fragmentShader = [[
    precision highp float;
    
    uniform lowp sampler2D texture;
    uniform lowp float circleSize;
    
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    
    void main()
    {
        highp vec4 col;
        lowp float dis = distance(vTexCoord,vec2(0.5,0.5)); //get the distance from the texCoord to the center
    
        if (dis < circleSize) { //circleSize is the size of the circle.
            //Turning a rectangular texture into a circle won't actually be that hard. All we have to do is remove
            //the pixels that are distant from the center. It's really that simple!
            col = texture2D(texture, vTexCoord); //sample the pixel in texture at the position vTexCoord
        }
        else {col = vec4(0,0,0,0);} //remove this pixel
        gl_FragColor = col;
    }
    ]]
    }
    
  • Posts: 154

    @Kolosso, this is great!
    I like that you also include working examples that are easy to "Paste into new project" - very nice touch.

  • Posts: 160

    Thanks, @juce! :smiley:

  • edited January 31 Posts: 160

    This thread is a little old, but I just wanted to post a few more of these.

    Voronoi

    This shader creates a voronoi pattern that can have many uses. The example project uses a modified version of the shader to use the pattern as a displacement map, for example.
    Difficulty: This shader may be more difficult for beginners.
    Shader Inputs
    aspect: _float (number)
    , This is the aspect ration of the rectangle.
    scale: float (number), This scales the pattern. 1.0 is one cell, so a scale of 20.0 will show 20.0 cells.
    panX: float (number), This pans the pattern left or right.
    panY: float (number), This pans the pattern up or down.
    Shader

    shader([[uniform mat4 modelViewProjection; // vertex shader
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main() { vColor = color; vTexCoord = texCoord; gl_Position = modelViewProjection * position; }]],
    [[ // fragment shader
    //Default precision qualifier
    precision highp float;
    
    // aspect ratio of rectangle (width/height)
    uniform highp float aspect;
    
    // scale the pattern
    uniform highp float scale;
    
    // pan the pattern
    uniform highp float panX;
    uniform highp float panY;
    
    //The interpolated vertex color for this fragment
    varying lowp vec4 vColor;
    
    //The interpolated texture coordinate for this fragment
    varying highp vec2 vTexCoord;
    
    // function R22: Returns random vec2 in range 0-1 with vec2 seed.
    vec2 R22(vec2 n) {
        highp vec3 a = fract(3.3 + n.xyx * vec3(123.34, 234.34, 345.65));
        a += dot(a, a + 34.45);
        return fract(vec2(a.x * a.y, a.y * a.z));
    }
    // function voronoi: Returns the brightness of the given point (uv) on a voronoi pattern.
    //     Requires:
    //         -function R22
    float voronoi(highp vec2 uv) {
        lowp vec2 lv = fract(uv); // local x,y coord in cell
        mediump float md = 3.0; // distance to nearest point will be stored in md
        for (float x = -1.0; x <= 1.0; x++) { // loop from -1 to +1
            for (float y = -1.0; y <= 1.0; y++) { // loop from -1 to +1
                lowp vec2 o = vec2(x,y); // cell offset
                highp vec2 id = floor(uv) + o; // id for this cell
                mediump vec2 p = R22(id) + o; // local coord of point in cell
                mediump float d = length(lv - p);
                if (d < md) { // update nearest distance
                    md = d;
                }
            }
        }
        return md;
    }
    void main()
    {  highp vec2 uv = vTexCoord * scale;
        uv.x += panX;
        uv.y += panY;
        uv.x *= aspect; // correct for aspect ratio
        gl_FragColor = vec4(vColor.rgb * voronoi(uv),1.0); // multiply voronoi with vColor
    }]])
    

    Example Project

    -- Shaders - Voronoi
    
    function setup()
        print("Hello Voronoi!")
    
        -- Create a new mesh that will cover the screen
        m = mesh()
        m:addRect(WIDTH/2,HEIGHT/2,WIDTH*0.7,HEIGHT*0.7)
        m:setColors(255,255,255)
    
        parameter.boolean("Use_As_Displacement_Map")
        m.texture = readImage("Environments:Night Up") -- image to displace
    
        parameter.number("Displacement_Amount", 0, 1, 0.1) -- severity of the displacement
    
        m.shader = shader(voronoi.vert,voronoi.frag)
        m.shader.aspect = WIDTH/HEIGHT -- input the aspect ratio of the rect
        m.shader.scale = 15.0 -- scale the pattern
    end
    
    function draw()
        background(40, 40, 50)
    
        m.shader.panX = ElapsedTime * 0.6
        m.shader.panY = ElapsedTime * 0.1
        m.shader.displace = Use_As_Displacement_Map
        m.shader.displaceAmount = Displacement_Amount
    
        m:draw()
    end
    
    voronoi = {
    vert = [[
    //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;
    }
    ]],
    frag = [[
    //Default precision qualifier
    precision highp float;
    
    // texture to displace
    uniform lowp sampler2D texture;
    
    // aspect ratio of rectangle (width/height)
    uniform highp float aspect;
    
    // scale the pattern
    uniform highp float scale;
    
    // pan the pattern
    uniform highp float panX;
    uniform highp float panY;
    
    // displace texture boolean
    uniform bool displace;
    
    // displace amount
    uniform mediump float displaceAmount;
    
    //The interpolated vertex color for this fragment
    varying lowp vec4 vColor;
    
    //The interpolated texture coordinate for this fragment
    varying highp vec2 vTexCoord;
    
    // function R22: Returns random vec2 in range 0-1 with vec2 seed.
    vec2 R22(vec2 n) {
        highp vec3 a = fract(3.3 + n.xyx * vec3(123.34, 234.34, 345.65));
        a += dot(a, a + 34.45);
        return fract(vec2(a.x * a.y, a.y * a.z));
    }
    
    // function voronoi: Returns the brightness of the given point (uv) on a voronoi pattern.
    //     Requires:
    //         -function R22
    float voronoi(highp vec2 uv) {
        lowp vec2 lv = fract(uv); // local x,y coord in cell
        mediump float md = 3.0; // distance to nearest point will be stored in md
        for (float x = -1.0; x <= 1.0; x++) { // loop from -1 to +1
            for (float y = -1.0; y <= 1.0; y++) { // loop from -1 to +1
                lowp vec2 o = vec2(x,y); // cell offset
                highp vec2 id = floor(uv) + o; // id for this cell
                mediump vec2 p = R22(id) + o; // local coord of point in cell
                mediump float d = length(lv - p);
                if (d < md) { // update nearest distance
                    md = d;
                }
            }
        }
        return md;
    }
    
    void main()
    {
        highp vec2 uv = vTexCoord * scale;
        uv.x += panX;
        uv.y += panY;
        uv.x *= aspect; // correct for aspect ratio
    
        mediump float v = voronoi(uv); // get voronoi value for this fragment
    
        lowp vec3 col;
        if (displace)
            col = vColor.rgb * texture2D(texture, fract(vTexCoord + v * displaceAmount)).rgb;
        else
            col = vec3(v * vColor.rgb);
        gl_FragColor = vec4(col,1.0); //pass final color
    }
    ]]
    }
    
  • edited January 31 Posts: 160

    3D Sky Dome (but not really a dome)

    I was getting tired of the fact that Craft was the only answer for getting an easy 3D sky. That's why I made this shader. It works similarly to the Craft sky, except with one extra color input to control the gradient easier. ;)
    The shader uses raytracing to draw a 3D sky dome. (onto a 2D rectangle) The example below uses it in a 3D scene.
    Difficulty: You might want to learn the basics of raytracing before trying to understand this shader.
    Shader Inputs
    aspect: _float (number)
    , This is the aspect ratio of the screen
    zoom: float (number), This is the fov of the camera. The lower the value, the closer the FOV gets to 180 degrees. The higher the value, the fewer degrees. 0.5 is 90 degrees of FOV. 1.0 is 45 degrees of FOV. Note that this is on a logarithmic scale.
    lookAt: vec2 (vec2), This is the direction the camera is facing. Since the sky looks the same, no matter if you look left or right; I've only given it 2 dimensions. X is forward and Y is up. Note that this vec2 needs to be normalized.
    horizon: vec4 (color), This is the color of the horizon
    sky: vec4 (color), This is the color of the top of the sky
    midSky: vec4 (color)_, This is the color between the top of the sky and the horizon.
    ground: vec4 (color)_, This is the color of the bottom of the sky.
    Shader

    shader([[uniform mat4 modelViewProjection; // vertex shader
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main() { vColor = color; vTexCoord = texCoord; gl_Position = modelViewProjection * position; }]],
    [[ // fragment shader
    precision highp float;
    // camera zoom
    uniform mediump float zoom;
    // aspect ratio of the screen (WIDTH/HEIGHT)
    uniform mediump float aspect;
    // normalized look at vector
    uniform lowp vec2 lookAt;
    
    // 4 sky colors
    uniform highp vec4 sky;
    uniform highp vec4 midSky;
    uniform highp vec4 horizon;
    uniform highp vec4 ground;
    
    varying highp vec2 vTexCoord;
    void main()
    {  mediump vec2 uv = vec2((vTexCoord.x - 0.5)*aspect,(vTexCoord.y - 0.5));
        lowp vec3 up = cross(vec3(0.,lookAt.y,lookAt.x),vec3(1.,0.,0.));
        highp vec3 c = vec3(0.,lookAt.y,lookAt.x)*zoom;
        mediump float t = normalize(c + vec3(uv.x,0.,0.) + uv.y * up).y;
    
        lowp vec3 col;
        if (t < 0.) col = mix(horizon.rgb,ground.rgb,abs(t));
        else {
            lowp float h = 2.*t-1.;
            if (h>0.) h = 0.;
            h*=h;
            lowp float m = 2.*t-1.;
            m*=m;
            m=1.-m;
            lowp float s = 2.*t-1.;
            if (s<0.) s = 0.;
            s*=s;
            col = horizon.rgb*h + midSky.rgb*m + sky.rgb*s;
        } gl_FragColor = vec4(col,1.); }]])
    

    Example Project

    --# Main
    displayMode(FULLSCREEN)
    function setup()
        rotX,rotY = 0,0 -- camera rotation
        camX,camY,camZ = 20,20,20
    
        m = mesh() -- create a mesh that will cover the screen
        m:addRect(WIDTH/2,HEIGHT/2,WIDTH,HEIGHT)
        m:setColors(255,255,255,255)
        m.shader = shader(sky.vert,sky.frag)
        m.shader.zoom = 0.5 -- fov of the camera (0.5 is 90 degrees. 1.0 is 45 degrees)
        m.shader.aspect = WIDTH/HEIGHT -- aspect ration of the screen
        m.shader.sky = vec4(0.15,0.4,0.6,1.0) -- top color of the sky
        m.shader.midSky = vec4(0.3,0.5,0.7,1) -- color between the top and horizon
        m.shader.horizon = vec4(0.7,0.8,0.9) -- horizon color
        m.shader.ground = vec4(0.05,0.15,0.3) -- bottom color
    
        axis = mesh() -- x,y,z axis mesh
        axis.vertices = {
            vec3(0,1,0),vec3(6,0,0),vec3(0,0,0), -- x
            vec3(0.5,0.9166,0),vec3(0,6,0),vec3(0,1,0), -- y
            vec3(0,1,0),vec3(0,6,0),vec3(0,0.9166,0.5),
            vec3(0,1,0),vec3(0,0,6),vec3(0,0,0) -- z
        }
        local r,g,b = color(255,0,0),color(0,255,0),color(0,0,255)
        axis.colors = {
            r,r,r,
            g,g,g,
            g,g,g,
            b,b,b
        }
    
        -- create the ground
        ground = mesh()
        local size = 2000 -- size of the ground
        ground.vertices = {
        vec3(-size,0,-size),vec3(-size,0,size),vec3(size,0,size),
        vec3(size,0,size),vec3(size,0,-size),vec3(-size,0,-size)
        }
        local tiles = 160 -- number of tiles on the ground
        ground.texCoords = {
        vec2(0,0),vec2(0,tiles),vec2(tiles,tiles),
        vec2(tiles,tiles),vec2(tiles,0),vec2(0,0)
        }
        ground:setColors(255,255,255,255)
        ground.texture = readImage("Blocks:Grass Top")
        ground.shader = shader(basicTiles.vert,basicTiles.frag)
    end
    
    -- This function gets called once every frame
    function draw()
        -- This sets a dark background color 
        background(40, 40, 50)
    
        local lookAtX = math.sin(rotY) * math.cos(rotX)
        local lookAtY = math.sin(rotX)
        local lookAtZ = -math.cos(rotY) * math.cos(rotX)
        perspective(90,WIDTH/HEIGHT,0.1,1000)
        camera(camX,camY,camZ,
        camX + lookAtX,
        camY + lookAtY,
        camZ + lookAtZ)
        -- ground:draw() -- uncomment this to draw the ground
        axis:draw()
    
        ortho()
        viewMatrix(matrix())
    
        resetMatrix()
        zLevel(-10)
        m.shader.lookAt = vec2(math.cos(rotX),math.sin(rotX))
        m:draw()
    end
    
    function touched(t)
        rotY = rotY + t.deltaX * 0.01
        rotX = rotX + t.deltaY * 0.01
        if rotX < -1.5 then
            rotX = -1.5
        elseif rotX > 1.5 then
            rotX = 1.5
        end
    end
    
    --# Shaders
    sky = {
    vert = [[
    uniform mat4 modelViewProjection; // vertex shader
    attribute vec4 position;
    attribute vec4 color;
    attribute vec2 texCoord;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;
    void main() { vColor = color; vTexCoord = texCoord; gl_Position = modelViewProjection * position; }
    ]],
    frag = [[
    precision highp float;
    
    // camera zoom
    uniform mediump float zoom;
    // aspect ratio of the screen (WIDTH/HEIGHT)
    uniform mediump float aspect;
    // normalized look at vector
    uniform lowp vec2 lookAt;
    
    // 4 sky colors
    uniform highp vec4 sky;
    uniform highp vec4 midSky;
    uniform highp vec4 horizon;
    uniform highp vec4 ground;
    
    //The interpolated texture coordinate for this fragment
    varying highp vec2 vTexCoord;
    
    void main()
    {
        mediump vec2 uv = vec2((vTexCoord.x - 0.5)*aspect,(vTexCoord.y - 0.5));
        lowp vec3 up = cross(vec3(0.,lookAt.y,lookAt.x),vec3(1.,0.,0.));
        highp vec3 c = vec3(0.,lookAt.y,lookAt.x)*zoom;
        mediump float t = normalize(c + vec3(uv.x,0.,0.) + uv.y * up).y;
    
        lowp vec3 col;
        if (t < 0.) col = mix(horizon.rgb,ground.rgb,abs(t));
        else {
            lowp float h = 2.*t-1.;
            if (h>0.) h = 0.;
            h*=h;
            lowp float m = 2.*t-1.;
            m*=m;
            m=1.-m;
            lowp float s = 2.*t-1.;
            if (s<0.) s = 0.;
            s*=s;
            col = horizon.rgb*h + midSky.rgb*m + sky.rgb*s;
        }
        gl_FragColor = vec4(col,1.);
    }
    ]]
    }
    basicTiles = {
    vert = sky.vert, -- make the vertex shader the same as sky.vert because sky.vert is just the default vertex shader
    frag = [[
    //Default precision qualifier
    precision highp float;
    
    //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 and loop the coordinates with fract()
        lowp vec4 col = texture2D( texture, fract(vTexCoord) ) * vColor;
        gl_FragColor = col;
    }
    ]]
    }
    
    image.jpeg 118.4K
    image.jpeg 280.3K
  • Posts: 1,227

    @Kolosso - absolutely magic, I will learn a lot from these. One thing, error in your SkyDome where the code is trying to load a “Basic Tiles” shader and I have no file of that type. Thanks.

  • Posts: 160

    @Bri_G Thanks, I didn't see that. I've updated the code, so it should work now!

Sign In or Register to comment.