Created
January 31, 2025 09:18
-
-
Save josippapez/b14933d96c5ec610de641d95bfc002e4 to your computer and use it in GitHub Desktop.
Moving Blobs shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const MovingBlobsBackground = () => { | |
| const shaderRef = useRef<ShaderMaterial>(null!) | |
| useFrame((state) => { | |
| if (shaderRef.current) { | |
| shaderRef.current.uniforms.uTime.value = state.clock.elapsedTime | |
| } | |
| }) | |
| return ( | |
| <mesh position={[0, 0, 1]}> | |
| <planeGeometry args={[2, 2]} /> | |
| <shaderMaterial | |
| ref={shaderRef} | |
| fragmentShader={` | |
| uniform float uTime; | |
| float random(vec2 st) { | |
| return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123); | |
| } | |
| // Simplex 2D noise | |
| vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); } | |
| float snoise(vec2 v){ | |
| const vec4 C = vec4(0.211324865405187, 0.366025403784439, | |
| -0.577350269189626, 0.024390243902439); | |
| vec2 i = floor(v + dot(v, C.yy) ); | |
| vec2 x0 = v - i + dot(i, C.xx); | |
| vec2 i1; | |
| i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); | |
| vec4 x12 = x0.xyxy + C.xxzz; | |
| x12.xy -= i1; | |
| i = mod(i, 289.0); | |
| vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) | |
| + i.x + vec3(0.0, i1.x, 1.0 )); | |
| vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), | |
| dot(x12.zw,x12.zw)), 0.0); | |
| m = m*m ; | |
| m = m*m ; | |
| vec3 x = 2.0 * fract(p * C.www) - 1.0; | |
| vec3 h = abs(x) - 0.5; | |
| vec3 ox = floor(x + 0.5); | |
| vec3 a0 = x - ox; | |
| m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); | |
| vec3 g; | |
| g.x = a0.x * x0.x + h.x * x0.y; | |
| g.yz = a0.yz * x12.xz + h.yz * x12.yw; | |
| return 130.0 * dot(m, g); | |
| } | |
| void main() { | |
| vec2 uv = gl_FragCoord.xy / vec2(1000.0); | |
| // Create multiple layers of noise for ice structure | |
| float n1 = snoise(uv * 3.0 + uTime * 0.05); | |
| float n2 = snoise(uv * 6.0 - uTime * 0.03); | |
| float n3 = snoise(uv * 9.0 + uTime * 0.02); | |
| // Combine noise layers | |
| float finalNoise = (n1 * 0.5 + n2 * 0.3 + n3 * 0.2); | |
| // Create ice pattern threshold | |
| float iceThreshold = 0.5; | |
| float pattern = smoothstep(0.3, 0.7, finalNoise); | |
| // Determine if current pixel is ice or background | |
| bool isIce = pattern > iceThreshold; | |
| vec3 color; | |
| float alpha; | |
| if (isIce) { | |
| // Ice areas - translucent and grainy | |
| vec3 baseColor = vec3(0.85, 0.92, 1.0); | |
| vec3 secondaryColor = vec3(0.75, 0.85, 0.95); | |
| color = mix(baseColor, secondaryColor, pattern); | |
| // Add grain only to ice | |
| float grain = random(uv * uTime) * 0.03; | |
| color += vec3(grain); | |
| // Make ice translucent | |
| alpha = mix(0.6, 0.8, pattern); | |
| } else { | |
| // Non-ice areas - solid black | |
| color = vec3(0.0); | |
| alpha = 1.0; | |
| } | |
| gl_FragColor = vec4(color, alpha); | |
| } | |
| `} | |
| vertexShader={` | |
| void main() { | |
| gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); | |
| } | |
| `} | |
| uniforms={{ | |
| uTime: { value: 0 }, | |
| }} | |
| transparent={true} | |
| /> | |
| </mesh> | |
| ) | |
| } |
Author
josippapez
commented
Jan 31, 2025

Author
Same but smaller blobs
<mesh position={[0, 0, 1]}> <planeGeometry args={[2, 2]} /> <shaderMaterial ref={shaderRef} fragmentShader={
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}
// Simplex 2D noise
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }
float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}
void main() {
vec2 uv = gl_FragCoord.xy / vec2(1000.0);
// Create multiple layers of noise with higher frequencies
float n1 = snoise(uv * 30.0);
float n2 = snoise(uv * 40.0);
float n3 = snoise(uv * 50.0);
float n4 = snoise(uv * 60.0);
float n5 = snoise(uv * 70.0);
// Combine noise layers for more detailed pattern
float finalNoise = (n1 * 0.3 + n2 * 0.25 + n3 * 0.2 + n4 * 0.15 + n5 * 0.1);
// Create more scattered, point-like blobs
float blobThreshold = 0.5;
float pattern = smoothstep(0.45, 0.55, finalNoise);
// Add fine grain structure
float baseGrain = random(uv * 2.0) * 0.15;
float detailGrain = random(uv * 10.0) * 0.1;
float combinedGrain = baseGrain + detailGrain;
vec3 color;
float alpha;
// Create point-like effect
bool isPoint = (pattern + combinedGrain) > blobThreshold;
if (isPoint) {
// Point areas - create grainy, scattered effect
vec3 baseColor = vec3(0.9, 0.95, 1.0);
vec3 grainColor = vec3(0.7, 0.8, 0.9);
// Mix colors based on noise and grain
color = mix(baseColor, grainColor, combinedGrain);
// Add sparkle effect
float sparkle = pow(random(uv * 50.0), 3.0) * 0.5;
color += vec3(sparkle);
// Vary transparency for depth effect
alpha = mix(0.1, 0.3, pattern * (1.0 - combinedGrain));
} else {
color = vec3(0.0);
alpha = 1.0;
}
gl_FragColor = vec4(color, alpha);
}
`}
vertexShader={`
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`}
uniforms={{}}
transparent={true}
/>
</mesh>`
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment