Shadertoys


Index


Metaballs

SHOW SOURCE

const float aR = 16.0/9.0;
 

float remap(float value, float low1, float high1, float low2, float high2)
{
    return low2 + (value - low1) * (high2 - low2) / (high1 - low1);      
}
// polynomial smooth min (k = 0.1); (IQuilez)
float smin(float a, float b, float k)
{
    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
    return mix( b, a, h ) - k*h*(1.0-h);
}

struct Circle
{
	vec2 pos;
    float radius;
};
    
Circle circle1 = Circle(vec2(.3, .3), .2);
Circle circle2 = Circle(vec2(1, .5), .2);
Circle circle3 = Circle(vec2(1, .5), .2);

//settings
const float timeStep = 1.0;
const float smoothFactor = 0.2;


float distToCenter(vec2 point, Circle circle)
{
    return sqrt(pow(point.x - circle.pos.x, 2.0) + pow(point.y - circle.pos.y, 2.0));
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.y;
    
    //Circle Movement
	float timeSine = (sin(iTime/timeStep)+1.0)/2.0;
    float timeCos = (cos(iTime/.7)+1.0)/2.0;
  	float timeTan = (tan(iTime/timeStep)+1.0)/2.0;

    circle1.pos.x = mix(0.0 + circle1.radius, aR - circle1.radius, timeSine);
    circle1.pos.y = mix(0.0 + circle1.radius, 1.0 - circle1.radius, timeSine);
    circle2.pos.x = aR-mix(0.0 + circle2.radius, aR - circle2.radius, timeSine);
    
    circle3.pos.y = mix(0.0 + circle3.radius, 1.0 - circle3.radius, timeCos);
    circle3.pos.x = mix(0.0 + circle3.radius, aR - circle3.radius, 1.0-timeCos);

    //For coloring based on distance to closest center
    float centerDist = distToCenter(uv, circle1);
    float centerDist2 = distToCenter(uv, circle2);  
    float centerDist3 = distToCenter(uv, circle3);
    float closestCenterDist = min(min(centerDist, centerDist2), centerDist3);
    float circleDist = centerDist - circle1.radius;    

    circleDist = smin(circleDist, centerDist2 - circle2.radius, smoothFactor);
    circleDist = smin(circleDist, centerDist3 - circle3.radius, smoothFactor);
    if(circleDist <= .01)
    {        
        //centreDist ranges from 0 (center) to radius (circumpherence)
        //normalize in 0...1 range by dividing by radius
        closestCenterDist /= .2;
        centerDist /=.2;
        centerDist2 /=.2;
        centerDist3 /=.2;
        
        //Weighted distribution of color, the closest you are to a sphere the more its color 
        //bleeds onto the current pixel.
        //    distanceToCircle
        //    ----------------
        //  distanceToAllCircles
        //Thought i had to do 1 - this but apparently it works like this so eh ill take it
        
        float c1Infl = centerDist / (centerDist + centerDist2 + centerDist3);
        float c2Infl = centerDist2 / (centerDist + centerDist2 + centerDist3);
        float c3Infl = centerDist3 / (centerDist + centerDist2 + centerDist3);

        vec3 col1 = vec3(146, 0, 255) * c1Infl;
        vec3 col2 = vec3(255, 146, 0) * c2Infl;
        vec3 col3 = vec3(0, 255, 146) * c3Infl;
        
        fragColor = vec4(/*closestCenterDist * */(col1+col2 + col3)/255.0, 1.0);
    }
    else
    {
    	fragColor = vec4(0);   
    }
}


2D Lighting Simulation

SHOW SOURCE

float distanceToSphere(vec3 sphere, vec2 point)
{
    return sqrt(pow((point.x - sphere.x), 2.0)+pow((point.y - sphere.y), 2.0))- sphere.z;
}


//Position xy, Radius
vec3 sphere1 = vec3(1.3, .3, .05);
vec3 sphere2 = vec3(.4, .45, .05);

float intensity = 2.0;

struct PointLight
{
	vec2 pos;
    vec3 color;
    float intensity;
};
    
PointLight centerLight = PointLight(vec2(0, 0), vec3(.1, .3, .8), 2.0);
    
PointLight rightLight = PointLight(vec2(.3, .7), vec3(.7, .2, .5), 2.0);


vec3 RenderLight(PointLight light, vec2 uv)
{
    vec3 finalColor = vec3(0);
    vec2 ray = normalize(light.pos - uv);   

    int maxSteps = 200;
    vec2 currentPoint = uv;
    float travelledDist = 0.0;
    float dist, dist2;
    float smallestDistance = 1.0;
    for(int i = 0; i < maxSteps; i++)
    {
    	dist = distanceToSphere(sphere1, currentPoint);
        dist2 = distanceToSphere(sphere2, currentPoint);
        float distToTarget = length(light.pos - currentPoint);
        float minDistance = min(min(dist, dist2), distToTarget);
        smallestDistance = min(smallestDistance, min(dist, dist2));
        if(minDistance < .01)
        {
            break;
        }
        
        travelledDist += minDistance;
        currentPoint = uv + ray * travelledDist;
        
        if(length(currentPoint-light.pos)<.02)
        {
            float lightVal = .2 * (1.0 - length(uv - light.pos) + .2);
            if(smallestDistance < .03)
            {
            	float clamper = smallestDistance / .03;
                finalColor = light.color * light.intensity * mix(0.0, lightVal, clamper);
            }
            else
            {
	            finalColor += light.color * lightVal * light.intensity;   
            }
            break;
        }
    }
    return finalColor;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.y;
	vec2 mousePos = iMouse.xy / iResolution.y;
    // Time varying pixel color
    //vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    // Output to screen
    fragColor = vec4(0);
        
    centerLight.pos = mousePos;
    rightLight.pos.x = .30 + (sin(iTime/1.5)+1.0)/2.0;
    vec3 light1 = RenderLight(centerLight, uv);
    vec3 light2 = RenderLight(rightLight, uv);
    fragColor = vec4(light1 + light2, 1);
    float dist, dist2;

    dist = distanceToSphere(sphere1, uv);
    dist2 = distanceToSphere(sphere2, uv);
    if(dist < .01)
    {
    	fragColor = vec4(1);
    }
    
    if(dist2 < .01)
    {
    	fragColor = vec4(1);
    }
}

Click on the screen to interact with the light