Howdy, Stranger!

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

Free-to-Use Rainbow Circle Shader

in Shaders Posts: 160

Today I saw this post from 3 months ago by @xThomas. He was asking how to make a rainbow circle shader, and I wanted to give it a shot. I wasn't sure if I should comment on his old post or if I should make a new one. The shader is free for use and easy to use. Here is an example project using the shader.

--# 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;
}
]]
}
Tagged:

Comments

  • dave1707dave1707 Mod
    Posts: 7,469

    @Kolosso Nice job. I like it when people use shaders because I can learn from them. If I run your program in fullscreen landscape mode and move my finger in a large circle, the image gives me an uneasy feeling. Your rainbow circle is similar to what I have in the link below. Below that is another version based on my original code.

    https://codea.io/talk/discussion/8375/rainbow-rectangle
    
    supportedOrientations(LANDSCAPE_ANY)
    
    function setup()
        parameter.integer("size",100,2000,750)
        print("Please wait while I finish my calculations, approx 10 seconds.")
        print("Use the parameter to change the size, and use your finger to move the circle around the screen.")
        dx,dy=0,0
        tab1={}
        r,g,b=0,255,255
        y=WIDTH
        while y>=0 do
            table.insert(tab1,vec3(r,g,b))
            y=y-WIDTH/(256*6)
            if r==255 and g==0 and b==0 then
                rv,gv,bv=0,1,0
            elseif r==255 and g==255 and b==0 then
                rv,gv,bv=-1,0,0
            elseif r==0 and g==255 and b==0 then
                rv,gv,bv=0,0,1
            elseif r==0 and g==255 and b==255 then
                rv,gv,bv=0,-1,0
            elseif r==0 and g==0 and b==255 then
                rv,gv,bv=1,0,0
            elseif r==255 and g==0 and b==255 then
                rv,gv,bv=0,0,-1
            end 
            r=r+rv
            g=g+gv
            b=b+bv       
        end
        w=#tab1//2
        img=image(#tab1,#tab1)
        setContext(img)
        background(0)
        noFill()
        strokeWidth(1)
        for z=1,#tab1 do
            stroke(tab1[z].x,tab1[z].y,tab1[z].z)
            ellipse(w,w,z)        
        end
        setContext()
    end
    
    function draw()
        background(0)
        sprite(img,WIDTH/2+dx,HEIGHT/2+dy,size)
    end
    
    function touched(t)
        if t.state==MOVING then
            dx=dx+t.deltaX
            dy=dy+t.deltaY
        end
    end
    
  • Posts: 160

    @dave1707 That's a cool effect! I'm pretty new to shaders but I think my little experience with C# helps me understand it better. I'm also very surprised you would learn something from me. As a beginner I had always looked up to you and try to learn from your code. The last thing I would have ever expected was for someone as experienced as you to learn something from me.

    And thank-you for inspiring me throughout my whole journey with all of your examples. :)

  • dave1707dave1707 Mod
    Posts: 7,469

    @Kolosso Thanks for the kind words. I don't do a lot of shader coding, so I do learn something when I see them. And I also learn things from some Codea code. I tend to use the same variable names and code things the same way, so when someone codes something in a different way, I find that interesting. Looking at small examples was one way I learned things. I would take that code and play with it until I understood what was happening, then I would start to modify it just to see what would happen. I've been using Codea for over 5 years and there's still things I don't know which keeps me interested.

Sign In or Register to comment.