0

I want to create a similar background with a shader to these images: enter image description here:

These are just blurred blobs with colors, distributed across the whole page: enter image description here

Here's my current progress: https://codesandbox.io/s/lucid-bas-wvlzl9?file=/src/components/Background/Background.tsx

Vertex shader:

  varying vec2 vUv;
  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }

Fragment shader:

precision highp float;

uniform float uTime;
uniform float uAmplitude;
uniform float uFrequency;
varying vec2 vUv;
uniform vec2 uResolution;

vec4 Sphere(vec2 position, float radius)
{
    // float dist = radius / distance(vUv, position);
    // float strength = 0.01 / distance(vUv, position);
    float strength = 0.1 / distance(vec2(vUv.x, (vUv.y - 0.5) * 8. + 0.5), vec2(0.));
    return vec4(strength * strength);
}

void main()
{
    vec2 uv = vUv;

    vec4 pixel = vec4(0.0, 0.0, 0.0, 0.0);

    vec2 positions[4];
    positions[0] = vec2(.5, .5);
    // positions[1] = vec2(sin(uTime * 3.0) * 0.5, (cos(uTime * 1.3) * 0.6) + vUv.y);
    // positions[2] = vec2(sin(uTime * 2.1) * 0.1, (cos(uTime * 1.9) * 0.8) + vUv.y);
    // positions[3] = vec2(sin(uTime * 1.1) * 1.1, (cos(uTime * 2.6) * 0.7) + vUv.y);

    for (int i = 0; i < 2; i++)
        pixel += Sphere(positions[i], 0.22);

    pixel = pixel * pixel;
    gl_FragColor = pixel;
}
Bart Krakowski
  • 1,655
  • 2
  • 8
  • 25

1 Answers1

1

For each blob, you can multiply it's color by a a noise function and then a 2D gaussian curve centered in a random point. Then add all the blobs together. I only added the ones of the adjacent cells to make it scrollable and the numbers in the for loops might be increased for bigger blobs.

here is my code :

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

const float blobSize = 0.125;
const float cellSize = .75;
const float noiseScale = .375;
const float background = .125;
const float blobsLuminosity = .75;
const float blobsSaturation = .5;

vec2 random2(vec2 st){
    st = vec2( dot(st,vec2(127.1,311.7)),
              dot(st,vec2(269.5,183.3)) );
    return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}

// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);

    vec2 u = f*f*(3.0-2.0*f);

    return mix( mix( dot( random2(i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ),
                     dot( random2(i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x),
                mix( dot( random2(i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ),
                     dot( random2(i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y)*.5+.5;
}


float gaussFunction(vec2 st, vec2 p, float r) {
    return exp(-dot(st-p, st-p)/2./r/r);
}

//  Function from Iñigo Quiles
//  https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
                             6.0)-3.0)-1.0,
                     0.0,
                     1.0 );
    rgb = rgb*rgb*(3.0-2.0*rgb);
    return c.z * mix( vec3(1.0), rgb, c.y);
}

vec3 hash32(vec2 p)
{
    vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
    p3 += dot(p3, p3.yxz+33.33);
    return fract((p3.xxy+p3.yzz)*p3.zyx);
}

vec3 blobs(vec2 st){
    vec2 i = floor(st/cellSize);
    vec3 c = vec3(0.);
    
    for(int x = -1; x <= 1; x++)
        for(int y = -1; y <= 1; y++){
            vec3 h = hash32(i+vec2(x, y));
            c += hsb2rgb(vec3(h.z, blobsSaturation, blobsLuminosity)) * gaussFunction(st/cellSize, i + vec2(x, y) + h.xy, blobSize) * smoothstep(0., 1., noise(noiseScale*st/cellSize / blobSize));
            //c += hsb2rgb(vec3(h.z, blobsSaturation, blobsLuminosity)) * gaussFunction(st/cellSize, i + vec2(x, y) + h.xy, blobSize) * noise(noiseScale*st/cellSize / blobSize);
        }
    return c + vec3(background);
}


float map(float x, float a, float b, float c, float d){
    return (x-a)/(b-a)*(d-c)+c;
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    st.x *= u_resolution.x/u_resolution.y;
    
    
    vec3 color = vec3(0.0);
    
    
    
    color = vec3(blobs(st - u_mouse/u_resolution.xy*4.));

    gl_FragColor = vec4(color,1.0);
}

made in this shader editor.

Cadeyrn
  • 545
  • 2
  • 12
  • Thank you so much! I'm wondering how to make it scrollable because now it's fixed. I've change the st variable to: ``` vec2 st = vUv; ``` but now it's stretched. – Bart Krakowski Jul 19 '22 at 12:10
  • I edited the answer. However, as I don't know anything about vertex shaders, I'm not sure of the solution for the streching problem : I think that multiplying the x component of the st vector by the height/width ratio of the image must fix it. – Cadeyrn Jul 19 '22 at 19:55
  • Thanks! It works, without stretching. The problem is when I change st to vUv. The vertex shader is the standard one: ``` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } ``` – Bart Krakowski Jul 19 '22 at 20:42
  • I was thinking about the fact that the distortion caused by the noise wasn't that strong and so I tried to put it in a smoothstep function (to get more values near 0 and 1) and the result was way better in my opinion. – Cadeyrn Jul 20 '22 at 20:21