学生作品選集
2025年度授業「コンピュータグラフィックス特論」の生徒作品を紹介します。一つのフラグメントシェーダーを使って蘭の花の画像を生成Aすることが目的でした。もし興味あったら宿題の説明をご覧ください。
uniform vec2 u_resolution;
uniform float u_time;
float cross2(vec2 a, vec2 b) {
return a.x * b.y - a.y * b.x;
}
float sdTriangle(vec2 p, vec2 a, vec2 b, vec2 c) {
vec2 e0 = b - a;
vec2 e1 = c - b;
vec2 e2 = a - c;
vec2 v0 = p - a;
vec2 v1 = p - b;
vec2 v2 = p - c;
vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);
vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);
vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);
float d = min(min(dot(pq0, pq0), dot(pq1, pq1)), dot(pq2, pq2));
float s0 = e0.x * v0.y - e0.y * v0.x;
float s1 = e1.x * v1.y - e1.y * v1.x;
float s2 = e2.x * v2.y - e2.y * v2.x;
bool inside = (s0 > 0.0 && s1 > 0.0 && s2 > 0.0) || (s0 < 0.0 && s1 < 0.0 && s2 < 0.0);
return (inside ? -sqrt(d) : sqrt(d));
}
float sdSegment(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
float sdTrapezoid(vec2 lp, float baseW, float topW, float h, float r) {
vec2 a = vec2(-baseW * 0.5 + 0.1, 0.0);
vec2 b = vec2(baseW * 0.5 + 0.05, 0.0);
vec2 c = vec2(topW * 0.5 + 0.06, -h);
vec2 d = vec2(-topW * 0.5 + 0.05, -h + 0.07);
float dseg = min(min(sdSegment(lp, a, b), sdSegment(lp, b, c)), min(sdSegment(lp, c, d), sdSegment(lp, d, a)));
float s0 = cross2(b - a, lp - a);
float s1 = cross2(c - b, lp - b);
float s2 = cross2(d - c, lp - c);
float s3 = cross2(a - d, lp - d);
bool inside = ((s0 > 0.0) && (s1 > 0.0) && (s2 > 0.0) && (s3 > 0.0)) || ((s0 < 0.0) && (s1 < 0.0) && (s2 < 0.0) && (s3 < 0.0));
float sd = inside ? -dseg : dseg;
return sd - r;
}
float sdRoundedBox(vec2 p, vec2 b, float r) {
vec2 q = abs(p) - b;
return length(max(q, 0.0)) - r + min(max(q.x, q.y), 0.0);
}
float orientedSector(vec2 p, vec2 c, float R, float A, float theta) {
vec2 v = p - c;
float r = length(v);
float ang = atan(v.y, v.x);
float dAng = abs(ang - theta);
dAng = min(dAng, 6.3 - dAng); // wrap to [-pi, pi]
return step(r, R) * step(dAng, A);
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x * 34.0) + 1.0) * x);
}
vec4 permute(vec4 x) {
return mod289(((x * 34.0) + 1.0) * x);
}
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 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec2 x1 = x0 - i1 + C.xx;
vec2 x2 = x0 - 1.0 + 2.0 * C.xx;
i = mod289(i);
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(x1, x1), dot(x2, x2)), 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.8 - 0.8 * (a0 * a0 + h * h);
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.y = a0.y * x1.x + h.y * x1.y;
g.z = a0.z * x2.x + h.z * x2.y;
return 130.0 * dot(m, g);
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod(i, 289.0);
vec4 p = permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y + vec4(0.0, i1.y, i2.y, 1.0)) + i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 1.0 / 7.0;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ * ns.x + ns.yyyy;
vec4 y = y_ * ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0) * 2.0 + 1.0;
vec4 s1 = floor(b1) * 2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
vec3 g0 = vec3(a0.x, a0.y, h.x);
vec3 g1 = vec3(a0.z, a0.w, h.y);
vec3 g2 = vec3(a1.x, a1.y, h.z);
vec3 g3 = vec3(a1.z, a1.w, h.w);
vec4 norm = inversesqrt(vec4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3)));
g0 *= norm.x;
g1 *= norm.y;
g2 *= norm.z;
g3 *= norm.w;
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
m = m * m;
return 42.0 * dot(m * m, vec4(dot(g0, x0), dot(g1, x1), dot(g2, x2), dot(g3, x3)));
}
float turbulence(vec3 p) {
float amp = 0.5;
float f = 0.0;
for(int i = 0; i < 5; i++) {
f += amp * abs(snoise(p));
p = p * 2.0 + vec3(36.0, 18.0, 24.0); // rounded offsets
amp *= 0.5;
}
return f;
}
float fbm(vec2 p) {
float a = 1.68, f = 0.0;
for(int i = 0; i < 6; i++) {
f += a * snoise(p);
p = p * 2.0 + vec2(37.0, 17.0);
a *= 0.5;
}
return f;
}
// Colours
vec3 greyBG() {
return vec3(0.055, 0.110, 0.080);
}
vec3 bodyGrey() {
return vec3(0.145, 0.069, 0.039);
}
vec3 blue() {
return vec3(0.12, 0.36, 0.85);
}
vec3 turquoise() {
return vec3(0.20, 0.85, 0.75);
}
vec3 finGradient(float t) {
return mix(turquoise(), blue(), clamp(t, 0.0, 1.0));
}
vec2 hash22(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
return fract(sin(p) * 43758.5453123);
}
float dotGrid(vec2 uv, float cell, float radius, float jitter) {
vec2 g = floor(uv / cell);
vec2 f = fract(uv / cell);
vec2 j = (hash22(g) - 0.5) * jitter;
vec2 c = 0.5 + j;
float d = length(f - c);
return smoothstep(radius, radius * 0.85, d); // 1 inside the dot
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy; // for vignette
float s = min(u_resolution.x, u_resolution.y);
vec2 p = (gl_FragCoord.xy - 0.5 * u_resolution) / s; // [-0.5, 0.5]^2
float t = u_time;
vec3 uv = vec3(0.75 * gl_FragCoord.xy / u_resolution.y - 0.5, 0.05 * u_time);
float flow = 1.328 * turbulence(uv) + 0.5;
vec3 waterHue = mix(vec3(0.094, 0.280, 0.081), vec3(0.129, 0.315, 0.390), 0.35);
vec3 bg = mix(waterHue, greyBG(), flow);
vec3 col = bg;
// Head
vec2 A = vec2(-0.42, 0.02);
vec2 B = vec2(-0.30, 0.1);
vec2 C = vec2(-0.30, -0.07);
float headSDF = sdTriangle(p, A, B, C);
float headMask = smoothstep(0.02, -0.005, headSDF);
// Eye
vec2 eyeC = vec2(-0.35, 0.03);
float eyeR = 0.02;
float eyeD = length(p - eyeC) - eyeR;
float eyeMask = smoothstep(0.01, -0.005, eyeD);
float eyeNoise = 0.5 + 1.836 * snoise((p - eyeC) * 22.0);
vec3 eyeCol = mix(greyBG(), turquoise(), eyeNoise);
float headNoise = 0.5 + 5.5 * snoise(p * 15.0);
float headPattern = smoothstep(0.45, 0.85, headNoise);
vec3 headBase = bodyGrey();
vec3 headBlue = 1.0 * finGradient(headNoise);
vec3 headCol = mix(headBase, headBlue, headPattern);
headCol = mix(headCol, eyeCol, eyeMask);
// Body
vec2 bodyCenter = vec2(-0.02, 0.01);
vec2 bp = p - bodyCenter;
float bulge = 1.0 + 0.35 * exp(-bp.x * bp.x / 0.10);
vec2 q = vec2(bp.x, bp.y / bulge);
float bodySDF = sdRoundedBox(q, vec2(0.22, 0.03), 0.055);
float bodyMask = smoothstep(0.02, -0.005, bodySDF);
vec3 bodyBase = bodyGrey();
vec2 dotsUV = q * vec2(20.0, 20.0) + vec2(1.2, 0.0);
float dots = dotGrid(dotsUV + 0.05 * fbm(q * 4.536) * vec2(1.0), 0.5, 0.2, 0.18);
float bodyFalloff = clamp(-bodySDF / 0.20, 0.0, 1.0);
vec3 bodyBlue = 3.326 * finGradient(0.6 + 0.4 * snoise(q * 5.0));
vec3 bodyCol = mix(bodyBase, bodyBlue, dots * bodyFalloff);
float sway = 0.8 * t;
// Tail
vec2 tailBase = bodyCenter + vec2(0.25, 0.00);
float tailTheta = 0.0 + 0.08 * sin(sway);
float tailR = 0.3 + 0.02 * sin(sway * 0.7);
float tailA = 1.648 + 0.06 * sin(sway * 0.5);
float tailMask = orientedSector(p, tailBase, tailR, tailA, tailTheta);
vec2 tv = p - tailBase;
float tailStripes = 0.5 + 0.5 * sin(25.0 * atan(tv.y, tv.x) + 11.0 * length(tv) + 1.2 * t);
float tailNoise = 1.7 + 0.4 * fbm(tv * 7.0 + vec2(0.0, 1.600 * t));
float gTail = clamp(length(tv) / tailR, 0.0, 1.0); // radial gradient factor
vec3 gradTail = finGradient(gTail);
vec3 stripeTail = mix(bodyGrey(), gradTail, tailStripes); // stripes: grey→gradient
vec3 tailCol = stripeTail * (0.35 + 0.65 * tailNoise); // animated shimmer
// Top fin
vec2 topFinBase = bodyCenter + vec2(0.1, 0.02);
float topFinTheta = 1.57 + 0.06 * sin(sway * 0.9);
float topFinR = 0.282 + 0.02 * sin(sway * 0.9);
float topFinA = 0.82 + 0.05 * sin(sway);
float topFinMask = orientedSector(p, topFinBase, topFinR, topFinA, topFinTheta);
vec2 dv = p - topFinBase;
float topFinStripes = 0.5 + 0.5 * sin(25.0 * atan(dv.y, dv.x) + 9.0 * length(dv) - 0.8 * t);
float topFinNoise = 1.7 + 0.4 * fbm(tv * 7.0 + vec2(0.0, 1.600 * t));
float gTopFin = clamp(length(dv) / topFinR, 0.0, 1.0);
vec3 gradTopFin = finGradient(gTopFin);
vec3 stripeTopFin = mix(bodyGrey(), gradTopFin, topFinStripes);
vec3 topFinCol = stripeTopFin * (0.35 + 0.65 * topFinNoise);
// Bottom fin
float bodyHalfH = 0.11;
float baseY = bodyCenter.y - bodyHalfH;
vec2 ap = p - vec2(bodyCenter.x, baseY);
float trapBaseW = 0.3;
float trapTopW = 0.22;
float trapH = 0.12;
float trapR = 0.03;
float bottomFinSDF = sdTrapezoid(ap, trapBaseW, trapTopW, trapH, trapR);
float bottomFinMask = smoothstep(0.02, -0.005, bottomFinSDF);
float bottomFinStripeMask = 0.720 + sin(gl_FragCoord.x / 2.800) / 0.544;
bottomFinStripeMask = smoothstep(0.60, 0.99, bottomFinStripeMask);
float nearBody = clamp(1.0 - (-ap.y) / trapH, 0.0, 1.0);
float gBottomFin = clamp((-ap.y) / trapH, 0.0, 1.0);
vec3 gradBottomFin = finGradient(gBottomFin);
float mixStrength = bottomFinStripeMask * (0.35 + 0.65 * (1.0 - nearBody));
vec3 stripeBottomFin = mix(bodyGrey(), gradBottomFin, mixStrength);
float bottomFinNoise = 1.6 + 0.4 * fbm(ap * 6.0 + vec2(0.2, 0.5 * t));
vec3 bottomFinCol = stripeBottomFin * (0.35 + 0.65 * bottomFinNoise);
// Small fins
float baseW = 0.020;
float height = baseW * 7.0;
vec2 joint = bodyCenter + vec2(-0.20, -0.08);
vec2 BR_baseL = joint + vec2(-baseW * 0.5, -0.01);
vec2 BR_baseR = joint + vec2(+baseW * 0.5, -0.01);
vec2 BR_tip = joint + vec2(+0.13, -height);
float brSDF = sdTriangle(p, BR_baseL, BR_baseR, BR_tip);
float brMask = smoothstep(0.02, -0.005, brSDF);
vec2 BL_baseL = joint + vec2(-baseW * 0.5, -0.015);
vec2 BL_baseR = joint + vec2(+baseW * 0.5, -0.015);
vec2 BL_tip = joint + vec2(-0.04, -height);
float blSDF = sdTriangle(p, BL_baseL, BL_baseR, BL_tip);
float blMask = smoothstep(0.02, -0.005, blSDF);
float smallFinNoise = 3.5 + 0.5 * snoise(p * 12.0 + vec2(0.0, 0.9 * t));
vec3 smallFinCol = mix(bodyGrey(), blue(), smallFinNoise) * (0.1 + 0.6 * fbm(p * 9.0));
col = mix(col, tailCol, tailMask);
col = mix(col, topFinCol, topFinMask);
col = mix(col, bottomFinCol, bottomFinMask);
col = mix(col, bodyCol, bodyMask);
col = mix(col, headCol, headMask);
float ventralMask = clamp(brMask + blMask, 0.0, 1.0);
col = mix(col, smallFinCol, ventralMask);
float vign = smoothstep(0.95, 0.2, length(st - 0.5));
col *= mix(0.85, 1.0, vign);
col = pow(col, vec3(0.95));
colour_out = vec4(col, 1.0);
}
Betta mahachaiensis by Hilary
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
mat2 rot(float angle){
float s = sin(angle);
float c = cos(angle);
return mat2(c, -s, s, c);
}
float random(in vec2 st){
return fract(sin(dot(st, vec2(12.9898, 78.233)))*43758.5453123);
}
float noise(vec2 st){
vec2 i = floor(st);
vec2 f = fract(st);
float a = random(i);
float b = random(i+vec2(1., 0.));
float c = random(i+vec2(0., 1.));
float d = random(i+vec2(1., 1.));
vec2 u = f*f*(3.-2.*f);
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
#define OCTAVES 4
float fbm(vec2 st){
float value = 0.;
float amplitude = .5;
float frequency = 1.;
for(int i = 0;i < OCTAVES;i++){
st.x += .3;
value += amplitude*abs(noise(frequency*st));
amplitude *= .18;
frequency *= 2.;
st = 2.*rot(.7)*st+vec2(100., 0.);
}
return value;
}
#define rot2d(x) mat2(cos(x), -sin(x), sin(x), cos(x))
#define FISH 1.
#define FIN1 1.1
#define FIN2 1.2
#define FIN3 1.3
#define FIN4 1.4
#define lightPos vec3(0., 2., 15.)
vec2 smin( float a, float b, float k )
{
float h = 1.0 - min( abs(a-b)/(4.0*k), 1.0 );
float w = h*h;
float m = w*0.5;
float s = w*k;
return (a<b) ? vec2(a-s,m) : vec2(b-s,1.0-m);
}
vec3 hsv(float h, float s, float v){return ((clamp(abs(fract(h+vec3(0., 2., 1.)/3.)*6.-3.)-1., 0., 1.)*s-1.)+1.)*v;}
float sdSegment( vec3 p, vec3 a, vec3 b )
{
vec3 pa = p - a, ba = b - a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h );
}
float sdHexagon2D( in vec2 p, in float r )
{
const vec3 k = vec3(-0.866025404,0.5,0.577350269);
p = abs(p);
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
return length(p)*sign(p.y);
}
float sdSegment2D( in vec2 p, in vec2 a, in vec2 b )
{
vec2 pa = p-a, ba = b-a;
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
return length( pa - ba*h );
}
vec2 sdFish(vec3 p){
vec3 p_o = p;
p *= vec3(1., .8, 1.2);
vec3 a = vec3( -0., 0.0, 0.0);
vec3 b = vec3(-1.5, 0.0, 0.0);
vec3 c = vec3(-3., 0.0, 0.0);
vec3 d = vec3(-5.5, 0.0, 0.0);
float t = clamp(dot(p-a, d-a)/dot(d-a, d-a), 0., 1.);
float d1 = sdSegment(p, a, b);
float d2 = sdSegment(p, b, c);
float d3 = sdSegment(p, c, d);
float minDist = min(d1, min(d2, d3));
float shape = clamp(-2.2*pow(t+.2, 2.)*(t-.86)+.45, 0., 3.);
return vec2(FISH, minDist-(shape));
}
vec2 sdBezier( in vec2 pos, in vec2 A, in vec2 B, in vec2 C )
{
vec2 a = B - A;
vec2 b = A - 2.0*B + C;
vec2 c = a * 2.0;
vec2 d = A - pos;
float kk = 1.0/dot(b,b);
float kx = kk * dot(a,b);
float ky = kk * (2.0*dot(a,a)+dot(d,b))/3.0;
float kz = kk * dot(d,a);
vec2 res;
float p = ky - kx*kx;
float q = kx*(2.0*kx*kx - 3.0*ky) + kz;
float p3 = p*p*p;
float q2 = q*q;
float h = q2 + 4.0*p3;
if( h>=0.0 )
{
h = sqrt(h);
vec2 x = (vec2(h,-h)-q)/2.0;
vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));
float t = clamp( uv.x+uv.y-kx, 0.0, 1.0 );
vec2 q = d+(c+b*t)*t;
res = vec2(dot(q,q), t);
}
else
{
float z = sqrt(-p);
float v = acos(q/(p*z*2.0))/3.0;
float m = cos(v);
float n = sin(v)*1.732050808;
vec3 t = clamp( vec3(m+m,-n-m,n-m)*z-kx, 0.0, 1.0 );
vec2 qx = d+(c+b*t.x)*t.x; float dx=dot(qx,qx);
vec2 qy = d+(c+b*t.y)*t.y; float dy=dot(qy,qy);
res = (dx<dy) ? vec2(dx, t.x) : vec2(dy, t.y);
}
return vec2(sqrt(res.x), res.y);
}
float sdBezier3D( vec3 p, vec3 A, vec3 B, vec3 C, float thickness )
{
vec2 bezierResult = sdBezier( p.xy, A.xy, B.xy, C.xy );
float distXY = bezierResult.x;
float t = bezierResult.y;
float distZ = p.z - A.z;
return length(vec2(distXY, distZ)) - thickness * (1. - t);
}
vec2 sdFin1(vec3 p){
float bound = length(p - vec3(2.5, 1.0, 0.)) - 4.0;
if(bound > 1.) return vec2(FIN1, bound);
vec3 p_o = p;
float bold1 = 0.12;
p.z *= 1.2;
p.y = abs(p.y);
float sy = 0.2;
float d1 = sdBezier3D(p, vec3(0., 4.5*sy, 0.), vec3(1., 2., 0.), vec3(2.5, 2.9, 0.), bold1);
float d2 = sdBezier3D(p, vec3(0., 3.5*sy, 0.), vec3(1., 2., 0.), vec3(3.9, 3.-1.*2./3., 0.), bold1);
float d3 = sdBezier3D(p, vec3(0., 2.5*sy, 0.), vec3(1., 1.5, 0.), vec3(4.4, 3.-2.1*2./3., 0.), bold1);
float d4 = sdBezier3D(p, vec3(0., 1.5*sy, 0.), vec3(1., 1., 0.), vec3(4.75, 3.-3.1*2./3., 0.), bold1);
float d5 = sdBezier3D(p, vec3(0., 0.5*sy, 0.), vec3(1., .5, 0.), vec3(5.3, 3.-4.1*2./3., 0.), bold1);
float d6 = sdBezier3D(p, vec3(0., -0.5*sy, 0.), vec3(1., 0., 0.), vec3(4.3, 3.-5.*2./3., 0.), bold1);
float minDist = min(
min(min(d1, d2), min(d3, d4)),
min(d5, d6)
);
float shape = clamp(.05, 0., 3.);
return vec2(FIN1, minDist-(shape));
}
vec2 sdFin2(vec3 p){
float bound = length(p - vec3(1.5, 2.5, 0.)) - 4.5;
if(bound > 1.) return vec2(FIN2, bound);
vec3 p_o = p;
float bold1 = 0.04;
p.z *= 1.;
float offset = .2;
float d1 = sdBezier3D(p, vec3(0., 0., 0.), vec3(-2., 3., 0.), vec3(2.5, 2.7, 0.), bold1);
float d2 = sdBezier3D(p, vec3(offset, 0., 0.), vec3(-1.5+1.*offset, 3., 0.), vec3(2.5+1.*offset, 3.5, 0.), bold1);
float d3 = sdBezier3D(p, vec3(2.*offset, 0., 0.), vec3(-1.3+2.*offset, 3., 0.), vec3(2.8+2.*offset, 3.9, 0.), bold1);
float d4 = sdBezier3D(p, vec3(3.*offset, 0., 0.), vec3(1., 3., 0.), vec3(2.5+3.*offset, 3., 0.), bold1);
float d5 = sdBezier3D(p, vec3(4.*offset, 0., 0.), vec3(1.5, 1.8, 0.), vec3(4.5+4.*offset, 1.9, 0.), bold1);
float d6 = sdBezier3D(p, vec3(5.*offset, 0., 0.), vec3(2., 1.5, 0.), vec3(5.+5.*offset, 1., 0.), bold1);
float minDist = min(
min(min(d1, d2), min(d3, d4)),
min(d5, d6)
);
float shape = clamp(.05, 0., 3.);
return vec2(FIN2, minDist-(shape));
}
vec2 sdFin3(vec3 p){
float bound = length(p - vec3(0., -2.5, 0.)) - 3.5;
if(bound > 1.) return vec2(FIN3, bound);
vec3 p_o = p;
float bold1 = 0.12;
float offset = .15;
float d1 = sdBezier3D(p, vec3(0., 0., 0.), vec3(-1., -3., 0.), vec3(.5, -3.2, 0.), bold1);
for(float i = 1.;i < 20.;i++){
d1 = min(d1, sdBezier3D(p, vec3(0.+i*offset, 0., 0.), vec3(-1.+1.5*i*offset, -2.5, 0.), vec3(.1+1.2*i*offset, -3.2-i*.01, 0.), bold1));
}
return vec2(FIN3, d1);
}
vec2 sdFin4(vec3 p){
p.z = abs(p.z);
p.z -= .6;
float bound = length(p - vec3(1.0, -1.0, 0.)) - 3.5;
if(bound > 1.) return vec2(FIN3, bound);
vec3 p_o = p;
float bold1 = 0.1;
float offset = .3;
float d1 = sdBezier3D(p, vec3(0., 0., 0.), vec3(-1., -1., 0.), vec3(2., -2.2, 0.), bold1);
for(float i = 1.;i < 4.;i++){
d1 = min(d1, sdBezier3D(p, vec3(0.+i*offset*.1, 0., 0.), vec3(-1.+1.5*i*offset, -1, 0.), vec3(2.-2.2*i*offset, -2.2+i*.65, 0.), bold1));
}
return vec2(FIN3, d1);
}
#define EYE 2.
vec2 sdEyes(vec3 p){
p.z = abs(p.z);
return vec2(EYE, length(p-vec3(-4.3, 0.0, .4))-.32);
}
vec2 map(vec3 p){
vec2 objFish = sdFish(p);
vec2 objFin1 = sdFin1(p);
vec2 objFin2 = sdFin2(p-vec3(-2., 1., 0.));
vec2 objFin3 = sdFin3(p-vec3(-3., -1., 0.));
vec2 objFin4 = sdFin4(p-vec3(-3.5, -.8, 0.));
vec2 objFins = objFin1;
if(objFin2.y < objFins.y) objFins = objFin2;
if(objFin3.y < objFins.y) objFins = objFin3;
if(objFin4.y < objFins.y) objFins = objFin4;
float d = smin(objFins.y, objFish.y, .12).x;
float id = (objFins.y < objFish.y) ? objFins.x : objFish.x;
vec2 obj = sdEyes(p);
if(obj.y < d){
d = obj.y;
id = obj.x;
}
return vec2(id, d);
}
vec3 gNor(vec3 p){
vec2 e = vec2(.001, 0.);
float d = map(p).y;
return normalize(vec3(
map(p+e.xyy).y - d,
map(p+e.yxy).y - d,
map(p+e.yyx).y - d
));
}
vec3 fishCol(vec3 p){
vec3 col;
vec3 mate = 1.4*mix(hsv(.64, .9, .9), hsv(.0, .8, .8), smoothstep(-0., 3.2, p.x))*(.7+1.2*fbm(p.xy*3.));
mate = mix(hsv(.0, .2, .8), mate, smoothstep(-6., -1., p.x));
mate = mix(mate*.2, mate, smoothstep(-10., 2., p.x));
mate = mix(mate*.1, mate, smoothstep(-1., 0., p.y));
mate = mix(mate*.1, mate, smoothstep(3., 0., p.y));
vec2 p2 = p.xy*13.;
vec2 p2_o = p2;
p2.x = mod(p2.x, 3.8)-1.7;
p2.y = mod(p2.y, 11.)-5.5;
p2.x *= 1.5;
p2.xy = rot(radians(30.))*p2.xy;
if(abs(sdHexagon2D(p2, 3.))-.2<0.)mate *= .6;
p2 = p2_o;
p2.x = mod(p2.x, 3.8)-1.7;
p2.y -= 5.5;
p2.y = mod(p2.y, 11.)-5.5;
if(sdSegment2D(p2, vec2(0., 2.3), vec2(0., -2.3))-.15<0.)mate *= .6;
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
vec3 fin1Col(vec3 p){
vec3 col;
vec3 mate = mix(hsv(.63, .8, .8), hsv(.0, .8, .8), smoothstep(-0., 3.2, p.x))*(1.+1.2*fbm(p.xy*3.));
mate = mix(hsv(.0, .2, .8), mate, smoothstep(-6., -1., p.x));
mate = mix(mate*.1, mate, smoothstep(-1., 2., abs(p.y)));
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
vec3 fin2Col(vec3 p){
vec3 col;
vec3 mate = mix(hsv(.61, .8, .8), hsv(.0, .8, .6), smoothstep(-0., 1.2, p.x))*(.7+1.2*fbm(p.xy*3.));
mate = mix(hsv(.0, .2, .8), mate, smoothstep(-6., -1., p.x));
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
vec3 fin3Col(vec3 p){
vec3 col;
vec3 mate = hsv(.0, .7, 1.3)*(.7+1.2*fbm(p.xy*3.));
mate = mix(mate*.1, mate, smoothstep(1., 3., abs(p.y)));
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
vec3 fin4Col(vec3 p){
vec3 col;
vec3 mate = hsv(.0, .7, .8);
mate = mix(mate*.1, mate, smoothstep(1., 3., abs(p.y)));
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
vec3 eyeCol(vec3 p){
vec3 col;
vec3 mate = hsv(.0, .7, .8)*.1;
vec3 nor = gNor(p);
float diff = clamp(dot(normalize(lightPos-p), nor), 0., 1.);
col = mate*diff+mate*.2;
return col;
}
void main() {
vec2 fragCoord = gl_FragCoord.xy;
vec2 uv = fragCoord/u_resolution.xy;
vec2 uv_o = uv;
vec2 p_o = uv*2.-1.;
uv.y *= 2.;
vec2 p = (fragCoord*2.-u_resolution.xy)/u_resolution.y;
vec3 col = hsv(.6, 1., .3*mix(.6, 0., smoothstep(0., 2., length(p))));
vec3 ro=vec3(-1., 0., 8.), cUp=vec3(0., 1., 0.), cDir=vec3(0., 0., -1.), cSide=cross(cDir, cUp), rd=normalize(cSide*p.x+cUp*p.y+cDir), ray;
ro.xz = rot2d(-.2+.2*sin(-u_time*1.2))*ro.xz;
rd.xz = rot2d(-.2+.2*sin(-u_time*1.2))*rd.xz;
float t=0.;
for(float i=0.;i < 80.;i++){
ray = ro+rd*t;
vec2 obj = map(ray);
if(obj.y<.001){
if(obj.x == FISH){
col =fishCol(ray);
}else if(obj.x == FIN1){
col =fin1Col(ray);
}else if(obj.x == FIN2){
col =fin2Col(ray);
}else if(obj.x == FIN3){
col =fin3Col(ray);
}else if(obj.x == EYE){
col =eyeCol(ray);
}
break;
}
t += .9*obj.y;
}
col = pow(col, vec3(.4545));
colour_out = vec4(col,1.0);
}
Betta beta by UK0141
uniform vec2 u_resolution;
uniform float u_time;
// utility
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);
}
mat2 rot(float a) {
float s = sin(a);
float c = cos(a);
return mat2(c, -s, s, c);
}
// water noise helpers
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
f = f * f * (3.0 - 2.0 * f);
float a = hash(i);
float b = hash(i + vec2(1.0, 0.0));
float c = hash(i + vec2(0.0, 1.0));
float d = hash(i + vec2(1.0, 1.0));
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
}
float fbm(vec2 p) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
for (int i = 0; i < 4; i++) {
value += amplitude * noise(p * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return value;
}
float waterNoise(vec2 uv, float t) {
vec2 p = uv * 5.0;
float ripple1 = sin(length(p - vec2(sin(t * 0.3) * 2.0, cos(t * 0.3) * 2.0)) * 8.0 - t * 2.0) * 0.5 + 0.5;
float ripple2 = sin(length(p - vec2(cos(t * 0.4) * 2.5, sin(t * 0.4) * 2.5)) * 6.0 - t * 1.5) * 0.5 + 0.5;
float wave1 = fbm(p * 0.5 + vec2(t * 0.1, t * 0.08));
float wave2 = fbm(p * 0.8 + vec2(-t * 0.12, t * 0.15));
float combined = wave1 * 0.4 + wave2 * 0.3;
combined += ripple1 * 0.2 + ripple2 * 0.1;
return combined;
}
// sdf shapes
float sdEllipse(vec2 p, vec2 r) {
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
float sdCrescent(vec2 p, float outerRadius, float innerRadius, float offset) {
float dOuter = length(p) - outerRadius;
float dInner = length(p - vec2(offset, 0.0)) - innerRadius;
return max(dOuter, -dInner);
}
float sdVesica(vec2 p, float r, float d) {
p = abs(p);
float b = sqrt(r*r - d*d);
return ((p.y-b)*d > p.x*b) ? length(p-vec2(0.0,b))
: length(p-vec2(-d,0.0))-r;
}
float sdRoundBottomTear(vec2 p, float tipRadius, float tipOffset, float baseRadius) {
if (p.y > 0.0) {
return sdVesica(p, tipRadius, tipOffset);
} else {
return length(p) - baseRadius;
}
}
vec2 applyFishWarp(vec2 p) {
vec2 fishPos = p;
float swim = sin(fishPos.x * 2.0 - u_time * 3.0) * 0.02 * smoothstep(0.5, -1.0, fishPos.x);
fishPos.y += swim;
return fishPos;
}
float sdGillShape(vec2 fishPos) {
vec2 gillUV = fishPos - vec2(0.55, 0.0);
gillUV *= rot(-3.0);
gillUV *= mat2(0.75, 0.0,
0.0, 1.0);
float dGill = sdCrescent(gillUV, 0.08, 0.12, -0.06);
return max(dGill, -(gillUV.x + 0.012));
}
// pectoral fin distance
float getPectoralDist(vec2 fishPos, float t) {
vec2 pecUV = fishPos - vec2(0.33, 0.0); //position
float flap = sin(t * -2.0) * 0.002;
pecUV *= rot(7.9 + flap);
pecUV.x += sin(pecUV.y * 80.0 - t * 4.0) * 0.003;
// overall pectoral fin scale
float k = 0.45;
float size = 0.50 * k; //len
float offset = 0.37 * k;
float base = size - offset;
float dFin = sdRoundBottomTear(pecUV, size, offset, base);
// fin cutout
vec2 cutCenter = vec2(0.02 * k, 0.0);
float cutRadius = 0.28 * k;
float cutCircle = sdCircle(pecUV - cutCenter, cutRadius);
dFin = max(dFin, cutCircle);
return dFin;
}
// main fish sdf
float mapFish(vec2 p) {
vec2 fishPos = applyFishWarp(p);
float dBody = sdEllipse(fishPos, vec2(0.75, 0.18));
float dHead = sdCircle(fishPos - vec2(0.4, -0.02), 0.12);
dBody = smin(dBody, dHead, 0.1);
// fins
//tail fin
vec2 tailUV = fishPos - vec2(-0.26, 0.0);
float fold = sin(tailUV.y * 60.0 - u_time * 2.0) * 0.012;
tailUV.x += fold;
float dTail = length(tailUV) - 0.52;
float tailCut = dot(tailUV, vec2(-0.9, 0.0)) + 0.35;
dTail = max(dTail, -tailCut);
//dorsal fin (top)
vec2 dorsalUV = fishPos - vec2(-0.15, 0.18);
dorsalUV *= rot(4.2);
dorsalUV.x += sin(dorsalUV.y * 100.0 + u_time) * 0.005;
float dDorsal = sdVesica(dorsalUV, 0.45, 0.05);
dDorsal = max(dDorsal, dorsalUV.y - 0.0);
//anal fin (bottom)
vec2 analUV = fishPos - vec2(-0.08, -0.18);
analUV *= rot(5.0);
analUV.x += sin(analUV.y * 100.0 - u_time * 1.5) * 0.005;
float dAnal = sdEllipse(analUV, vec2(0.38, 0.6));
dAnal = max(dAnal, analUV.y);
//gill
float dGill = sdGillShape(fishPos);
dBody = smin(dBody, dGill, 0.02);
// combine body and fins
float dMeltyFins = min(dTail, min(dDorsal, dAnal));
float dBaseFish = smin(dBody, dMeltyFins, 0.1);
return dBaseFish;
}
void main() {
vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution) / u_resolution.y;
st *= 1.2;
float d = mapFish(st);
vec2 warpedPos = applyFishWarp(st);
float gillDist = sdGillShape(warpedPos);
float pecDist = getPectoralDist(warpedPos, u_time);
// background color
vec3 color = vec3(0,0.52,0.84);
// circular gradient for fish color
vec2 center = vec2(0.4, 0.0);
float r = length(st - center);
float t = smoothstep(0.0, 1.0, r);
vec3 innerColor = vec3(0.00, 0.34, 0.84);
vec3 outerColor = vec3(1.00, 0.15, 0.00);
vec3 fishColor = mix(innerColor, outerColor, t);
float gillMask = smoothstep(0.01, -0.015, gillDist);
float pecMask = smoothstep(0.01, -0.01, pecDist);
if (d < 0.0) {
float light = smoothstep(0.0, 0.5, -d);
color = fishColor * (0.5 + 0.5 * light);
float rim = smoothstep(-0.05, 0.0, d);
color += vec3(0.5, 0.8, 1.0) * rim * 0.005;
}
color += vec3(0.2, 0.4, 0.9) * (0.01 / abs(d));
// gill
color = mix(color, vec3(1.0, 1.0, 1.0), gillMask);
// pectoral fin
if (pecMask > 0.0) {
vec3 pecColor = vec3(0.89, 0.14, 0.00);
// semi transparent blend
color = mix(color, pecColor, pecMask * 0.2);
}
// pectoral fin outline
float pecOutline = smoothstep(0.01, 0.001, abs(pecDist));
color += vec3(0.4, 0.6, 0.9) * pecOutline * 0.5;
// eye
float eyeDist = sdCircle(warpedPos - vec2(0.6, 0.03), 0.01);
float eyeMask = smoothstep(0.02, -0.005, eyeDist);
color = mix(color, vec3(1.0, 1.0, 1.0), eyeMask);
// water layer on top
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
float water = waterNoise(uv, u_time);
vec3 deepWater = vec3(0.00, 0.12, 0.34);
vec3 shallowWater = vec3(0.2, 0.6, 0.8);
vec3 foam = vec3(0.8, 0.9, 1.0);
vec3 waterColor = mix(deepWater, shallowWater, water);
waterColor = mix(waterColor, foam, smoothstep(0.2, 0.9, water));
float shimmer = fbm(uv * 10.0 + u_time * 0.5);
waterColor += shimmer * 0.8;
float waterAlpha = 0.15;
color = mix(color, waterColor, waterAlpha);
colour_out = vec4(color, 1.0);
}
Bicolor Delta Betta by JL
uniform vec2 u_resolution;
uniform float u_time;
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x * 34.0) + 1.0) * x);
}
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 = mod289(i);
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);
}
//Fractal Brownian Motion
float fbm(vec2 p, int octaves) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
for(int i = 0; i < 6; i++) {
if(i >= octaves) break;
value += amplitude * snoise(p * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return value;
}
//Ellipse SDF
float sdEllipse(vec2 p, vec2 ab) {
p = abs(p);
if(p.x > p.y) { p = p.yx; ab = ab.yx; }
float l = ab.y * ab.y - ab.x * ab.x;
float m = ab.x * p.x / l;
float m2 = m * m;
float n = ab.y * p.y / l;
float n2 = n * n;
float c = (m2 + n2 - 1.0) / 3.0;
float c3 = c * c * c;
float q = c3 + m2 * n2 * 2.0;
float d = c3 + m2 * n2;
float g = m + m * n2;
float co;
if(d < 0.0) {
float h = acos(q / c3) / 3.0;
float s = cos(h);
float t = sin(h) * sqrt(3.0);
float rx = sqrt(-c * (s + t + 2.0) + m2);
float ry = sqrt(-c * (s - t + 2.0) + m2);
co = (ry + sign(l) * rx + abs(g) / (rx * ry) - m) / 2.0;
} else {
float h = 2.0 * m * n * sqrt(d);
float s = sign(q + h) * pow(abs(q + h), 1.0 / 3.0);
float u = sign(q - h) * pow(abs(q - h), 1.0 / 3.0);
float rx = -s - u - c * 4.0 + 2.0 * m2;
float ry = (s - u) * sqrt(3.0);
float rm = sqrt(rx * rx + ry * ry);
co = (ry / sqrt(rm - rx) + 2.0 * g / rm - m) / 2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0 - co * co));
return length(r - p) * sign(p.y - r.y);
}
//Fish body parts SDFs
float bodyShape(vec2 p) {
vec2 bodyPos = p - vec2(0.57, 0.48);
float body = sdEllipse(bodyPos, vec2(0.24, 0.10));
return body;
}
//Tail
float tailShape(vec2 p, float time) {
vec2 tailCenter = vec2(0.47, 0.48);
vec2 tp = p - tailCenter;
float angle = atan(tp.y, tp.x);
float dist = length(tp);
float flow = snoise(vec2(angle * 3.0, time * 0.5)) * 0.03;
float flow2 = snoise(vec2(angle * 5.0 - time * 0.3, dist * 10.0)) * 0.02;
float baseRadius = 0.35;
float radiusVar = 0.04 * sin(angle * 8.0 + time * 0.5);
float noiseVar = fbm(vec2(angle * 4.0, time * 0.3), 3) * 0.04;
float tailRadius = baseRadius + radiusVar + noiseVar + flow + flow2;
float edgeDetail = snoise(vec2(angle * 12.0, time * 0.4)) * 0.02;
tailRadius += edgeDetail;
float innerRadius = 0.01;
float tail = dist - tailRadius;
float inner = innerRadius - dist;
return max(tail, inner);
}
//Fin
float ventralFinShape(vec2 p) {
vec2 finPos = p - vec2(0.60, 0.37);
//Fin rotation
float rotationAngle = -0.9;
float cosA = cos(rotationAngle);
float sinA = sin(rotationAngle);
finPos = vec2(
finPos.x * cosA - finPos.y * sinA,
finPos.x * sinA + finPos.y * cosA
);
float fin = sdEllipse(finPos, vec2(0.08, 0.04));
return fin;
}
//Colors and patterns
float scalePattern(vec2 p, float time) {
vec2 sp = p * 50.0;
sp.x += mod(floor(sp.y), 2.0) * 0.5;
vec2 cell = fract(sp) - 0.5;
float d = length(cell);
float movement = snoise(p * 20.0 + time * 0.1) * 0.1;
return smoothstep(0.4 + movement, 0.35 + movement, d);
}
float finStripes(vec2 p, float time) {
float stripes = sin(p.x * 80.0 + p.y * 40.0 + snoise(p * 10.0 + time * 0.2) * 2.0);
return stripes * 0.5 + 0.5;
}
//Body color
vec3 bodyColor(vec2 p, float time) {
vec3 tealDark = vec3(0.05, 0.25, 0.35);
vec3 tealLight = vec3(0.2, 0.55, 0.65);
vec3 tealHighlight = vec3(0.4, 0.75, 0.8);
float scales = scalePattern(p, time);
float grad = (p.y - 0.3) * 2.0;
grad += snoise(p * 8.0) * 0.2;
vec3 baseColor = mix(tealDark, tealLight, grad);
baseColor = mix(baseColor, tealHighlight, scales * 0.3);
float shimmer = snoise(p * 30.0 + vec2(time * 0.5, 0.0)) * 0.5 + 0.5;
baseColor += vec3(0.1, 0.15, 0.1) * shimmer * scales;
return baseColor;
}
//Tail color
vec3 tailColor(vec2 p, float time, float bodyDist) {
vec3 cyan = vec3(0.16, 0.71, 0.75);
vec3 blue = vec3(0.01, 0.43, 0.64);
vec3 darkBlue = vec3(0.0, 0.22, 0.48);
vec3 offWhite = vec3(0.9, 0.85, 0.85);
vec2 center = vec2(0.50, 0.48);
float distFromBody = length(p - center);
float gradientT = smoothstep(0.08, 0.35, distFromBody);
float noiseVal = fbm(p * 8.0 + time * 0.1, 3) * 0.3;
gradientT += noiseVal;
gradientT = clamp(gradientT, 0.0, 1.0);
vec3 color = mix(blue, cyan, gradientT);
color = mix(color, darkBlue, smoothstep(0.6, 1.0, gradientT));
float stripes = finStripes(p, time);
color = mix(color, color * 1.2, stripes * 0.15);
float edgeBrightness = smoothstep(0.2, 0.4, distFromBody) * 0.2;
color = mix(color, offWhite, edgeBrightness * (1.0 - abs(snoise(p * 20.0))));
return color;
}
//Small fin color
vec3 smallFinColor(vec2 p, float time) {
vec3 maroon = vec3(0.66, 0.094, 0.15);
vec3 lavender = vec3(0.71, 0.75, 0.86);
float noise = snoise(p * 15.0 + time * 0.2) * 0.5 + 0.5;
vec3 color = mix(maroon, lavender, noise);
float stripes = finStripes(p, time);
color = mix(color, color * 1.2, stripes * 0.2);
return color;
}
//Eye
float eyeShape(vec2 p) {
vec2 eyePos = p - vec2(0.78, 0.50);
return length(eyePos) - 0.012;
}
vec3 eyeColor(vec2 p) {
vec2 eyePos = p - vec2(0.68, 0.50);
vec3 color = vec3(0.02, 0.02, 0.05);
float highlight = smoothstep(0.008, 0.003, length(eyePos - vec2(-0.003, 0.003)));
color = mix(color, vec3(0.3, 0.35, 0.4), highlight * 0.5);
return color;
}
//Main
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
float aspect = u_resolution.x / u_resolution.y;
vec2 p = st;
p.x *= aspect;
p.x -= (aspect - 1.0) * 0.5;
float time = u_time;
vec3 bgDark = vec3(0.02, 0.03, 0.08);
vec3 bgLight = vec3(0.05, 0.08, 0.15);
float bgNoise = fbm(st * 3.0 + time * 0.05, 4) * 0.5 + 0.5;
vec3 background = mix(bgDark, bgLight, bgNoise * 0.3 + st.y * 0.2);
float caustic = snoise(st * 8.0 + time * 0.2) * snoise(st * 12.0 - time * 0.15);
vec3 causticBlue = vec3(0.0, 0.12, 0.26);
background += causticBlue * caustic;
float body = bodyShape(p);
float tail = tailShape(p, time);
float eye = eyeShape(p);
float ventralFin = ventralFinShape(p);
//Cutoff Parameters
float bodyY = 0.48;
float upperCutoffX = 0.58;
float upperAngle = 0.3;
float lowerCutoffX = 0.65;
float lowerAngle = -0.2;
float upperLineDist = (p.x - upperCutoffX) * cos(upperAngle) + (p.y - bodyY) * sin(upperAngle);
float lowerLineDist = (p.x - lowerCutoffX) * cos(lowerAngle) + (p.y - bodyY) * sin(lowerAngle);
//Tail visibility area
bool shouldDrawTail;
if(p.y >= bodyY) {
shouldDrawTail = (upperLineDist < 0.0);
} else {
shouldDrawTail = (lowerLineDist < 0.0);
}
vec3 color = background;
//Draw tail
if(tail < 0.0 && shouldDrawTail) {
vec3 fColor = tailColor(p, time, body);
float alpha = smoothstep(0.005, -0.005, tail);
color = mix(color, fColor, alpha);
}
//Draw body
if(body < 0.0) {
vec3 bColor = bodyColor(p, time);
color = bColor;
}
//Draw eye
if(eye < 0.0) {
vec3 eColor = eyeColor(p);
float alpha = smoothstep(0.002, -0.002, eye);
color = mix(color, eColor, alpha);
}
//Draw fin
if(ventralFin < 0.0) {
vec3 fColor = smallFinColor(p, time);
float alpha = smoothstep(0.003, -0.003, ventralFin);
color = mix(color, fColor, alpha);
}
//Add glowing effect
float fishDist;
if(body < 0.0) {
fishDist = body;
} else if(tail < 0.0 && shouldDrawTail) {
fishDist = tail;
} else {
fishDist = body;
}
float glow = exp(-fishDist * 15.0) * 0.15;
vec3 glowRed = vec3(0.64, 0.035, 0.07);
color += glowRed * glow;
colour_out = vec4(color, 1.0);
}
better (betta) on the way by Sun Chang
//Author Informations
//Author: LI Zhuohang, 5125EG13-0, use ameato9ei as my pseudonym if possible;)
//Fish Name: TryMouseInteractOnMeFish
//For complete html file, refer to github: https://github.com/takko9ei/WebGL_Course/blob/main/HW3-Procedual-design/assignment/betta-fish.html
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
// NOTICE: Chinese comment use UTF-8
// Function Definitions
// SDF Functions
float remap(float value, float origFrom, float origTo, float targetFrom, float targetTo) {
float normalizedValue = (value - origFrom) / (origTo - origFrom);
return targetFrom + (targetTo - targetFrom) * normalizedValue;
}
float getRuffleNoise(float angle, float time,float noiseScale) {
// numbers here has no special meaning, just random values
float noise = sin(angle * 8.3 + time * 2.0) * 0.5;
noise += sin(angle * 17.7 - time * 3.5) * 0.25;
noise += sin(angle * 37.9 + time * 4.5) * 0.125;
return noise * noiseScale; //the noise strength
}
vec3 getBodyPattern(vec2 uv, vec3 baseCol, vec3 scaleCol, vec3 hintCol, float scale, float rot, float iTime){
// geo calc
mat2 rotMat = mat2(cos(rot), -sin(rot), sin(rot), cos(rot));
vec2 st = rotMat * uv;
st *= scale * 7.0;
st.x += step(1.0, mod(st.y, 2.0)) * 0.5;
vec2 cellUV = fract(st);
cellUV.y = remap(cellUV.y, 0.0, 1.0, 0.0, 0.65); // 将 y 方向压缩为等边三角形高度比例
// dist
float d = length(cellUV - vec2(0.5, 0.0));
float scaleShape = smoothstep(0.65, 0.45, d);
// thickness
float shadow = smoothstep(0.2, 0.45, d);
// color mix
vec3 baseColor = baseCol;
vec3 scaleColor = scaleCol;
vec3 iridescent = hintCol * sin(uv.y * 5.0 + iTime*5.0 * 0.5);
// 混合:底色 + 鳞片形状 * (鳞片色 + 偏光)
// 减去 shadow 让边缘变暗,而不是变亮,这样看起来像凸起而不是孔洞
vec3 finalColor = baseColor + scaleShape * (scaleColor + iridescent) - shadow * 0.2;
return clamp(finalColor, 0.0, 1.0);
}
vec3 getFinPattern(vec2 uv, vec3 mainCol, vec3 subCol, float density, float rot, vec2 st, float scale, float iTime){
vec2 u0 = uv;
float speed = 0.5;
uv*=scale;
mat2 rotMat = mat2(cos(rot), sin(rot), -sin(rot), cos(rot));
uv = rotMat * uv;
uv -= st;
float shapeFactor = cos(clamp(uv.x * 1.2, -1.57, 1.57));
uv.y /= (shapeFactor * shapeFactor + 0.1);
for (int i = 0; i < 4; i++) {
float fi = float(i);
float offset = 0.15 / (fi + 1.0) * sin(fi * 3.0 * uv.y + iTime * speed + 0.3 * fi) + 0.5;
uv.x += offset;
uv.y += 0.1 / (fi + 1.0) * sin(fi * 4.0 * uv.x + iTime * speed * 0.8);
}
float pattern = sin(uv.x * density + uv.y * density);
pattern = abs(pattern);
pattern = 0.50 / max(pattern, 0.001); // max防止除0
pattern = pow(pattern,1.8);
pattern = min(pattern, 2.0);
vec3 col = mainCol;
col += vec3(0.2, 0.1, 0.4) * sin(u0.y * 2.0 + uv.y);
col *= pattern;
col += subCol * (1.0 - pattern);
float mask = smoothstep(0.0, 0.8, shapeFactor);
mask = pow(mask, 3.0);
//float vFade = 1.0 - smoothstep(0.5, 1.0, abs(u0.y));
col *= mask;// * vFade;
return col;
}
float sdEgg( vec2 p, float he, float ra, float rb, float bu )
{
float r = 0.5*(he + ra+rb)/bu;
float da = r - ra;
float db = r - rb;
float y = (db*db - da*da - he*he)/(2.0*he);
float x = sqrt(da*da - y*y);
p.x = abs(p.x);
float k = p.y*x - p.x*y;
if( k>0.0 && k<he*(p.x+x) )
return length(p+vec2(x,y))-r;
return min( length(p)-ra,
length(vec2(p.x,p.y-he))-rb );
}
float sdBettaTailShape( vec2 p, vec2 c, float r, float iTime )
{
float angle = atan(p.y, p.x);
float ruffleOffset = getRuffleNoise(angle, iTime,0.12) * r;
p.x = abs(p.x);
float l = length(p) - (r + ruffleOffset);
float m = length(p-c*clamp(dot(p,c),0.0,r));
return max(l,m*sign(c.y*p.x-c.x*p.y));
}
float sdOrientedVesica( vec2 p, vec2 a, vec2 b, float w )
{
float r = 0.5*length(b-a);
float d = 0.5*(r*r-w*w)/w;
vec2 v = (b-a)/r;
vec2 c = (b+a)*0.5;
vec2 q = 0.5*abs(mat2(v.y,v.x,-v.x,v.y)*(p-c));
vec3 h = (r*q.x<d*(q.y-r)) ? vec3(0.0,r,0.0) : vec3(-d,0.0,d+w);
return length( q-h.xy) - h.z;
}
float sdMoon(vec2 p, float d, float ra, float rb, float intensity, float iTime )
{
// 对称性
// 原函数利用了上下对称性。这意味着我们的噪声也会随之上下对称(镜像)。
// 如果想要非对称的噪声,需要修改这行代码的逻辑,但为了保持 SDF 算法的稳定性,
// 我们暂时保留这个对称性,这意味着月亮咬痕的上下两半是镜像的。
p.y = abs(p.y);
// 相对小圆心角度
// 小圆圆心在 (d, 0)。
// 我们需要计算当前点 p 到 (d, 0) 的向量。
vec2 relP = p - vec2(d, 0.0);
// 获取角度。atan(y, x) 返回弧度
float angle = atan(relP.y, relP.x);
//扰动后半径
// 这里的 rb 变成了变量
// 注意:我们把 getNoise 的结果加到 rb 上
float rbNoisy = rb + getRuffleNoise(angle,iTime, intensity);
//原本公式中所有用到 rb 的地方,现在全部都要换成 rbNoisy
float a = (ra*ra - rbNoisy*rbNoisy + d*d)/(2.0*d);
float b = sqrt(max(ra*ra-a*a,0.0));
if( d*(p.x*b-p.y*a) > d*d*max(b-p.y,0.0) )
return length(p-vec2(a,b));
return max( (length(p)-ra),
-(length(p-vec2(d,0))-rbNoisy));
}
//do not use this directly, use sUnion instead
//this method encapsuled in the sUnion func
float sMinCubic( float a, float b, float k )
{
float h = max( k - abs(a-b), 0.0 )/k;
return min( a, b ) - h*h*h*k*(1.0/6.0);
}
float sDiffCubic( float d1, float d2, float k )
{
float h = max( k - abs(d1 + d2), 0.0 )/k;
return max( d1, -d2 ) + h*h*h*k*(1.0/6.0);
}
//input: 1d distance and 3d color.
//this function returns the smooth union of d(sdf result) and color
vec4 sUnion(vec4 dc1, vec4 dc2, float k) {
float h = clamp( 0.5 + 0.5 * (dc1.x - dc2.x) / k, 0.0, 1.0 );
float dist = sMinCubic(dc1.x, dc2.x, k);
vec3 col = mix(dc1.yzw, dc2.yzw, h);
return vec4(dist, col);
}
float hash( vec2 p ) {
p = vec2( dot(p,vec2(127.1,311.7)),
dot(p,vec2(269.5,183.3)) );
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}
//value noise
float noise( vec2 x ) {
vec2 i = floor(x);
vec2 f = fract(x);
//smoothstep for interpolation
vec2 u = f*f*(3.0-2.0*f);
//random values for the 4 corners of the cell
float a = hash( i + vec2(0.0,0.0) );
float b = hash( i + vec2(1.0,0.0) );
float c = hash( i + vec2(0.0,1.0) );
float d = hash( i + vec2(1.0,1.0) );
//bilinearly interpolate
return mix(mix( a, b, u.x), mix( c, d, u.x), u.y);
}
//returns the distances to the nearest and second-nearest cell centers
vec2 voronoi(vec2 uv, float time) {
vec2 g = floor(uv); // Grid cell
vec2 f = fract(uv); // Position within cell
vec2 closest = vec2(1.0); // .x is dist to nearest, .y is dist to 2nd nearest
//check 3x3 grid of cells around the current one
for (int y = -1; y <= 1; y++) {
for (int x = -1; x <= 1; x++) {
vec2 offset = vec2(x, y);
vec2 cellPos = g + offset;
// pseudo random anime
float h = hash(cellPos);
vec2 pointPos = 0.5 + 0.4 * vec2(sin(time * 0.7 + h * 6.28), cos(time * 0.7 + h * 6.28)); // 2*PI
float dist = length(offset + pointPos - f);
//update two closest distances
if (dist < closest.x) {
closest.y = closest.x;
closest.x = dist;
} else if (dist < closest.y) {
closest.y = dist;
}
}
}
return closest;
}
vec3 getWavePattern(vec2 uv, vec3 mainCol, vec3 subCol, float scale, float iTime) {
vec2 scaledUV = uv * scale * 6.0;
vec2 dists = voronoi(scaledUV, iTime);
// The first distance gives a nice gradient within the cell
float cellInterior = dists.x;
// The difference between the two distances defines the cell edge
float edgeDistance = dists.y - dists.x;
vec3 waterColor = mainCol;
waterColor = mix(subCol, waterColor, smoothstep(0.0, 0.4, cellInterior));
//flicker mask
float flickerNoiseSample = noise(scaledUV * 0.5 + iTime * 0.2);
//a second, smoother noise for shimmer instead of a raw hash
float shimmerNoise = noise(scaledUV * 1.5 + iTime * -0.5);
float shimmer = (0.6 + 0.4 * sin(iTime * 8.0 + shimmerNoise * 6.28));
float flickerMask = mix(0.5, 1.0, flickerNoiseSample);
flickerMask *= shimmer;
//bloom effect
float edgeWidth = fwidth(edgeDistance) * 1.5; // Get pixel width for AA
//sharp core
float sharpGlow = pow(1.0 - smoothstep(0.0, edgeWidth * 2.0, edgeDistance), 40.0);
//softer bloom
float softGlow = pow(1.0 - smoothstep(0.0, edgeWidth * 8.0, edgeDistance), 10.0);
//combine the bloom layers
float totalBloom = sharpGlow * 1.0 + softGlow * 0.3;
//combine bloom with the flicker mask
float sparkle = totalBloom * flickerMask;
vec3 sparkleColor = vec3(0.9, 1.0, 1.0);
//combine water color with the sparkling highlights
vec3 finalColor = waterColor + sparkle * sparkleColor;
return clamp(finalColor, 0.0, 1.0);
}
vec2 getWaterRipple(vec2 uv, vec2 center, float time) {
vec2 dv = center - uv;
float dis = length(dv);
//ripple parameters
float frequency = 15.0;
float speed = 5.0;
float maxRadius = 1.2;
float amplitude = 0.03;
//sine Factor (The wave)
//usually "- time" looks like expanding waves, "+ time" looks like imploding.
float sinFactor = sin(dis * frequency - time * speed);
//damping/Falloff
//limits the effect to a specific radius and fades it out at the edges
float damp = max(0.0, maxRadius - dis);
damp = pow(damp, 2.0);
vec2 dir = normalize(dv);
//avoid 0/0
if (dis < 0.0001) dir = vec2(0.0);
//final offset
return dir * sinFactor * damp * amplitude;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
// st: left bottom (0,0) to right top (1,1), linear
vec2 centcoord = st * 2.0 - 1.0;
vec2 mousePos = u_mouse.xy / u_resolution.xy;
vec2 rippleCenter = mousePos * 2.0 - 1.0;
//calculate the offset
vec2 rippleOffset = getWaterRipple(centcoord, rippleCenter, u_time);
//apply offset
centcoord += rippleOffset;
// centcoord: left bottom (-1,-1) to right top (1,1), linear
vec3 bodyColor = getBodyPattern(centcoord,vec3(0.4314, 0.1765, 0.502), vec3(0.2, 0.7, 0.8), vec3(0.3765, 0.1608, 0.8039),1.952,2.032, u_time);
vec3 backfinColor = getFinPattern(centcoord,vec3(0.1608, 0.5961, 0.7843),vec3(0.3451, 0.0235, 0.0235),23.0,-0.192,vec2(-0.200,0.590),1.128,u_time);
vec3 bellyfinColor = getFinPattern(centcoord,vec3(0.1647, 0.5686, 0.8784),vec3(0.3451, 0.0235, 0.0235),21.0,-0.856,vec2(0.480,0.630),1.80,u_time);
vec3 tailColor = getFinPattern(centcoord,vec3(0.1412, 0.502, 0.7804),vec3(0.3451, 0.0235, 0.0235),18.0,-0.416,vec2(-0.790,0.580),1.0,u_time);
vec3 waterColor = getWavePattern(centcoord, vec3(0.3686, 0.7176, 0.7686), vec3(0.549, 0.7922, 0.8039), 0.7, u_time);
vec2 uv = centcoord;
// --- 1. THE HEAD (ID:0) ---
vec2 p0 = centcoord - vec2(0.300, -0.080);
vec2 a0 = vec2(0.640, 0.760);
vec2 b0 = vec2(0.140, 0.120);
float w0 = 0.176;
float d0 = sdOrientedVesica(p0, a0, b0, w0);
// --- 2. THE BODY (ID:1) ---
vec2 p1 = centcoord - vec2(0.640, 0.340);
float theta1 = -4.256;
mat2 rotate1 = mat2(cos(theta1), -sin(theta1), sin(theta1), cos(theta1));
float he1 = 0.488;
float ra1 = 0.204;
float rb1 = 0.144;
float bu1 = 0.528;
float d1 = sdEgg(rotate1 * p1, he1, ra1, rb1, bu1);
// --- 3. THE TAIL (ID:2) ---
vec2 p2 = centcoord - vec2(0.140, 0.140);
float theta2 = -4.360;
mat2 rotate2 = mat2(cos(theta2), -sin(theta2), sin(theta2), cos(theta2));
vec2 c2 = vec2(0.920, 0.280);
float r2 = 1.00;
float itime2 = u_time;
float d2 = sdBettaTailShape(rotate2 * p2, c2, r2, itime2);
//--- 4. THE BACK FIN (ID:3) ---
vec2 p3 = centcoord - vec2(-0.610,0.410);
float theta3 = 0.448;
mat2 rotate3 = mat2(cos(theta3), -sin(theta3), sin(theta3), cos(theta3));
float cfactor = 0.736;
mat2 compress = mat2(cfactor*st.x,0,0,1);
float pm3 = -0.440;
float ra3 = 0.480;
float rb3 = 0.688;
float iTime3 = u_time;
float intensity3 = 0.042;
float d3 = sdMoon(rotate3*compress*p3,pm3,ra3,rb3,intensity3,iTime3);
// --- 5. The belly fin(ID:4) ---
vec2 p4 = centcoord - vec2(0.390,0.050);
float theta4 = -5.408;
mat2 rotate4 = mat2(cos(theta4), -sin(theta4), sin(theta4), cos(theta4));
float pm4 = -0.752;
float ra4 = 0.376;
float rb4 = 0.616;
float iTime4 = u_time;
float intensity4 = 0.042;
float d4 = sdMoon(rotate4*p4,pm4,ra4,rb4,intensity4,iTime4);
// COLOR
// --- 6. CLIP AND COMBINE ---
float headBodyK = 0.096;
float finK = 0.04;
//k for smooth union & color lerp factor
float clipMargin = -0.01;
float dHeadbody = sMinCubic(d0, d1, headBodyK);
float dTail = d2;
float dBackfin = d3;
float dBellyfin = d4;
//we use xxCore for and ONLY for clipping redundant d of fin
float dBodyCore = dHeadbody + clipMargin;
float dTailCore = dTail + clipMargin-0.1;
dBackfin = sDiffCubic(dBackfin, dBodyCore, 0.02);
dBellyfin = sDiffCubic(dBellyfin, dBodyCore, 0.02);
dBellyfin = sDiffCubic(dBellyfin, d3, 0.02);
dBellyfin = sDiffCubic(dBellyfin,dTailCore,0.02);
vec4 tempRes = vec4(dHeadbody, bodyColor);
tempRes = sUnion(tempRes, vec4(dBackfin, backfinColor), finK);
tempRes = sUnion(tempRes, vec4(dBellyfin, bellyfinColor), finK);
if(dBackfin<0.0&&dTail<0.01){
tempRes.yzw = tailColor;
}
tempRes = sUnion(tempRes,vec4(dTail,tailColor), finK);
float dFinal = tempRes.x;
float mask = step(dFinal,0.0);
float eyeMask = step(length(centcoord - vec2(0.800, 0.53)) , 0.0450);
eyeMask = remap(eyeMask, 0.0, 1.0, 1.0, 0.0);
float eyeMaskHighlight = step(length(centcoord - vec2(0.790, 0.54)) , 0.01);
//eyeMaskHighlight = remap(eyeMaskHighlight, 0.0, 1.0, 1.0, 0.0);
//temp cancel
// Output color
//colour_out = vec4(tempRes.yzw,1.0);
colour_out = mask * vec4(tempRes.yzw, 1.0)+ (1.0 - mask) * vec4(waterColor, 1.0);
//the most violent way to draw eye
colour_out.xyz = colour_out.xyz * eyeMask;
colour_out.xyz += eyeMaskHighlight * vec3(1.0, 1.0, 1.0);
colour_out = clamp(colour_out, 0.0, 1.0);
}
TryMouseInteractOnMeFish by ameato9ei
uniform vec2 u_resolution;
uniform float u_time;
// --- SDF関数群 ---
// 回転行列(ラジアン)
mat2 rot(float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c);
}
// 角度(度)から回転した方向ベクトルを返す
vec2 rotateDir(float deg) {
vec2 dir0 = normalize(vec2(0.0, -1.0));
return rot(radians(deg)) * dir0;
}
// 楕円の SDF
float sdEllipse(vec2 p, vec2 center, vec2 radius, float angle) {
vec2 q = rot(angle) * (p - center);
return length(q / radius) - 1.0;
}
// 角丸矩形の SDF
float sdBox(vec2 p, vec2 center, vec2 halfSize, float angle, float r) {
vec2 q = rot(angle) * (p - center);
vec2 d = abs(q) - halfSize;
return length(max(d, 0.0)) - r;
}
// 円の SDF
float sdCircle(vec2 p, vec2 center, float radius) {
return length(p - center) - radius;
}
// 扇形(円と角度範囲の共通部分)
float sdFan(vec2 p, vec2 center, float radius, vec2 dir, float theta) {
vec2 q = p - center;
float r = length(q) - radius;
float ang = acos(clamp(dot(normalize(q), dir), -1.0, 1.0));
float a = ang - theta;
return max(r, a);
}
// 三角形の SDF
float sdTriangle(vec2 p, vec2 a, vec2 b, vec2 c) {
vec2 ba = b - a; vec2 pa = p - a;
vec2 cb = c - b; vec2 pb = p - b;
vec2 ac = a - c; vec2 pc = p - c;
vec2 nor = vec2(ba.y, -ba.x);
float s = sign(dot(nor, p - a));
float h1 = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
float h2 = clamp(dot(pb, cb) / dot(cb, cb), 0.0, 1.0);
float h3 = clamp(dot(pc, ac) / dot(ac, ac), 0.0, 1.0);
float d1 = length(pa - ba * h1);
float d2 = length(pb - cb * h2);
float d3 = length(pc - ac * h3);
return min(min(d1, d2), d3) * s;
}
// 平行四辺形の SDF(中心、サイズ、回転角度、シア量)
float sdParallelogram(vec2 p, vec2 center, vec2 size, float angle, float skew) {
vec2 q = p - center;
q = rot(angle) * q;
return max(
abs(q.x - skew * q.y) - size.x * 0.5,
abs(q.y) - size.y * 0.5
);
}
// Noise2D関数
// Description : Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(vec2 v)
{
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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 / u_resolution;
vec2 p = uv;
// 1. 背景 (黒)
vec3 col = vec3(0.0);
// 座標変換: 魚全体を少し揺らす
float t = u_time * 2.0;
vec2 offset = vec2(0.0, 0.02 * sin(t));
p -= offset;
// --- レイヤー描画 (奥から順に上書き) ---
// 2. 尾びれ (赤)
// 上の大きな扇
float tailTop = sdFan(
p,
vec2(0.32, 0.45), // ヒレの中心位置
0.60, // 半径(大きさ)
rotateDir(-110.0), // 回転後の方向ベクトル
0.7 // 開き具合(角度の広さ)
);
if (tailTop < 0.0) {
vec2 finLocal = rot(-radians(110.0)) * (p - vec2(0.32, 0.45));
float finRadius = clamp(length(finLocal) / 0.60, 0.0, 1.0);
// 中心からの角度を計算(放射状の線用)
float angle = atan(finLocal.y, finLocal.x);
float normalizedAngle = (angle + 3.14159265359) / (2.0 * 3.14159265359); // 0〜1に正規化
// ノイズを使って放射状の線を生成
vec2 noiseCoord = vec2(normalizedAngle * 20.0, finRadius * 10.0);
noiseCoord.x = noiseCoord.x * 10.0;
float noiseValue = snoise(noiseCoord);
float radialLines = smoothstep(0.3, 0.7, noiseValue); // ノイズから線を抽出
vec3 finColorA = vec3(0.80);
vec3 finColorB = vec3(0.004, 0.114, 0.275) * 1.3;
vec3 finColorC = vec3(0.655, 0.133, 0.063);
float s1 = 0.3;
float s2 = 0.75;
vec3 finColor;
if (finRadius < s1) {
// 内側: finColorA → finColorB
float t = finRadius / s1;
finColor = mix(finColorA, finColorB, t);
} else if (finRadius < s2) {
// 中間: finColorB → finColorC
float t = (finRadius - s1) / (s2 - s1);
finColor = mix(finColorB, finColorC, t);
} else {
// 外側: finColorC を維持
finColor = finColorC;
}
// 放射状の線を色に反映(線の部分を少し暗くする)
finColor = mix(finColor, finColor * 0.6, radialLines * 0.4);
col = finColor;
}
// 下の扇
float tailBot = sdFan(
p,
vec2(0.32, 0.40), // ヒレの中心位置
0.28, // 半径(大きさ)
rotateDir(-40.0), // 回転後の方向ベクトル
0.7 // 開き具合(角度の広さ)
);
if (tailBot < 0.0) {
// 中心からの距離を 0〜1 に正規化
vec2 finLocal = rot(-radians(110.0)) * (p - vec2(0.32, 0.45));
float finRadius = clamp(length(finLocal) / 0.28, 0.0, 1.0);
// 中心からの角度を計算(放射状の線用)
float angle = atan(finLocal.y, finLocal.x);
float normalizedAngle = (angle + 3.14159265359) / (2.0 * 3.14159265359); // 0〜1に正規化
// ノイズを使って放射状の線を生成
vec2 noiseCoord = vec2(normalizedAngle * 20.0, finRadius * 10.0);
noiseCoord.x = noiseCoord.x * 10.0;
float noiseValue = snoise(noiseCoord);
float radialLines = smoothstep(0.3, 0.7, noiseValue); // ノイズから線を抽出
vec3 finColorA = vec3(0.80);
vec3 finColorB = vec3(0.004, 0.114, 0.275) * 1.3;
vec3 finColorC = vec3(0.655, 0.133, 0.063);
float s1 = 0.5;
float s2 = 0.75;
vec3 finColor;
if (finRadius < s1) {
// 内側: finColorA → finColorB
float t = finRadius / s1;
finColor = mix(finColorA, finColorB, t);
} else if (finRadius < s2) {
// 中間: finColorB → finColorC
float t = (finRadius - s1) / (s2 - s1);
finColor = mix(finColorB, finColorC, t);
} else {
// 外側: finColorC を維持
finColor = finColorC;
}
// 放射状の線を色に反映(線の部分を少し暗くする)
finColor = mix(finColor, finColor * 0.7, radialLines * 0.3);
col = finColor;
}
// 3. 腹びれ
float analFin = sdParallelogram(
p,
vec2(0.45, 0.22), // 中心位置
vec2(0.18, 0.07), // サイズ(縦横)
radians(-35.0), // 回転角度
0.10 // x方向へのシア
);
if (analFin < 0.0) {
// ノイズを使って放射状の線を生成
float radius = clamp(length(p) / 0.18, 0.0, 1.0);
vec2 p_temp = vec2(p.x*10.0, p.y*10.0);
float noiseValue = snoise(p_temp);
vec3 finColorA = vec3(0.55, 0.12, 0.12)*1.3;
vec3 finColorB = vec3(0.10);
vec3 finColor_temp = mix(finColorA, finColorB, radius);
vec3 finColor = mix(finColor_temp, finColor_temp * 0.7, noiseValue * 0.3);
col = finColor;
}
// 奥のヒレ
float pecFinBack = sdFan(
p,
vec2(0.65, 0.20), // ヒレの中心位置
0.12, // 半径(大きさ)
rotateDir(-82.0), // 回転後の方向ベクトル
0.7 // 開き具合(角度の広さ)
);
if (pecFinBack < 0.0) {
// 扇形に沿ったグラデーション(中心から扇の外周へ向かう)
vec2 finLocal = rot(-radians(82.0)) * (p - vec2(0.65, 0.20));
float finRadius = clamp(length(finLocal) / 0.12, 0.0, 1.0);
// 中心からの角度を計算(放射状の線用)
float angle = atan(finLocal.y, finLocal.x);
float normalizedAngle = (angle + 3.14159265359) / (2.0 * 3.14159265359); // 0〜1に正規化
// ノイズを使って放射状の線を生成
vec2 noiseCoord = vec2(normalizedAngle * 20.0, finRadius * 10.0);
noiseCoord.x = noiseCoord.x * 10.0;
float noiseValue = snoise(noiseCoord);
float radialLines = smoothstep(0.3, 0.7, noiseValue); // ノイズから線を抽出
vec3 finColorA = vec3(0.55, 0.12, 0.12)*1.3;
vec3 finColorB = vec3(0.10);
vec3 finColor_temp = mix(finColorA, finColorB, finRadius);
vec3 finColor = mix(finColor_temp, finColor_temp * 0.7, radialLines * 0.4);
col = finColor;
}
// 6. 胴体 (グレー) - 斜めの楕円 + パターン
float body = sdEllipse(p, vec2(0.50, 0.30), vec2(0.24, 0.095), radians(-40.0));
// 5. 尾の付け根 - 胴体と尾の間にある三角形
float tailJoint = sdFan(
p,
vec2(0.41, 0.57), // 中心位置(調整可)
0.17, // 半径
rotateDir(25.0), // 方向
0.25 // 開き具合(狭めに)
);
if (body < 0.0 || tailJoint < 0.0) {
vec2 patternP = p;
patternP *= 30.0;
// 胴体の傾きに合わせてパターンを回転(-40度)
patternP = rot(radians(40.0)) * patternP;
vec2 s = vec2(2.0, 1.0);
patternP = mod(patternP, s) - vec2(0.5 * s.x, 0.0);
patternP.x = abs(patternP.x);
float d0 = length(patternP - vec2(0.0, s.y));
float d1 = length(patternP - 0.5 * s);
float d2 = length(patternP);
float d3 = length(patternP - 0.5 * vec2(s.x, -s.y));
float a = 3.14159265359 * 2.0 * 4.0;
float e1 = 0.2;
float e2 = 0.01;
float v = smoothstep(-e1, e1, sin(d0 * a));
v = mix(v, smoothstep(-e1, e1, sin(d1 * a)), 1.0 - smoothstep(s.y - e2, s.y, d1));
v = mix(v, smoothstep(-e1, e1, sin(d2 * a)), 1.0 - smoothstep(s.y - e2, s.y, d2));
v = mix(v, smoothstep(-e1, e1, sin(d3 * a)), 1.0 - smoothstep(s.y - e2, s.y, d3));
// パターンとグレーを組み合わせ
col = mix(vec3(0.8), vec3(v), 0.2);
}
// 中央の扇
float tailMid = sdFan(
p,
vec2(0.31, 0.40), // ヒレの中心位置
0.45, // 半径(大きさ)
rotateDir(-185.0), // 回転後の方向ベクトル
0.5 // 開き具合(角度の広さ)
);
if (tailMid < 0.0) {
vec2 finLocal = rot(-radians(110.0)) * (p - vec2(0.32, 0.45));
float finRadius = clamp(length(finLocal) / 0.45, 0.0, 1.0);
// 中心からの角度を計算(放射状の線用)
float angle = atan(finLocal.y, finLocal.x);
float normalizedAngle = (angle + 3.14159265359) / (2.0 * 3.14159265359); // 0〜1に正規化
// ノイズを使って放射状の線を生成
vec2 noiseCoord = vec2(normalizedAngle * 20.0, finRadius * 10.0);
noiseCoord.x = noiseCoord.x * 10.0;
float noiseValue = snoise(noiseCoord);
float radialLines = smoothstep(0.3, 0.7, noiseValue); // ノイズから線を抽出
vec3 finColorA = vec3(0.80);
vec3 finColorB = vec3(0.004, 0.114, 0.275) * 1.3;
vec3 finColorC = vec3(0.655, 0.133, 0.063);
float s1 = 0.3;
float s2 = 0.75;
vec3 finColor;
if (finRadius < s1) {
// 内側: finColorA → finColorB
float t = finRadius / s1;
finColor = mix(finColorA, finColorB, t);
} else if (finRadius < s2) {
// 中間: finColorB → finColorC
float t = (finRadius - s1) / (s2 - s1);
finColor = mix(finColorB, finColorC, t);
} else {
// 外側: finColorC を維持
finColor = finColorC;
}
// 放射状の線を色に反映(線の部分を少し暗くする)
finColor = mix(finColor, finColor * 0.7, radialLines * 0.3);
col = finColor;
}
// 7. 口 (濃いグレー) - 先端の四角
float mouth = sdParallelogram(
p,
vec2(0.662, 0.147), // 中心位置
vec2(0.06, 0.04), // サイズ(縦横)
radians(-0.0), // 回転角度
0.20 // x方向へのシア
);
if (mouth < 0.0) col = vec3(0.5);
// 9. 胸びれ (濃い赤) - エラ部分にある扇形
// 手前のヒレ
vec2 frontFinCenter = vec2(0.58, 0.20);
float pecFinFront = sdFan(p, frontFinCenter, 0.12, rotateDir(88.0), 0.8);
if (pecFinFront < 0.0) {
// 扇形に沿ったグラデーション(中心から扇の外周へ向かう)
vec2 finLocal = rot(-radians(88.0)) * (p - frontFinCenter);
float finRadius = clamp(length(finLocal) / 0.12, 0.0, 1.0);
// 中心からの角度を計算(放射状の線用)
float angle = atan(finLocal.y, finLocal.x);
float normalizedAngle = (angle + 3.14159265359) / (2.0 * 3.14159265359); // 0〜1に正規化
// ノイズを使って放射状の線を生成
vec2 noiseCoord = vec2(normalizedAngle * 20.0, finRadius * 10.0);
noiseCoord.x = noiseCoord.x * 10.0;
float noiseValue = snoise(noiseCoord);
float radialLines = smoothstep(0.3, 0.7, noiseValue); // ノイズから線を抽出
vec3 finColorA = vec3(0.55, 0.12, 0.12)*1.3;
vec3 finColorB = vec3(0.10);
vec3 finColor_temp = mix(finColorA, finColorB, finRadius);
vec3 finColor = mix(finColor_temp, finColor_temp * 0.7, radialLines * 0.4);
col = finColor;
}
// 8. 目 (白・黒)
float eyeWhite = sdEllipse(p, vec2(0.605, 0.18), vec2(0.018, 0.023), radians(-20.0));
float eyeBlack = sdEllipse(p, vec2(0.605, 0.18), vec2(0.01, 0.015), radians(-20.0));
if (eyeWhite < 0.0) col = vec3(1.0);
if (eyeBlack < 0.0) col = vec3(0.0);
colour_out = vec4(col, 1.0);
}
Unknown by Manchonot
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
///////////////////////////////////
// Modulo 289 without a division (only multiplications)
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
// Modulo 7 without a division
vec3 mod7(vec3 x) {
return x - floor(x * (1.0 / 7.0)) * 7.0;
}
// Permutation polynomial: (34x^2 + x) mod 289
vec3 permute(vec3 x) {
return mod289((34.0 * x + 1.0) * x);
}
// Cellular noise, returning F1 and F2 in a vec2.
// Standard 3x3 search window for good F1 and F2 values
vec2 cellular(vec2 P) {
const float K = 0.142857142857; // 1/7
const float Ko = 0.428571428571; // 3/7
const float jitter = 1.0; // Less gives more regular pattern
vec2 Pi = mod289(floor(P));
vec2 Pf = fract(P);
vec3 oi = vec3(-1.0, 0.0, 1.0);
vec3 of = vec3(-0.5, 0.5, 1.5);
vec3 px = permute(Pi.x + oi);
vec3 p = permute(px.x + Pi.y + oi); // p11, p12, p13
vec3 ox = fract(p * K) - Ko;
vec3 oy = mod7(floor(p * K))*K - Ko;
vec3 dx = Pf.x + 0.5 + jitter * ox;
vec3 dy = Pf.y - of + jitter * oy;
vec3 d1 = dx * dx + dy * dy; // d11, d12 and d13, squared
p = permute(px.y + Pi.y + oi); // p21, p22 and p23
ox = fract(p * K) - Ko;
oy = mod7(floor(p * K))*K - Ko;
dx = Pf.x - 0.5 + jitter * ox;
dy = Pf.y - of + jitter * oy;
vec3 d2 = dx * dx + dy * dy; // d21, d22 and d23, squared
p = permute(px.z + Pi.y + oi); // p31, p32 and p33
ox = fract(p * K) - Ko;
oy = mod7(floor(p * K))*K - Ko;
dx = Pf.x - 1.5 + jitter * ox;
dy = Pf.y - of + jitter * oy;
vec3 d3 = dx * dx + dy * dy; // d31, d32 and d33, squared
// Sort out the two smallest distances (F1, F2)
vec3 d1a = min(d1, d2);
d2 = max(d1, d2); // Swap to keep candidates for F2
d2 = min(d2, d3); // neither F1 nor F2 are now in d3
d1 = min(d1a, d2); // F1 is now in d1
d2 = max(d1a, d2); // Swap to keep candidates for F2
d1.xy = (d1.x < d1.y) ? d1.xy : d1.yx; // Swap if smaller
d1.xz = (d1.x < d1.z) ? d1.xz : d1.zx; // F1 is in d1.x
d1.yz = min(d1.yz, d2.yz); // F2 is now not in d2.yz
d1.y = min(d1.y, d1.z); // nor in d1.z
d1.y = min(d1.y, d2.x); // F2 is in d1.y, we're done.
return sqrt(d1.xy);
}
// Demo mapping
float colorMapping(vec2 xy) {
return cellular(xy).x * 2.0 - 1.0;
}
///////////////////////////////////
float dot2(vec2 v) {
return dot(v, v);
}
float swimPhase() {
return u_time * 0.8;
}
float pectoralPhase(){
return u_time * 0.5;
}
const float PEC_BASE_ANGLE_DEG = -75.0;
// convert degree to rad
float deg2rad(float d) {
return d * 3.14159265 / 180.0;
}
float pectoralSwingOneSide() {
float s = sin(pectoralPhase());
return s;
}
// 1D Hash. 10 and 10000 aren't ideal, but oh well, good enough
float hash1(float n) {
return fract(sin(n * 10.0) * 10000.0);
}
// basic sdBezier
float sdBezier(in vec2 pos, in vec2 A, in vec2 B, in vec2 C)
{
vec2 a = B - A;
vec2 b = A - 2.0 * B + C;
vec2 c = a * 2.0;
vec2 d = A - pos;
float kk = 1.0 / dot(b, b + 1e-9); // anti-zero division
float kx = kk * dot(a, b);
float ky = kk * (2.0 * dot(a, a) + dot(d, b)) / 3.0;
float kz = kk * dot(d, a);
float res = 0.0;
float p = ky - kx * kx;
float p3 = p * p * p;
float q = kx * (2.0 * kx * kx - 3.0 * ky) + kz;
float h = q * q + 4.0 * p3;
if (h >= 0.0)
{
h = sqrt(h);
vec2 x = (vec2(h, -h) - q) / 2.0;
vec2 uv = sign(x) * pow(abs(x), vec2(1.0 / 3.0));
float t = clamp(uv.x + uv.y - kx, 0.0, 1.0);
res = dot2(d + (c + b * t) * t);
}
else
{
float z = sqrt(-p);
float v = acos(q / (p * z * 2.0)) / 3.0;
float m = cos(v);
float n = sin(v) * 1.732050808; // sqrt(3)
vec3 t = clamp(vec3(m + m, -n - m, n - m) * z - kx, 0.0, 1.0);
res = min(
dot2(d + (c + b * t.x) * t.x),
dot2(d + (c + b * t.y) * t.y)
);
}
return sqrt(res);
}
// basic fin for that tail. Used for most stuff
float sdTailFin(
vec2 p,
vec2 A0, vec2 B0, vec2 C0,
float freq,
float ampB, float ampC,
float phaseC,
float phaseOffset, // phase offset to change the phase of other fins
float thickness
) {
vec2 AB0 = B0 - A0;
vec2 AC0 = C0 - A0;
float rB = length(AB0);
float rC = length(AC0);
// initial angle at t=0
float baseAngleB = atan(AB0.y, AB0.x);
float baseAngleC = atan(AC0.y, AC0.x);
float basePhase = swimPhase() * freq + phaseOffset;
// angular change wrt time
float angleB = baseAngleB + ampB * sin(basePhase);
float angleC = baseAngleC + ampC * sin(basePhase + phaseC);
// new location of the three coordinates of the bezier after transformation
vec2 A = A0;
vec2 B = A0 + rB * vec2(cos(angleB), sin(angleB));
vec2 C = A0 + rC * vec2(cos(angleC), sin(angleC));
float dCenter = sdBezier(p, A, B, C);
return dCenter - thickness;
}
// simple circle
float sdCircle(vec2 p, vec2 c, float r) {
return length(p - c) - r;
}
// definition of the spine
vec2 spinePos(float t) {
vec2 headPos = vec2(0.0, 0.7);
vec2 tailPos = vec2(0.0, -0.2);
vec2 spine = mix(headPos, tailPos, t);
// bend the spine w.r.t. time
float bend = -0.2 * sin(3.14159 * (t - 0.2) + swimPhase());
spine.x += bend * 0.4;
return spine;
}
// CENTRAL PART: This controls the shape of the fish
const int NUM_KEYS = 5;
const vec2 radiusKeys[NUM_KEYS] = vec2[NUM_KEYS](
vec2(0.00, 0.10), // Head
vec2(0.05, 0.12), // Neck
vec2(0.20, 0.14), // Body
vec2(0.80, 0.06), // Tail
vec2(1.00, 0.02) // Tail tip
);
float catmullRom(float p0, float p1, float p2, float p3, float s) {
float s2 = s * s;
float s3 = s2 * s;
return 0.5 * (
2.0 * p1 +
(-p0 + p2) * s +
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * s2 +
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * s3
);
}
float radiusProfile(float t) {
if (t <= radiusKeys[0].x) return radiusKeys[0].y;
if (t >= radiusKeys[NUM_KEYS-1].x) return radiusKeys[NUM_KEYS-1].y;
int seg = 0;
for (int i = 0; i < NUM_KEYS - 1; ++i) {
if (t >= radiusKeys[i].x && t <= radiusKeys[i+1].x) {
seg = i;
break;
}
}
int i1 = seg;
int i2 = seg + 1;
int i0 = max(i1 - 1, 0);
int i3 = min(i2 + 1, NUM_KEYS - 1);
float t1 = radiusKeys[i1].x;
float t2 = radiusKeys[i2].x;
float s = (t - t1) / (t2 - t1);
float p0 = radiusKeys[i0].y;
float p1 = radiusKeys[i1].y;
float p2 = radiusKeys[i2].y;
float p3 = radiusKeys[i3].y;
return catmullRom(p0, p1, p2, p3, s);
}
// Betta body
float sdBettaBody(vec2 p) {
float d = 1e9;
const int N = 30;
for (int i = 0; i < N; ++i) {
float t = float(i) / float(N - 1);
vec2 spine = spinePos(t);
float radius = radiusProfile(t);
float dc = sdCircle(p, spine, radius);
d = min(d, dc);
}
return d;
}
// MAX FINS COUNT!!! Lessen to relax the calculation load
const int MAX_FINS = 64;
// Ultimate fin function
// tAttach : where on the body the fin is attached from 0 to 1
// numFins : FIN COUNT!!! Be careful
// lenScaleGlobal : length of the fins
// thicknessScaleGlobal : thickness of the fins
// spreadScale : spread of the fan
// baseAngleOffset : base angle offset
float sdAllTailFins(
vec2 p,
float tAttach,
int numFins,
float lenScaleGlobal,
float thicknessScaleGlobal,
float spreadScale,
float baseAngleOffset,
float phaseOffset
) {
float t = clamp(tAttach, 0.0, 1.0);
vec2 basePos = spinePos(t);
float dt = 0.02;
vec2 tangent = normalize(
spinePos(min(t + dt, 1.0)) - spinePos(max(t - dt, 0.0)) + vec2(1e-5)
);
// baseangle with offset
float baseAngle = atan(tangent.y, tangent.x) + baseAngleOffset;
int N = clamp(numFins, 1, MAX_FINS);
float spread = 1.0 * spreadScale;
float d = 1e9;
//Loop to add the fins using the fin function
for (int i = 0; i < MAX_FINS; ++i) {
if (i >= N) break;
float fi = float(i);
float denom = max(float(N - 1), 1.0);
float u = (fi / denom) - 0.5;
float angleOffset = u * spread;
float angle = baseAngle + angleOffset;
float lenScaleLocal = mix(0.8, 1.2, hash1(fi * 5.31));
float lenBBase = 0.25 * lenScaleGlobal;
float lenCBase = 0.65 * lenScaleGlobal;
float lenB = lenBBase * lenScaleLocal;
float lenC = lenCBase * lenScaleLocal;
vec2 dirFin = vec2(cos(angle), sin(angle));
vec2 A0 = basePos;
vec2 B0 = basePos + lenB * dirFin;
vec2 C0 = basePos + lenC * dirFin;
float ampScale = 0.8 + 1.3 * abs(u);
float freq = 0.8;
float ampB = 0.10 * ampScale;
float ampC = 0.25 * ampScale;
float phaseC = 0.0 + u * 0.5;
float baseThickness = 0.008 * thicknessScaleGlobal;
float thickScale = mix(0.1, 0.8, hash1(fi * 5.13));
float thickness = baseThickness * thickScale;
float dFin = sdTailFin(
p,
A0, B0, C0,
freq, ampB, ampC, phaseC,
phaseOffset,
thickness
);
d = min(d, dFin);
}
return d;
}
//Base case for testing and debugging.
//Can be used with no parameters if lazy
float sdAllTailFins(vec2 p) {
return sdAllTailFins(p, 0.9, 24, 1.0, 1.0, 1.0, 0.0, 0.0);
}
//Pectoral fin (chest fin) thingy
float sdPectoralFin(
vec2 p,
vec2 basePos,
vec2 dirForward,
float sideSign
) {
// dirForward: head → tail
vec2 f = normalize(dirForward);
vec2 n = vec2(-f.y, f.x) * sideSign;
float a = deg2rad(PEC_BASE_ANGLE_DEG);
vec2 dirBase = normalize(
n * cos(a) + (-f) * sin(a)
);
// swing only to one side
float swing = 0.8 * pectoralSwingOneSide(); // 0〜1くらい
vec2 dirB = normalize(dirBase + 0.3 * swing * (-f));
vec2 dirC = normalize(dirBase + 1.0 * swing * (-f));
float lenB = 0.12;
float lenC = 0.26;
vec2 A = basePos;
vec2 B = basePos + lenB * dirB;
vec2 C = basePos + lenC * dirC;
float thickness = 0.012;
float dCenter = sdBezier(p, A, B, C);
return dCenter - thickness;
}
float sdPectoralFinsSide(
vec2 p,
vec2 basePos,
vec2 dirForward,
float sideSign
) {
vec2 f = normalize(dirForward);
vec2 n = vec2(-f.y, f.x) * sideSign;
float a = deg2rad(PEC_BASE_ANGLE_DEG);
vec2 baseDir = normalize(
n * cos(a) + (-f) * sin(a)
);
float baseAngle = atan(baseDir.y, baseDir.x);
const int NUM_PEC_FINS = 7;
float spread = 0.1;
float d = 1e9;
for (int i = 0; i < NUM_PEC_FINS; ++i) {
float fi = float(i);
float u = (fi / float(NUM_PEC_FINS - 1)) - 0.5;
float angleOffset = u * spread;
float angle = baseAngle + angleOffset;
vec2 dirBaseFin = vec2(cos(angle), sin(angle));
float swing = 0.7 * pectoralSwingOneSide();
vec2 dirB = normalize(dirBaseFin + 0.3 * swing * (-f));
vec2 dirC = normalize(dirBaseFin + 1.0 * swing * (-f));
float lenScale = mix(0.9, 1.1, hash1(fi * 7.31 + (sideSign > 0.0 ? 1.0 : 2.0)));
float lenBBase = 0.10;
float lenCBase = 0.26;
float lenB = lenBBase * lenScale;
float lenC = lenCBase * lenScale;
vec2 A = basePos;
vec2 B = basePos + lenB * dirB;
vec2 C = basePos + lenC * dirC;
float baseThickness = 0.010;
float thickScale = mix(0.2, 0.5,
hash1(fi * 3.17 + (sideSign > 0.0 ? 5.0 : 6.0)));
float thickness = baseThickness * thickScale;
float dFin = sdBezier(p, A, B, C) - thickness;
d = min(d, dFin);
}
return d;
}
float sdAllPectoralFins(vec2 p) {
float tBase = 0.35;
vec2 spineC = spinePos(tBase);
vec2 f = normalize(spinePos(tBase + 0.02) - spinePos(tBase - 0.02) + vec2(1e-5));
vec2 n = vec2(-f.y, f.x);
float r = radiusProfile(tBase);
//base position for the left and the right
vec2 baseL = spineC + n * r;
vec2 baseR = spineC - n * r;
float dL = sdPectoralFinsSide(p, baseL, f, +1.0);
float dR = sdPectoralFinsSide(p, baseR, f, -1.0);
return min(dL, dR);
}
float sdFinsAlongSpineRange(
vec2 p,
float tStart,
float tEnd,
int numFins, //This is the total number of fins along the spine
float lenScaleGlobal,
float thicknessScaleGlobal,
float baseAngleOffset,
float phaseOffset //can be used to offset the angle of fins, but usually keep it at 0
) {
float d = 1e9;
int N = clamp(numFins, 1, MAX_FINS);
//fail safe
float t0 = min(tStart, tEnd);
float t1 = max(tStart, tEnd);
for (int i = 0; i < MAX_FINS; ++i) {
if (i >= N) break;
float fi = float(i);
float denom = max(float(N - 1), 1.0);
float u = (N == 1) ? 0.0 : (fi / denom);
float t = mix(t0, t1, u);
t = clamp(t, 0.0, 1.0);
vec2 basePos = spinePos(t);
float dt = 0.02;
vec2 tangent = normalize(
spinePos(min(t + dt, 1.0)) - spinePos(max(t - dt, 0.0)) + vec2(1e-5)
);
float baseAngle = atan(tangent.y, tangent.x) + baseAngleOffset;
// spread the angles slightly
float jitter = (hash1(fi * 3.73) - 0.5) * 0.4;
float angle = baseAngle + jitter;
// length, with slight randomness with hash 1. In between 0.9 to 1.1 times
float lenScaleLocal = mix(0.9, 1.1, hash1(fi * 5.31));
float lenBBase = 0.25 * lenScaleGlobal;
float lenCBase = 0.65 * lenScaleGlobal;
float lenB = lenBBase * lenScaleLocal;
float lenC = lenCBase * lenScaleLocal;
vec2 dirFin = vec2(cos(angle), sin(angle));
vec2 A0 = basePos;
vec2 B0 = basePos + lenB * dirFin;
vec2 C0 = basePos + lenC * dirFin;
// adjust as needed, for the animation
float ampScale = 2.0;
float freq = 0.8;
float ampB = 0.10 * ampScale;
float ampC = 0.25 * ampScale;
float phaseC = 0.0 + u * 1.2;
float baseThickness = 0.008 * thicknessScaleGlobal;
float thickScale = mix(0.3, 0.9, hash1(fi * 5.13));
float thickness = baseThickness * thickScale;
float dFin = sdTailFin(
p,
A0, B0, C0,
freq, ampB, ampC, phaseC,
phaseOffset,
thickness
);
d = min(d, dFin);
}
return d;
}
//Throw in the calculated sd stuff in here, to mix the colors.
vec3 mixColor(vec3 baseColor, float dShape, vec3 shapeColor, float alpha) {
float mask = smoothstep(0.02, 0.0, dShape);
float blend = mask * alpha;
return mix(baseColor, shapeColor, blend);
}
// -------------------- main --------------------
void main() {
vec2 p = (2.0 * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
// All the sdf calculations
float dBody = sdBettaBody(p);
float dTail = sdAllTailFins(p, 0.9, 32, 1.0, 1.0, 0.7, 0.0, 0.0);
float dPec = sdAllPectoralFins(p);
float dTailThin = sdAllTailFins(p, 0.9, 8, 0.9, 0.4, 0.6, 0.0, 0.0);
float dTailSpread = sdAllTailFins(p, 0.9, 30, 0.8, 0.4, 0.6, 0.3, 1.4);
float dBack = sdAllTailFins(p, 0.2, 24, 1.0, 0.4, 0.4, 0.0, 0.0);
float dBack2 = sdAllTailFins(p, 0.5, 32, 1.0, 0.4, 0.7, 0.2, 0.0);
float dSpine = sdFinsAlongSpineRange(p, 0.2, 0.8, 60, 0.7, 0.4, 0.0, 0.3);
float dSpine2 = sdFinsAlongSpineRange(p, 0.2, 0.8, 60, 0.5, 0.4, 0.0, 0.1);
// color for each body segements
vec3 bg = vec3(0.6, 0.7, 1.0);
vec3 bodyCol = vec3(0.9, 0.25, 0.3);
vec3 pecCol = vec3(0.9, 0.25, 0.3);
vec3 tailCol = vec3(0.9, 0.3, 0.3);
vec3 tailColThin = vec3(0.7, 0.3, 0.3);
vec3 backCol = vec3(0.9, 0.3, 0.3);
vec3 spineCol2 = vec3(0.85, 0.3, 0.3);
vec3 bodyColBase = vec3(0.9, 0.25, 0.3); //For the base body color
vec3 bodyColEdge = vec3(0.8, 0.2, 0.2); // body color for outer rim
float rimWidth = 0.06;
float rimFactor = smoothstep(-rimWidth, 0.0, dBody);
bodyCol = mix(bodyColBase, bodyColEdge, rimFactor);
vec3 color = bg;
//MIX EVERYTHING
color = mixColor(color, dBody, bodyCol, 0.9);
color = mixColor(color, dBack, backCol, 0.4);
color = mixColor(color, dBack2, backCol, 0.55);
color = mixColor(color, dPec, pecCol, 0.6);
color = mixColor(color, dTail, tailCol, 0.6);
color = mixColor(color, dTailThin, tailColThin, 0.7);
color = mixColor(color, dSpine, tailCol, 0.6);
color = mixColor(color, dSpine2, spineCol2, 0.8);
color = mixColor(color, dTailSpread, tailCol, 0.6);
///////////////////
//noise from https://www.redblobgames.com/x/2107-webgl-noise/webgl-noise/webdemo/cellular.html
//NOISE!!!! The worley noise 2D defined here
float t = u_time;
// First noise layer
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
vec2 uv1 = uv * u_resolution.xy / min(u_resolution.x, u_resolution.y);
float n1 = colorMapping(uv1 * 4.0 + vec2(t * 0.3, t * 0.1));
float v1 = 0.5 + 0.5 * n1;
vec3 col1 = vec3(v1);
float alpha1 = v1 * 0.3;
color = mix(color, col1, alpha1);
// Second noise layer
vec2 uv2 = uv * u_resolution.xy / min(u_resolution.x, u_resolution.y);
float n2 = colorMapping(uv2 * 12.0 + vec2(u_time * 0.4, u_time * 0.7));
float v2 = 0.5 + 0.5 * n2;
vec3 col2 = vec3(v2);
float alpha2 = v2 * 0.3;
color = mix(color, col2, alpha2);
colour_out = vec4(color, 1.0);
}
Red Betta (Not goldfish) by Shuma Kise
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
in vec2 coord;
float edgeWidth = 0.05;
struct FishState {
vec2 pos; // 位置
vec2 velocity;// 速度ベクトル
float angle; // 回転角度
float bend; // 曲がり具合
float facing; // 向き(左右)
};
struct FishField {
float insideBody;
float insideCaudal;
float insideDorsal;
};
struct FishConfig {
vec2 bodyCenter;
vec2 bodySize;
vec2 caudalCenter;
vec2 caudalSize;
float caudalAngle;
vec2 dorsalCenter;
vec2 dorsalSize;
float dorsalAngle;
vec2 eyeCenter;
float eyeSize;
};
FishConfig getFishConfig() {
FishConfig c;
c.bodyCenter = vec2(0.3, 0.0);
c.bodySize = vec2(0.4, 0.16);
// 尾鰭
c.caudalCenter = vec2(0.6, 0.0);
c.caudalSize = vec2(1.2, 1.3);
c.caudalAngle = radians(70.0);
// 背鰭
c.dorsalCenter = vec2(0.1, 0.0);
c.dorsalSize = vec2(2.0, 0.7);
c.dorsalAngle = radians(50.0);
// 目
c.eyeCenter = vec2(0.05, 0.04);
c.eyeSize = 0.05;
return c;
}
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(vec2 v) {
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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);
}
// 楕円
float sdEllipse( in vec2 p, in vec2 ab ) {
p = abs(p); if( p.x > p.y ) {p=p.yx;ab=ab.yx;}
float l = ab.y*ab.y - ab.x*ab.x;
float m = ab.x*p.x/l; float m2 = m*m;
float n = ab.y*p.y/l; float n2 = n*n;
float c = (m2+n2-1.0)/3.0; float c3 = c*c*c;
float q = c3 + m2*n2*2.0;
float d = c3 + m2*n2;
float g = m + m*n2;
float co;
if( d<0.0 )
{
float h = acos(q/c3)/3.0;
float s = cos(h);
float t = sin(h)*sqrt(3.0);
float rx = sqrt( -c*(s + t + 2.0) + m2 );
float ry = sqrt( -c*(s - t + 2.0) + m2 );
co = (ry+sign(l)*rx+abs(g)/(rx*ry)- m)/2.0;
}
else
{
float h = 2.0*m*n*sqrt( d );
float s = sign(q+h)*pow(abs(q+h), 1.0/3.0);
float u = sign(q-h)*pow(abs(q-h), 1.0/3.0);
float rx = -s - u - c*4.0 + 2.0*m2;
float ry = (s - u)*sqrt(3.0);
float rm = sqrt( rx*rx + ry*ry );
co = (ry/sqrt(rm-rx)+2.0*g/rm-m)/2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0-co*co));
return length(r-p) * sign(p.y-r.y);
}
// 光の筋
float getRays(vec2 uv, float t) {
vec2 lightPos = vec2(0.0, 1.5 + sin(t * 0.5) * 0.2);
vec2 rayDir = normalize(uv - lightPos);
float angle = atan(rayDir.y, rayDir.x);
float ray = snoise(vec2(angle * 5.0, t * 0.2));
float dist = length(uv - lightPos);
float attenuation = 1.0 / (1.0 + dist * dist * 2.0);
float directionality = smoothstep(0.0, 0.8, -rayDir.y);
return max(0.0, ray * attenuation * directionality);
}
// 泡
float getBubbles(vec2 uv, float t) {
float totalBubbles = 0.0;
for (float i = 0.0; i < 3.0; i++) {
float scale = 1.0 + i * 2.0;
float speed = 0.3 + i * 0.1;
vec2 pos = uv * scale - vec2(sin(t * 0.1 + i) * 0.5, t * speed);
vec2 grid = floor(pos);
vec2 local = fract(pos) - 0.5;
float rand = fract(sin(dot(grid, vec2(12.3456, 78.91011))) * 43210.98765);
if (rand > 0.8) {
float d = length(local);
float bubble = smoothstep(0.1, 0.07, d);
totalBubbles += bubble * (0.3 / scale);
}
}
return totalBubbles;
}
// ランダムな目標点を計算
vec2 getCyclePoint(float i) {
float maxWidth = 0.9;
float maxHeight = 0.2;
float rx = fract(sin(i * 12.9898) * 43758.5453) * 2.0 - 1.0;
float ry = fract(sin(i * 98.123) * 43758.5453) * 2.0 - 1.0;
return vec2(rx * maxWidth, ry * maxHeight);
}
// 魚の位置と向きを計算
FishState generateTransform(float t, float cycle) {
// --------パラメータ--------
float minDist = 0.6;
float minAngle = radians(10.0);
// ------------------------
float timeScale = t / cycle;
float i = floor(timeScale);
float f = fract(timeScale);
float progress = clamp(f, 0.0, 1.0);
float u = 1.0 - pow(1.0 - progress, 3.0);
// ---- 目標点の取得 ----
vec2 p0 = getCyclePoint(i);
vec2 p2 = getCyclePoint(i + 1.0);
// 最小移動距離補正
vec2 dVec = p2 - p0;
float dLen = length(dVec);
if(dLen < minDist) {
vec2 dir = (dLen > 0.001) ? normalize(dVec) : vec2 (1.0, 0.0);
p2 = p0 + dir * minDist;
}
// ベジエ曲線用の中間点
vec2 mid = (p0 + p2) * 0.5;
float curveRand = fract(sin(i * 54.321) * 9999.0) * 2.0 - 1.0;
vec2 p1 = mid + vec2(0.0, curveRand * 0.15);
// 2次ベジエ曲線の微分により速度ベクトルを求め, 速度も計算
vec2 tanTerm1 = p1 - p0;
vec2 tanTerm2 = p2 - p1;
vec2 velocity = 2.0 * (1.0 - u) * tanTerm1 + 2.0 * u * tanTerm2;
vec2 targetPos = mix(mix(p0, p1, u), mix(p1, p2, u), u);
vec2 drift = vec2(
sin(t * 0.8) * 0.02,
cos(t * 1.2) * 0.015
);
targetPos += drift;
// 進行方向に対する上下の傾き
float rawAngle = atan(velocity.y, abs(velocity.x));
float angleDamp = smoothstep(0.0, 0.15, progress) * smoothstep(1.0, 0.4, progress);
float angle = clamp(rawAngle, -minAngle, minAngle) * angleDamp;
// 方向転換時のしなり
float bendIntensity = sin(progress * 3.14159);
float bend = bendIntensity * curveRand * 0.8;
// 左右の向きの決定
vec2 prev_p0 = getCyclePoint(i - 1.0);
vec2 prev_p2 = p0;
float prevFacing = (prev_p0.x >= prev_p2.x) ? 1.0 : -1.0;
float currFacing = (p0.x >= p2.x) ? 1.0 : -1.0;
float turnProgress = smoothstep(0.0, 0.15, progress);
float facing = mix(prevFacing, currFacing, turnProgress);
return FishState(targetPos, velocity, angle, bend, facing);
}
// 魚の変形
vec2 deformFish(vec2 p, FishState state){
vec2 rel = p - state.pos;
// 回転
float f = (state.facing >= 0.0) ? 1.0 : -1.0;
float c = cos(-state.angle * f);
float s = sin(-state.angle * f);
rel = mat2(c, -s, s, c) * rel;
// 左右反転
// 反転する瞬間が最高値
float turnIntensity = 1.0 - abs(state.facing);
// 部位ごとの向き
float localFacing = state.facing - rel.x * turnIntensity;
if (abs(localFacing) < 0.01) {
localFacing = 0.01 * sign(localFacing);
}
rel.x /= localFacing;
return rel;
}
// 尾鰭のSDF
float sdFin(vec2 p, vec2 diameter, float maxAngle, float t) {
float angle = atan(p.y, p.x);
float absAngle = abs(angle);
float r = length(p);
float edgeNoise = snoise(vec2(r * 4.0, t * 1.5)) * 0.05;
float angOutside = absAngle - (maxAngle + edgeNoise);
angOutside = max(angOutside, 0.0);
vec2 np = p / diameter;
float finDist = length(np) - 1.0;
return max(finDist, angOutside * diameter.x);
}
FishField mapFish(vec2 p, float t) {
FishField f;
FishConfig fishConfig = getFishConfig();
// 胴体
float bodyDist = sdEllipse(p - fishConfig.bodyCenter, fishConfig.bodySize);
f.insideBody = step(bodyDist, 0.0);
// 尾鰭
float caudalFinDist = sdFin(p - fishConfig.caudalCenter, fishConfig.caudalSize, fishConfig.caudalAngle, t);
f.insideCaudal = max(step(caudalFinDist, 0.0) - f.insideBody, 0.0);
// 背鰭
float dorsalFinDist = sdFin(p - fishConfig.dorsalCenter, fishConfig.dorsalSize, fishConfig.dorsalAngle, t);
f.insideDorsal = max(step(dorsalFinDist, 0.0) - f.insideBody, 0.0);
return f;
}
// 体の模様生成
vec3 getBodyPattern(vec2 uv, vec2 velocity) {
return vec3(0.1, 0.05, 0.45);
}
// 尾鰭の模様生成
vec4 getFinPattern(vec2 uv, vec2 velocity, float t) {
float warpFactor = 0.5;
float stripeCount = 22.0;
float minSaturate = 0.6;
float maxSaturate = 0.85;
float gradEdge = 0.8;
vec3 blue = vec3(0.0, 0.2, 0.9);
vec3 grey = vec3(0.5, 0.5, 0.5);
vec3 red = vec3(0.8, 0.2, 0.08);
vec4 outColor = vec4(1.0);
float angle = atan(uv.y, uv.x);
float r = length(uv);
// 水流の抵抗による揺らぎの計算
float n1 = snoise(vec2(angle * 3.0, t * 0.25));
float n2 = snoise(vec2(r * 4.0, t * 0.35));
vec2 vel = normalize(velocity + 0.0001);
vel = abs(vel);
float flow = dot(normalize(uv), vel);
float n3 = snoise(vec2(flow * 6.0, t * 0.5));
float warp = (n1 * 0.15) + (n2 * 0.10) + (n3 * 0.25);
warpFactor *= smoothstep(0.0, 0.2, r);
float warpedR = r + warp * warpFactor;
float warpedAngle = angle + warp * warpFactor;
// 彩度変化によるストライプ模様
float stripe = sin(warpedAngle * stripeCount);
float stripeFactor = stripe * 0.5 + 0.5;
float saturation = mix(minSaturate, maxSaturate, stripeFactor);
// 中心とエッジのフェード
float centerFade = max(smoothstep(0.05, 0.2, warpedR), 0.4);
float rimFade = 1.0 - smoothstep(0.6, 0.8, warpedR);
float radialFade = centerFade * rimFade;
// saturation *= radialFade;
// 色のグラデーション
float edge = smoothstep(0.0, 0.85 + warp * 0.15, warpedR);
vec3 gradation;
if (edge < gradEdge) {
float a = smoothstep(0.0, gradEdge, edge);
gradation = mix(blue, red, a);
} else {
float a = smoothstep(gradEdge, 1.0, edge);
gradation = mix(red, grey, a);
}
outColor.rgb = saturation * gradation;
outColor.a = radialFade;
return outColor;
}
void main() {
// ------- パラメータ -------
float cycle = 8.0;
vec3 col = vec3(0.02, 0.03, 0.07);
vec3 bgColorTop = vec3(0.0, 0.1, 0.3);
vec3 bgColorBottom = vec3(0.0, 0.02, 0.1);
vec3 bodyColor = vec3(0.0, 0.1, 0.45);
// ーーーーーーーーーーーーーーー
FishConfig fishConfig = getFishConfig();
vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / min(u_resolution.x, u_resolution.y);
float t = u_time;
// 背景
vec3 bgCol = mix(bgColorBottom, bgColorTop, uv.y * 0.5 + 0.5);
float rays = getRays(uv, t);
bgCol += vec3(0.8, 0.9, 1.0) * rays * 0.5;
float bubbles = getBubbles(uv, t);
bgCol += vec3(1.0) * bubbles * 0.8;
vec3 finalColor = bgCol;
// 現在位置と移動方向ベクトルの計算
FishState fishState = generateTransform(t, cycle);
vec2 localUV = deformFish(uv, fishState);
vec2 caudalUV = (localUV - fishConfig.caudalCenter) / fishConfig.caudalSize;
vec2 dorsalUV = (localUV - fishConfig.dorsalCenter) / fishConfig.dorsalSize;
FishField field = mapFish(localUV, t);
vec4 caudal = getFinPattern(caudalUV, fishState.velocity, t);
vec4 dorsal = getFinPattern(dorsalUV, fishState.velocity, t + 1.0);
finalColor = mix(finalColor, bodyColor, field.insideBody);
finalColor = mix(finalColor, dorsal.rgb, dorsal.a * field.insideDorsal);
finalColor = mix(finalColor, caudal.rgb, caudal.a * field.insideCaudal);
float d = length(localUV - fishConfig.eyeCenter);
float eyeMask = 1.0 - smoothstep(fishConfig.eyeSize, fishConfig.eyeSize + 0.003, d);
float visibleEye = eyeMask * field.insideBody;
finalColor = mix(finalColor, vec3(0.0), visibleEye);
colour_out = vec4(finalColor, 1.0);
return;
}
salmon by tomato
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
const float PI = 3.14159265359;
const vec3 body_color = vec3(0.1, 0.5, 1.0);
const vec3 roof_fin_color = vec3(0.5, 0.7, 1.0);
const vec3 middle_fin_color = vec3(0.1, 0.5, 1.0);
const vec3 edge_fin_color = vec3(0.9, 0.9, 1.2);
vec2 mod289(vec2 x) {return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec3 mod289(vec3 x) {return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec4 mod289(vec4 x) {return x - floor(x * (1.0 / 289.0)) * 289.0;}
vec3 mod7(vec3 x) {return x - floor(x * (1.0 / 7.0)) * 7.0;}
vec3 permute(vec3 x) {return mod289(((x*34.0)+10.0)*x);}
vec4 permute(vec4 x) {return mod289(((x*34.0)+1.0)*x);}
float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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);
}
vec2 cellular(vec2 P) {
#define K 0.142857142857 // 1/7
#define Ko 0.428571428571 // 3/7
#define jitter 0.2 // Less gives more regular pattern
vec2 Pi = mod289(floor(P));
vec2 Pf = fract(P);
vec3 oi = vec3(-1.0, 0.0, 1.0);
vec3 of = vec3(-0.5, 0.5, 1.5);
vec3 px = permute(Pi.x + oi);
vec3 p = permute(px.x + Pi.y + oi); // p11, p12, p13
vec3 ox = fract(p*K) - Ko;
vec3 oy = mod7(floor(p*K))*K - Ko;
vec3 dx = Pf.x + 0.5 + jitter*ox;
vec3 dy = Pf.y - of + jitter*oy;
vec3 d1 = dx * dx + dy * dy; // d11, d12 and d13, squared
p = permute(px.y + Pi.y + oi); // p21, p22, p23
ox = fract(p*K) - Ko;
oy = mod7(floor(p*K))*K - Ko;
dx = Pf.x - 0.5 + jitter*ox;
dy = Pf.y - of + jitter*oy;
vec3 d2 = dx * dx + dy * dy; // d21, d22 and d23, squared
p = permute(px.z + Pi.y + oi); // p31, p32, p33
ox = fract(p*K) - Ko;
oy = mod7(floor(p*K))*K - Ko;
dx = Pf.x - 1.5 + jitter*ox;
dy = Pf.y - of + jitter*oy;
vec3 d3 = dx * dx + dy * dy; // d31, d32 and d33, squared
// Sort out the two smallest distances (F1, F2)
vec3 d1a = min(d1, d2);
d2 = max(d1, d2); // Swap to keep candidates for F2
d2 = min(d2, d3); // neither F1 nor F2 are now in d3
d1 = min(d1a, d2); // F1 is now in d1
d2 = max(d1a, d2); // Swap to keep candidates for F2
d1.xy = (d1.x < d1.y) ? d1.xy : d1.yx; // Swap if smaller
d1.xz = (d1.x < d1.z) ? d1.xz : d1.zx; // F1 is in d1.x
d1.yz = min(d1.yz, d2.yz); // F2 is now not in d2.yz
d1.y = min(d1.y, d1.z); // nor in d1.z
d1.y = min(d1.y, d2.x); // F2 is in d1.y, we're done.
return sqrt(d1.xy);
}
float FinLineFbm( vec2 p ) { /* Same as the fbm before. */
float f = 0.0, scale;
for (int i=0; i<2; i++) {
scale = pow( pow(2.0, 4.0/3.0), float(i) );
f += snoise( p * scale ) / scale;
}
return f;
}
float FinRingFbm( vec2 p ) { /* Same as the fbm before. */
float f = 0.0, scale;
scale = pow( pow(2.0, 4.0/3.0), 1.0 );
f += snoise( p * scale ) / scale; // calc f separatedly only when i = 1
for (int i=2; i<4; i++) {
scale = pow( pow(2.0, 4.0/3.0), float(i) );
f += snoise( p * scale ) * float(i)/20.0;
}
return f;
}
vec4 drawBody(vec2 p) {
vec2 p_eye = vec2(0.8, 0.05);
vec2 p_mouse = 2.0*u_mouse/u_resolution - 1.0;
float theta = atan(p_mouse.y - p_eye.y, p_mouse.x - p_eye.x);
float x = 0.03 * cos(theta);
float y = 0.03 * sin(theta);
float eye = step( 0.04, distance( p.xy, vec2(p_eye.x + x, p_eye.y + y) ) );
if (eye == 0.0){
return vec4(vec3(0.0), 1.0);
}else{
p *= 25.0;
p.y *= 0.6;
p.y *= 2.0/sqrt(3.0);
p.x += 0.5 * mod(floor(p.y), 2.0);
vec2 f = cellular(p);
float n = 1.0 - f.x;
float grad = pow(0.04*p.x + 0.07, -0.5);
float t = 0.08*sin(1.3*u_time + p.x/3.0);
return vec4(grad * n*body_color + t, 1.0);
}
}
vec4 drawFins(vec2 p) {
float s = sin(0.1*sin(u_time));
float c = cos(0.1*sin(u_time));
mat2 R = mat2(
c, s,
-s, c
);
R = transpose(R);
p.xy = R*p.xy;
float nL = FinLineFbm( p );
float theta = 30.0*atan(p.y, p.x) + 3.0 * nL;
float theta_mod = mod(theta, PI);
float k = pow(sin(theta_mod), 0.2);
float nR = FinRingFbm( p );
float d_noised = length(p) * 30.0 + 3.0 * nR;
vec3 base_color;
float roof_middle = 15.0;
float edge_middle = 18.0;
float edge = 25.0;
if(-30.0*PI/2.2 < theta && theta < 30.0*PI/2.2){
return vec4(0.0);
}else{
if(d_noised <= roof_middle){
base_color = roof_fin_color;
}else if((roof_middle <= d_noised) && (d_noised < edge_middle)){
base_color = middle_fin_color;
}else if((edge_middle <= d_noised) && (d_noised < edge)){
base_color = edge_fin_color;
}else{
return vec4(0.0);
}
}
float t = 0.1*sin(2.0*u_time-0.5*d_noised);
return vec4( base_color*k + t, 1.0 );
}
void main() {
vec2 p = (2.0 * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
float mask = 1.0;
mask *= 1.0 - step( 0.8, distance( p.xy, vec2(0.45, 0.6) ) );
mask *= 1.0 - step( 0.8, distance( p.xy, vec2(0.45, -0.6) ) );
if(mask == 1.0){
// colour_out = vec4(vec2(sin(u_time)), 0.0, 1.0);
colour_out = drawBody(p);
}else{
colour_out = drawFins(p);
}
}
half moon by kuroki
uniform vec2 u_resolution;
uniform float u_time;
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }
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 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod289(i);
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);
}
float fbm(vec2 p) {
float total = 0.0;
float amplitude = 0.5;
for (int i = 0; i < 3; i++) {
total += snoise(p) * amplitude;
p *= 2.0;
amplitude *= 0.5;
}
return total;
}
mat2 rotate2d(float angle){
return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
}
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);
}
float sdEllipse(vec2 p, vec2 r) {
float k0 = length(p / r);
float k1 = length(p / (r * r));
return k0 * (k0 - 1.0) / k1;
}
float fishSDF(vec2 p) {
p += vec2(0.1, 0.0);
vec2 finP = p;
float wave = sin(finP.x * 10.0 - u_time * 2.0 + finP.y * 5.0) * 0.015;
float angle = atan(finP.y, finP.x);
float folds = sin(angle * 40.0) * 0.01;
finP += wave + folds;
vec2 bodyP = p;
bodyP *= rotate2d(-0.1);
float body = sdEllipse(bodyP - vec2(0.2, 0.0), vec2(0.32, 0.11));
body += smoothstep(0.1, -0.4, bodyP.x) * 0.03;
vec2 tailPos = finP - vec2(-0.35, 0.0);
float tail = sdEllipse(tailPos, vec2(0.45, 0.55));
tail += sin(p.y * 25.0) * 0.015;
vec2 dorsalPos = finP - vec2(-0.15, 0.25);
dorsalPos *= rotate2d(0.3);
float dorsal = sdEllipse(dorsalPos, vec2(0.35, 0.3));
vec2 analPos = finP - vec2(-0.1, -0.3);
analPos *= rotate2d(-0.2);
float anal = sdEllipse(analPos, vec2(0.45, 0.35));
float fins = smin(tail, dorsal, 0.15);
fins = smin(fins, anal, 0.2);
float mainShape = smin(body, fins, 0.06);
return mainShape;
}
vec3 getFishColor(vec2 p) {
vec2 texUV = p;
vec3 blueDeep = vec3(0.0, 0.1, 0.4);
vec3 blueBright = vec3(0.0, 0.7, 0.9);
vec3 redDeep = vec3(0.6, 0.05, 0.1);
vec3 redBright = vec3(1.0, 0.35, 0.15);
float blueGradFactor = smoothstep(0.4, -0.8, texUV.x) * 0.7 + smoothstep(0.3, -0.3, texUV.y) * 0.3;
vec3 dynamicBlue = mix(blueDeep, blueBright, blueGradFactor);
float redGradFactor = smoothstep(0.1, -0.6, texUV.y);
vec3 dynamicRed = mix(redDeep, redBright, redGradFactor);
// Masks Defination
float bodyMask = smoothstep(-0.6, 0.0, texUV.x);
float bottomY = 1.0 - smoothstep(-0.5, 0.05, texUV.y);
float bottomX = smoothstep(-0.780, -0.124, texUV.x);
float bottomMask = bottomY * bottomX;
// BaseColor
vec3 baseColor = mix(dynamicBlue, dynamicRed, bottomMask);
// Simple textures
float scales = snoise(texUV * 30.0);
scales = smoothstep(0.0, 0.6, scales);
vec2 finCenter = texUV - vec2(-0.3, 0.0);
float angle = atan(finCenter.y, finCenter.x);
float dist = length(finCenter);
float rayNoise = fbm(vec2(angle * 10.0, dist * 2.0 - u_time * 0.5));
float streaks = smoothstep(0.2, 0.8, rayNoise);
// scales
vec3 colCyan = vec3(0.0, 0.8, 0.9);
baseColor += colCyan * scales * 0.15 * bodyMask * (1.0 - bottomMask);
// fins
vec3 streakColor = mix(vec3(0.0, 0.0, 0.2), vec3(0.3, 0.0, 0.0), bottomMask);
baseColor += streakColor * streaks * 0.5;
baseColor += colCyan * 0.2 * streaks * (1.0 - bottomMask);
// illustration
float light = snoise(texUV * 2.0 + u_time * 0.2);
baseColor += light * 0.1;
// eyes
vec2 eyePosCenter = vec2(0.350,0.050);
float eyeRadius = 0.022;
float distToEye = length(texUV - eyePosCenter);
float eyeMask = smoothstep(eyeRadius + 0.002, eyeRadius - 0.002, distToEye);
vec3 eyeBallCol = vec3(0.02, 0.02, 0.05);
vec2 highlightPos = eyePosCenter + vec2(0.007, 0.007);
float highlight = smoothstep(0.008, 0.003, length(texUV - highlightPos));
vec3 finalEyeCol = mix(eyeBallCol, vec3(1.0), highlight);
baseColor = mix(baseColor, finalEyeCol, eyeMask);
return baseColor;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
st = st * 2.0 - 1.0;
st.x *= u_resolution.x / u_resolution.y;
float d = fishSDF(st);
vec3 bgColor = vec3(0.0, 0.02, 0.08);
vec3 fishColor = getFishColor(st);
float alpha = smoothstep(0.005, -0.005, d);
float outline = smoothstep(0.01, 0.0, abs(d));
vec3 outlineColor = vec3(0.4, 0.8, 1.0);
vec3 objColor = mix(fishColor, outlineColor, outline * 0.5);
vec3 finalColor = mix(bgColor, objColor, alpha);
float glow = exp(-d * 4.0) * 0.2 * alpha;
finalColor += vec3(0.0, 0.2, 0.5) * exp(-abs(d) * 10.0) * 0.5;
colour_out = vec4(finalColor, 1.0);
}
Unknown by cookie
precision mediump float;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// Utilities
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);
}
float smax(float a, float b, float k) {
return -smin(-a, -b, k);
}
mat2 rot(float a) {
return mat2(cos(a), -sin(a), sin(a), cos(a));
}
// Noise (Perlin)
float hash(vec2 p) {
p = fract(p * vec2(672.077, 110.911));
p += dot(p, p.yx + 19.21);
return fract(p.x * p.y);
}
float noise(vec2 p) {
vec2 i = floor(p), f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
float a = hash(i);
float b = hash(i + vec2(1, 0));
float c = hash(i + vec2(0, 1));
float d = hash(i + vec2(1, 1));
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float fbm(vec2 p, float t) {
float v = 0.0, a = 0.5;
p += t * 0.05;
for (int i = 0; i < 5; i++) {
v += a * noise(p);
a *= 0.5; p = rot(0.5) * p * 2.0;
}
return v;
}
float caustics(vec2 p, float t) {
return pow(noise(p * 3.0 + t * 0.3) * noise(p * 5.0 - t * 0.2 + 100.0) * noise(p * 7.0 + t * 0.19 + 200.0), 0.67) * 3.0;
}
// Animation
float finFlap(float t, float speed, float amp, float phase) {
return sin(t * speed + phase) * amp;
}
vec2 bodyWave(vec2 p, float t) {
float wave = sin(p.x * 3.0 - t * 4.0) * 0.025 * smoothstep(-0.3, 0.4, p.x);
return vec2(p.x, p.y - wave);
}
// SDF primitives
float sdVesica(vec2 p, float r, float d) {
p = abs(p.yx);
float b = sqrt(r * r - d * d);
return ((p.y - b) * d > p.x * b) ? length(p - vec2(0, b)) : length(p - vec2(-d, 0)) - r;
}
float sdEllipse(vec2 p, vec2 ab) {
p = abs(p);
if (p.x > p.y) { p = p.yx; ab = ab.yx; }
float l = ab.y * ab.y - ab.x * ab.x;
float m = ab.x * p.x / l, n = ab.y * p.y / l;
float c = (m * m + n * n - 1.0) / 3.0, c3 = c * c * c;
float q = c3 + m * m * n * n * 2.0, d = c3 + m * m * n * n;
float g = m + m * n * n, co;
if (d < 0.0) {
float h = acos(q / c3) / 3.0, s = cos(h), t = sin(h) * sqrt(3.0);
float rx = sqrt(-c * (s + t + 2.0) + m * m), ry = sqrt(-c * (s - t + 2.0) + m * m);
co = (ry + sign(l) * rx + abs(g) / (rx * ry) - m) / 2.0;
} else {
float h = 2.0 * m * n * sqrt(d);
float s = sign(q + h) * pow(abs(q + h), 1.0/3.0);
float u = sign(q - h) * pow(abs(q - h), 1.0/3.0);
float rx = -s - u - c * 4.0 + 2.0 * m * m, ry = (s - u) * sqrt(3.0);
float rm = sqrt(rx * rx + ry * ry);
co = (ry / sqrt(rm - rx) + 2.0 * g / rm - m) / 2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0 - co * co));
return length(r - p) * sign(p.y - r.y);
}
// Fish Parts
float sdBody(vec2 p) {
return sdVesica(p, 0.5, 0.35);
}
float getScales(vec2 p) {
p = vec2(-p.y, p.x);
vec2 cell = p / vec2(0.035, 0.025);
if (mod(floor(cell.y), 2.0) == 1.0) cell.x += 0.5;
vec2 uv = fract(cell);
float dist = length(uv - vec2(0.5, -0.2));
float arc = abs(dist - 0.85) - 0.08;
return smoothstep(0.3, 0.9, dist / 0.85) * 0.3 +
(1.0 - smoothstep(0.0, 0.03, arc)) * step(0.2, uv.y) * 0.4;
}
float getRays(vec2 p, float n, float i) {
float rays = 0.5 + 0.5 * sin(atan(p.y, p.x) * n);
return mix(0.5, pow(rays, 0.5), smoothstep(0.0, 0.4, length(p)) * i);
}
// Tail fin
vec3 sdTail(vec2 p, float t) {
vec2 d = rot(finFlap(t, 5.0, 0.08, 0.0)) * (p - vec2(0.12, 0.0));
float angle = atan(d.y, d.x), dist = length(d);
float wave = sin(angle * 14.0 - t * 3.0) * 0.0375 + sin(angle * 23.0 - t * 4.5) * 0.018;
float shape = max(-d.x + 0.075, max(dist - 0.57 - wave,
max(d.y - d.x * 1.8 + 0.02, -d.y - d.x * 1.8 + 0.01)));
return vec3(shape, getRays(d, 70.0, 0.9), dist - 0.57 - wave);
}
// Dorsal fin
vec3 sdDorsal(vec2 p, float t) {
vec2 d = p - vec2(0.15, 0.1);
d = rot(0.1 + finFlap(t, 3.5, 0.05, 0.5) * smoothstep(0.0, 0.3, d.y)) * d;
float wave = sin(d.x * 48.0 - t * 2.5) * 0.0225 + sin(d.x * 80.0 - t * 3.25) * 0.012;
float shape = max(-d.y, max(-d.x - 0.27 + d.y * 0.4,
max(d.x - 0.18 - d.y * 0.6, d.y - 0.33 - wave)));
return vec3(shape, getRays(d, 50.0, 0.8), d.y - 0.33 - wave);
}
// Anal fin
vec3 sdAnal(vec2 p, float t) {
vec2 d = p - vec2(0.10, -0.1);
d = rot(0.1 - finFlap(t, 3.5, 0.04, 2.0) * smoothstep(0.0, -0.25, d.y)) * d;
float wave = sin(d.x * 48.0 - t * 2.5) * 0.018 + sin(d.x * 72.0 - t * 3.0) * 0.009;
float shape = max(d.y, max(-d.x - 0.225 - d.y * 0.5,
max(d.x - 0.15 + d.y * 0.7, -d.y - 0.27 - wave)));
return vec3(shape, getRays(d, 40.0, 0.8), -d.y - 0.27 - wave);
}
// Pectoral fin
vec3 sdPectoral(vec2 p, float t) {
vec2 d = rot(-0.1 + finFlap(t, 8.0, 0.25, 0.0)) * (p - vec2(-0.15, -0.05));
return vec3(sdEllipse(d - vec2(0.08, 0.0), vec2(0.093, 0.06)), getRays(d, 44.0, 0.4), d.x);
}
// Pelvic fin
vec3 sdPelvic(vec2 p, float t) {
vec2 d = rot(-1.5 + finFlap(t, 2.0, 0.2, 3.14)) * (p - vec2(-0.15, -0.10));
float taper = mix(0.045, 0.012, smoothstep(0.0, 0.28, d.x));
float wave = sin(d.y * 25.0 - t * 2.0) * 0.008;
float shape = smax(max(d.y - taper, -d.y - taper), max(-d.x - 0.01, d.x - 0.28 - wave), 0.025);
return vec3(shape, getRays(d, 30.0, 0.7), d.x);
}
// Main
void main() {
// Center the fish
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / u_resolution.y * 1.5;
float t = u_time;
// Global drift
uv += vec2(sin(t * 0.5) * 0.02, sin(t * 0.7) * 0.015);
vec2 bodyUV = bodyWave(uv, t);
// Background: tropical freshwater
float depth = smoothstep(-1.0, 0.6, uv.y);
vec3 col = mix(vec3(0.85, 0.78, 0.55), vec3(0.5, 0.75, 0.65), depth);
col = mix(col, vec3(0.6, 0.85, 0.8), smoothstep(0.3, 1.0, depth) + fbm(uv * 1.5, t * 0.7) * 0.2);
col += vec3(1.0, 0.98, 0.85) * caustics(uv * 0.8, t * 0.8) * 0.12 * depth;
col += vec3(0.9, 0.95, 0.8) * smoothstep(0.78, 0.88, noise(uv * 40.0 + t * 0.3)) * 0.15;
col = mix(col, vec3(0.7, 0.82, 0.5), 0.08);
// Colors
vec3 blue = vec3(0.05, 0.35, 0.9), black = vec3(0.02, 0.02, 0.04);
// Compute all SDFs
float dBody = sdBody(bodyUV);
vec3 tail = sdTail(bodyUV, t), dorsal = sdDorsal(bodyUV, t);
vec3 anal = sdAnal(bodyUV, t), pectoral = sdPectoral(bodyUV, t), pelvic = sdPelvic(bodyUV, t);
// Fusion zones
float fusionK = 0.04;
float dBodyDorsal = smin(dBody, dorsal.x, fusionK);
float dBodyAnal = smin(dBody, anal.x, fusionK);
float dTailFused = smin(tail.x, dBody, fusionK * 0.5);
// Compute body color
#define BODY_COLOR(uv) (mix(black, blue, smoothstep(-0.3, 0.5, uv.x)) * (0.7 + 0.5 * getScales(uv)))
// Compute fin color
#define FIN_COLOR(data, t1, t2) mix(mix(blue, black, smoothstep(t1, t2, data.z)) * 0.7, \
mix(blue, black, smoothstep(t1, t2, data.z)) * 1.3, data.y)
// Layer 1-2: Dorsal & Anal (background)
if (dorsal.x < 0.0) col = FIN_COLOR(dorsal, -0.25, -0.01);
if (anal.x < 0.0) col = FIN_COLOR(anal, -0.25, -0.01);
// Layer 3: Pelvic
if (pelvic.x < 0.0) {
float m = smoothstep(0.05, 0.25, pelvic.z);
col = mix(mix(black, blue, m) * 0.7, mix(black, blue, m) * 1.3, pelvic.y);
}
// Layer 4: Body
if (dBody < 0.0) col = BODY_COLOR(bodyUV);
// Fusion zones (dorsal-body, anal-body)
if (dBodyDorsal < 0.0 && dBody > 0.0 && dorsal.x > 0.0)
col = mix(FIN_COLOR(dorsal, -0.25, -0.01), BODY_COLOR(bodyUV), smoothstep(fusionK, 0.0, dBody));
if (dBodyAnal < 0.0 && dBody > 0.0 && anal.x > 0.0)
col = mix(FIN_COLOR(anal, -0.25, -0.01), BODY_COLOR(bodyUV), smoothstep(fusionK, 0.0, dBody));
// Layer 5: Tail (foreground)
if (dTailFused < 0.0) {
if (tail.x < 0.0) col = FIN_COLOR(tail, -0.25, -0.01);
else col = mix(BODY_COLOR(bodyUV), FIN_COLOR(tail, -0.25, -0.01), smoothstep(fusionK * 0.5, 0.0, tail.x));
}
// Layer 6: Pectoral
if (pectoral.x < 0.0) {
float m = smoothstep(0.10, 0.16, pectoral.z);
col = mix(mix(black, blue, m) * 0.8, mix(black, blue, m) * 1.2, pectoral.y);
}
// Layer 7: Eye
vec2 eyeP = bodyUV - vec2(-0.2, 0.03);
float dEye = length(eyeP) - 0.028;
if (dEye < 0.0) {
col = vec3(0.0, 0.02, 0.15);
if (length(eyeP - vec2(0.005, 0)) < 0.014) col = vec3(0.05, 0.1, 0.25);
if (length(eyeP - vec2(-0.008, 0.008)) < 0.006) col = vec3(1.0);
if (abs(dEye) < 0.006) col = vec3(0.0);
}
colour_out = vec4(col, 1.0);
}
Blue Half Moon Male Siamese Fighting Fish by
Prime
uniform vec2 u_resolution;
uniform float u_time;
// Citation for code below ///////////////////////////////////////////
// Description : Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x * 34.0) + 10.0) * x);
}
float snoise(vec2 v) {
const vec4 C = vec4(
0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439 // 1.0 / 41.0
);
// First corner
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
// i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
// i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
// Compute final noise value at P
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);
}
//////////////////////////////////////////////////////////////////////
// fbm
float fbm(vec2 p) {
float f = 0.0, scale;
for (int i = 0; i < 4; i++) {
scale = pow(pow(2.0, 4.0 / 3.0), float(i));
f += snoise(p * scale) / scale;
}
return f;
}
// fbm-ception (modified)
float noise(vec3 v) {
v.xy += vec2(fbm(v.xy), fbm(v.xy + v.z));
return fbm(v.xy) * 0.35 + 0.45;
}
// turbulence
float turbulence(vec2 p) {
float f = 0.0, scale;
for (int i = 0; i < 4; i++) {
scale = pow(pow(2.0, 4.0 / 3.0), float(i));
f += abs(snoise(p * scale)) / scale;
}
return f;
}
// smooth min
float smin(float a, float b, float k) {
float h = max(k - abs(a - b), 0.0) / k;
return min(a, b) - h * h * k * 0.25;
}
// sdf
float sdEllipse(vec2 p, vec2 r) {
float k0 = length(p / r);
float k1 = length(p / (r * r));
return k0 * (k0 - 1.0) / k1;
}
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
void main() {
// main colours
vec3 bodyColour = vec3(0.085, 0.258, 0.600);
vec3 scaleColour = vec3(0.0);
vec3 finColour1 = vec3(0.085, 0.258, 0.600);
vec3 finColour2 = vec3(0.900, 0.803, 0.364);
vec3 finColour3 = vec3(0.0);
// normalize
vec2 p = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / u_resolution.y;
// scale
p = p / 0.7;
// head
vec2 pHead = p - vec2(-0.1, 0.0);
float dHead = sdEllipse(pHead, vec2(0.3, 0.08));
// dorsal fin
vec2 pDorsal = p - vec2(0.05, 0.09);
float dorsalFrills = fbm(pDorsal * 4.0 + u_time) * 0.01;
float dDorsal = sdEllipse(pDorsal, vec2(0.18, 0.15)) - dorsalFrills;
float dDorsalBack = sdEllipse(pDorsal, vec2(0.18, 0.18)) - dorsalFrills;
float tDorsalStripe = 0.5 + sin(pDorsal.x * 100.0) * 0.5;
vec3 dorsalColour = mix(finColour1, finColour2, tDorsalStripe);
// anal fin
vec2 pAnal = p - vec2(0.05, -0.11);
float analFrills = fbm(pAnal * 4.0 + u_time) * 0.01;
float dAnal = sdEllipse(pAnal, vec2(0.28, 0.15)) - analFrills;
float dAnalBack = sdEllipse(pAnal, vec2(0.28, 0.18)) - analFrills;
float tAnalStripe = 0.5 + sin(pAnal.x * 100.0) * 0.5;
vec3 analColour = mix(finColour1, finColour2, tAnalStripe);
// caudal fin
vec2 pCaudal = p - vec2(0.35, 0.0);
float caudalFrills = fbm(pCaudal * 3.0 + u_time) * 0.01;
float dCaudal = sdCircle(pCaudal, 0.22) - caudalFrills;
float dCaudalBack = sdCircle(pCaudal - vec2(0.05, 0.0), 0.24) - caudalFrills;
float dBody = smin(dHead, dCaudal, 0.12);
vec2 caudalRadialVec = p - vec2(0.2, 0.0);
float caudalAngle = atan(caudalRadialVec.y, caudalRadialVec.x);
float caudalRays = smoothstep(0.3, 0.8, abs(sin(caudalAngle * 12.0)));
vec3 caudalColour = mix(finColour1, finColour2, caudalRays);
// pectoral fin
vec2 pPectoral = p - vec2(-0.05, 0.0);
float dPectoral = sdCircle(pPectoral, 0.08) - fbm(pPectoral * 8.0 + u_time) * 0.01;
vec2 pectoralRadialVec = pPectoral - vec2(-0.08, 0.0);
float pectoralAngle = atan(pectoralRadialVec.y, pectoralRadialVec.x);
float pectoralRays = smoothstep(0.3, 0.8, abs(sin(pectoralAngle * 10.0)));
vec3 pectoralColour = mix(finColour1, finColour3, pectoralRays);
// ventral fin
vec2 pVentral = p - vec2(-0.25, -0.1);
float dVentral = sdEllipse(pVentral, vec2(0.02, 0.15));
float dVentralBack = sdEllipse(pVentral + vec2(0.01, 0.0), vec2(0.02, 0.15)) - fbm(pVentral * 8.0 + u_time) * 0.01;
float tVentral = smoothstep(0.01, 0.0, pVentral.y);
vec3 ventralColour = mix(finColour1, finColour2, tVentral);
// eye
vec2 pEye = p - vec2(-0.35, 0.0);
float dEye = sdCircle(pEye, 0.018);
// scales
float nScale = turbulence(gl_FragCoord.xy / 10.0);
float tScale = smoothstep(0.1, 0.5, nScale);
bodyColour = mix(scaleColour, bodyColour, tScale);
// background
vec3 uv = vec3(0.5 * gl_FragCoord.xy / u_resolution.y - 0.5, 0.03 * u_time);
float bgNoise = noise(uv);
bgNoise = pow(bgNoise, 4.0) * 5.0;
vec3 colour = mix(vec3(0.222, 0.640, 0.263), vec3(0.331, 0.955, 0.392), bgNoise);
colour = mix(colour, finColour3, smoothstep(0.01, 0.0, dCaudalBack));
colour = mix(colour, finColour3, smoothstep(0.01, 0.0, dDorsalBack));
colour = mix(colour, finColour3, smoothstep(0.01, 0.0, dAnalBack));
colour = mix(colour, finColour3, smoothstep(0.01, 0.0, dVentralBack));
colour = mix(colour, ventralColour, smoothstep(0.01, 0.0, dVentral));
colour = mix(colour, dorsalColour, smoothstep(0.01, 0.0, dDorsal));
colour = mix(colour, analColour, smoothstep(0.01, 0.0, dAnal));
colour = mix(colour, caudalColour, smoothstep(0.01, 0.0, dCaudal));
colour = mix(colour, bodyColour, smoothstep(0.01, 0.0, dHead));
colour = mix(colour, pectoralColour, smoothstep(0.01, 0.0, dPectoral));
colour = mix(colour, vec3(0.1, 0.08, 0.05), smoothstep(0.003, 0.0, dEye));
colour_out = vec4(colour, 1.0);
}
blue halfmoon by hoshi
その他の学生作品
2025年の学生作品の残りは以下の通りです。なお、一部の作品は非常に計算量が多いため、お使いのブラウザで問題が発生する可能性があります。 全学生の作品を表示
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float y1 = abs(10.0 * st.y - 5.0);
float f = pow(abs((10.0 * st.x - 5.4 - pow(y1, 0.1)) / 4.0), 3.0) + pow(y1, 0.5) - 1.0;
float m1 = step(0.0, f);
float y2 = abs(3.0 * st.y - 1.5);
float base = 6.0 * st.x - 1.100 - pow(y2, 1.5);
float wave = 0.05 * sin(st.x * 100.0 + st.y * 30.0 + u_time * 5.0);
float g = pow(abs(base), 2.0) + pow(y2, 3.0) - (1.0 + wave);
float m2 = step(0.0, g);
float h = pow(2.5 * (st.x - 0.625) / (3.0*(st.y - 0.5)), 2.0) + pow(2.75 * (st.y - 0.5), 2.0) - (1.0 + 0.5 * wave);
float m3 = step(0.0, h);
vec4 c_body = vec4( 0.3, 0.8, 0.1*abs(sin(u_time+st.x))+0.8, 1.0 );
vec4 c_bg = vec4(1.0, 0.0, 1.0, 0.15*abs(sin(0.800*u_time + st.x))+0.1);
vec4 c_fin = vec4(0.3, 0.1*abs(sin(2.0*u_time+st.x*2.7))+0.8, 0.1*abs(sin(1.5*u_time+st.x))+0.8, 1.0);
vec4 final_color = c_bg * m1 * m2 * m3 + c_body * (1.0 - m1) * m2 + c_fin * max(1.0 - m2, (1.0 - m3) * m1);
colour_out = final_color;
}
Unknown by KK
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// --- Noise Functions (from webgl-noise logic) ---
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);
}
// --- Shape Functions ---
// 2D Rotation
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
// Background color (pale blue like an aquarium)
vec3 color = vec3(0.1, 0.15, 0.3) + (st.y * 0.2);
// --- Fish Coordinate Transformation ---
vec2 fishSt = st - vec2(0.5, 0.5);
// Slightly sway the whole fish
float swim = sin(u_time * 2.0) * 0.02;
fishSt.y += swim;
// --- Body (Biological/Organic shape) ---
vec2 bodyPos = fishSt;
vec2 distortedPos = bodyPos;
distortedPos.y *= 1.0 + distortedPos.x * 1.5;
// Create a perfect curve (ellipse) using length()
float dist = length(vec2(distortedPos.x * 0.8, distortedPos.y * 2.0));
// Use smoothstep to slightly blur the edges
float body = smoothstep(0.25, 0.23, dist);
// --- Fins ---
// Caudal Fin (Tail) - Right side
vec2 tailSt = fishSt - vec2(0.15, 0.0);
float tailAng = atan(tailSt.y, tailSt.x);
float tailLen = length(tailSt);
float tailWave = sin(tailAng * 10.0 - u_time * 3.0) * 0.05;
float tailShape = smoothstep(0.4 + tailWave, 0.35 + tailWave, tailLen);
tailShape *= smoothstep(-0.8, -0.5, tailAng) * smoothstep(0.8, 0.5, tailAng);
tailShape *= step(0.1, tailLen);
// Dorsal Fin - Top
vec2 dorsalSt = fishSt - vec2(0.05, 0.05);
dorsalSt = rotate2d(-0.5) * dorsalSt;
float dorsalWave = sin(dorsalSt.x * 10.0 - u_time * 4.0) * 0.03;
float shapeBase = 0.25 + dorsalWave - abs(dorsalSt.x)*0.5;
float dorsalShape = smoothstep(0.0, 0.02, dorsalSt.y) * smoothstep(shapeBase, shapeBase - 0.05, dorsalSt.y);
dorsalShape *= smoothstep(0.16, 0.10, abs(dorsalSt.x));
// Anal Fin - Bottom
vec2 analSt = fishSt - vec2(0.05, -0.05);
analSt = rotate2d(0.3) * analSt;
float analWave = sin(analSt.x * 15.0 - u_time * 5.0) * 0.02;
float analShape = step(analSt.y, 0.0) * step(-0.3 + analWave + abs(analSt.x)*0.8, analSt.y);
analShape *= step(abs(analSt.x - 0.05), 0.2);
// --- Color Application (Red from Reference Image) ---
vec3 bettaRed = vec3(0.85, 0.05, 0.15); // Main red
vec3 bettaDark = vec3(0.4, 0.0, 0.1); // Dark red
vec3 bettaPink = vec3(1.0, 0.4, 0.5); // Highlight
// Scales
float scalePattern = step(0.5, sin((fishSt.x + fishSt.y)*40.0) * sin((fishSt.x - fishSt.y)*40.0));
// Combine masks for the whole fish
float fullFish = max(body, max(tailShape, max(dorsalShape, analShape)));
// Color mixing
vec3 fishColor = mix(bettaRed, bettaDark, abs(fishSt.y)*3.0);
// Transparency and strands of the fins
float finStrands = sin(atan(tailSt.y, tailSt.x) * 40.0);
if(fullFish > 0.0 && body < 0.1) { // Fins part only
fishColor += finStrands * 0.1;
fishColor = mix(fishColor, bettaPink, tailLen * 0.5);
}
// Scales and highlights on the body
if(body > 0.0) {
fishColor = mix(fishColor, vec3(0.0, 0.0, 0.0), scalePattern * 0.3);
fishColor += bettaPink * (1.0 - distance(fishSt, vec2(-0.1, 0.0))*3.0) * 0.5;
}
// Eye center position
vec2 eyeCenter = vec2(-0.18, 0.05);
float eyeDist = length(fishSt - eyeCenter);
// Sclera (white), Pupil (black), and Highlight
float eyeWhite = smoothstep(0.035, 0.032, eyeDist);
float eyePupil = smoothstep(0.028, 0.015, eyeDist);
vec2 highlightPos = eyeCenter + vec2(0.01, 0.01);
float eyeHighlight = smoothstep(0.01, 0.1, length(fishSt - highlightPos));
vec3 eyeColor = vec3(0.1, 0.1, 0.1);
eyeColor = mix(eyeColor, vec3(0.0, 0.0, 0.0), eyePupil);
eyeColor = mix(eyeColor, vec3(1.0, 1.0, 1.0), eyeHighlight);
if (body > 0.0) {
fishColor = mix(fishColor, eyeColor, eyeWhite);
}
// Final Composition
colour_out = vec4(mix(color, fishColor, fullFish), 1.0);
}
Bouba Betta(BB) by Koji Naito
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec2 p = st * 2.0 - 1.0;
p.x *= u_resolution.x / u_resolution.y;
float speed = 0.5;
float xPos = sin(u_time * speed) * 0.3;
float yPos = 0.0;
vec2 tailPivot = vec2(xPos - 0.3, yPos);
vec2 r = p - tailPivot;
float ang = atan(r.y, r.x);
float rad = length(r);
float tail = abs(ang) - 1.1 + sin(ang*10.0 + u_time*3.0)*0.05 + (rad-0.15);
float tailMask = smoothstep(-0.02, 0.02, -tail);
vec3 tailCol = vec3(0.610,0.615,0.568);
vec2 bodyCenter = vec2(xPos, yPos);
vec2 bodySize = vec2(0.4, 0.2);
float bodySDF = length((p - bodyCenter) / bodySize) - 1.0;
float bodyMask = smoothstep(-0.05, 0.05, -bodySDF);
vec3 bodyCol = vec3(0.734,0.740,0.684);
vec2 eyeCenter = bodyCenter + vec2(-0.3, 0.05);
float eyeRadius = 0.03;
float eyeDist = length(p - eyeCenter);
vec3 eyeCol = vec3(0.740,0.022,0.015);
vec3 col = tailCol * tailMask;
col = mix(col, bodyCol, bodyMask);
if(eyeDist < eyeRadius){
col = eyeCol;
}
vec3 bg = vec3(0.234,0.351,0.530);
float alpha = max(tailMask, bodyMask);
colour_out = vec4(mix(bg, col, alpha), 1.0);
}
white by Asternoda
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// WebGL Noise functions (Simplex noise)
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec4 permute(vec4 x) { return mod289(((x*34.0)+1.0)*x); }
vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; }
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
vec3 i = floor(v + dot(v, C.yyy));
vec3 x0 = v - i + dot(i, C.xxx);
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min(g.xyz, l.zxy);
vec3 i2 = max(g.xyz, l.zxy);
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy;
vec3 x3 = x0 - D.yyy;
i = mod289(i);
vec4 p = permute(permute(permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
float n_ = 0.142857142857;
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_);
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4(x.xy, y.xy);
vec4 b1 = vec4(x.zw, y.zw);
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;
vec3 p0 = vec3(a0.xy, h.x);
vec3 p1 = vec3(a0.zw, h.y);
vec3 p2 = vec3(a1.xy, h.z);
vec3 p3 = vec3(a1.zw, h.w);
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2,p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 42.0 * dot(m*m, vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)));
}
// Fractal Brownian Motion for organic texture
float fbm(vec3 p) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
//for(int i = 0; i < 5; i++) {
for(int i = 0; i < 3; i++) {
value += amplitude * snoise(p * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return value;
}
// Smooth minimum for blending shapes
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);
}
// Betta body shape using SDF
float sdEllipse(vec2 p, vec2 ab) {
p = abs(p);
if(p.x > p.y) { p = p.yx; ab = ab.yx; }
float l = ab.y*ab.y - ab.x*ab.x;
float m = ab.x*p.x/l;
float n = ab.y*p.y/l;
float m2 = m*m;
float n2 = n*n;
float c = (m2+n2-1.0)/3.0;
float c3 = c*c*c;
float q = c3 + m2*n2*2.0;
float d = c3 + m2*n2;
float g = m + m*n2;
float co;
if(d < 0.0) {
float h = acos(q/c3)/3.0;
float s = cos(h);
float t = sin(h)*sqrt(3.0);
float rx = sqrt(-c*(s + t + 2.0) + m2);
float ry = sqrt(-c*(s - t + 2.0) + m2);
co = (ry+sign(l)*rx+abs(g)/(rx*ry)-m)/2.0;
} else {
float h = 2.0*m*n*sqrt(d);
float s = sign(q+h)*pow(abs(q+h), 1.0/3.0);
float u = sign(q-h)*pow(abs(q-h), 1.0/3.0);
float rx = -s-u-c*4.0+2.0*m2;
float ry = (s-u)*sqrt(3.0);
float rm = sqrt(rx*rx+ry*ry);
co = (ry/sqrt(rm-rx)+2.0*g/rm-m)/2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0-co*co));
return length(r-p) * sign(p.y-r.y);
}
// Flowing fins using animated noise
float fins(vec2 p, float time) {
float angle = atan(p.y, p.x);
float radius = length(p);
// Dorsal fin (top)
vec2 dorsalPos = p - vec2(-0.05, 0.0);
float dorsalAngle = atan(dorsalPos.y, dorsalPos.x);
float dorsalFlow = snoise(vec3(dorsalAngle * 3.0, radius * 5.0, time * 0.5)) * 0.3;
float dorsalFin = smoothstep(0.25, 0.0, abs(dorsalAngle - 1.57)) *
smoothstep(0.5, 0.0, radius - 0.15 - dorsalFlow);
// Ventral fin (bottom)
vec2 ventralPos = p - vec2(-0.05, 0.0);
float ventralAngle = atan(ventralPos.y, ventralPos.x);
float ventralFlow = snoise(vec3(ventralAngle * 3.0, radius * 5.0, time * 0.5 + 1.5)) * 0.3;
float ventralFin = smoothstep(0.25, 0.0, abs(ventralAngle + 1.57)) *
smoothstep(0.5, 0.0, radius - 0.15 - ventralFlow);
// Tail fin (caudal)
vec2 tailPos = p - vec2(-0.25, 0.0);
float tailAngle = atan(tailPos.y, tailPos.x);
float tailRadius = length(tailPos);
float tailFlow = fbm(vec3(tailAngle * 2.0, tailRadius * 3.0, time * 0.3));
float tailSpread = 0.4 + tailFlow * 0.3;
float tailFin = smoothstep(tailSpread, 0.0, abs(tailAngle)) *
smoothstep(0.6, 0.0, tailRadius - tailFlow * 0.2);
// Pectoral fins (side fins)
float pectoralFlow = snoise(vec3(p * 8.0, time * 0.8));
float pectoralFin = smoothstep(0.15, 0.0, length(p - vec2(0.1, 0.12))) *
(0.5 + pectoralFlow * 0.5);
pectoralFin += smoothstep(0.15, 0.0, length(p - vec2(0.1, -0.12))) *
(0.5 + pectoralFlow * 0.5);
return max(max(dorsalFin, ventralFin), max(tailFin, pectoralFin));
}
// Iridescent color palette for Betta
vec3 bettaColor(vec2 p, float noise, float time) {
float angle = atan(p.y, p.x);
float radius = length(p);
// Base colors: deep blue, crimson red, teal, purple
vec3 color1 = vec3(0.1, 0.3, 0.8); // Deep blue
vec3 color2 = vec3(0.8, 0.1, 0.3); // Crimson
vec3 color3 = vec3(0.2, 0.7, 0.7); // Teal
vec3 color4 = vec3(0.6, 0.2, 0.8); // Purple
// Mix colors based on position and noise
float mixFactor = sin(angle * 3.0 + time * 0.5 + noise * 2.0) * 0.5 + 0.5;
vec3 baseColor = mix(
mix(color1, color2, mixFactor),
mix(color3, color4, mixFactor),
sin(radius * 5.0 + time + noise) * 0.5 + 0.5
);
// Iridescent shimmer
float shimmer = fbm(vec3(p * 10.0, time * 0.2));
baseColor += shimmer * 0.3;
return baseColor;
}
// Bubble nest in background
float bubbles(vec2 p, float time) {
float bubble = 0.0;
for(float i = 0.0; i < 20.0; i++) {
vec2 offset = vec2(
snoise(vec3(i * 0.5, time * 0.3, 0.0)) * 0.8,
0.6 + snoise(vec3(i * 0.3, time * 0.2, 1.0)) * 0.3
);
float size = 0.02 + snoise(vec3(i, time * 0.1, 2.0)) * 0.015;
float dist = length(p - offset);
float ring = smoothstep(size, size - 0.005, dist) - smoothstep(size - 0.005, size - 0.01, dist);
bubble += ring * 0.3;
}
return bubble;
}
// Vegetation (plants)
float vegetation(vec2 p, float time) {
float plants = 0.0;
for(float i = 0.0; i < 8.0; i++) {
float xPos = -0.8 + i * 0.2;
vec2 plantPos = p - vec2(xPos, -0.7);
float sway = snoise(vec3(i, time * 0.4, 0.0)) * 0.1;
plantPos.x -= sway * (plantPos.y + 0.7);
float stem = smoothstep(0.01, 0.0, abs(plantPos.x));
stem *= smoothstep(0.5, 0.0, plantPos.y + 0.7);
plants += stem * 0.4;
// Leaves
for(float j = 0.0; j < 4.0; j++) {
float leafY = -0.5 + j * 0.15;
vec2 leafPos = plantPos - vec2(0.0, leafY);
float leafAngle = sin(time * 0.5 + i + j) * 0.5;
float leaf = smoothstep(0.05, 0.0, length(leafPos - vec2(leafAngle * 0.05, 0.0)));
plants += leaf * 0.2;
}
}
return plants;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
st = st * 2.0 - 1.0;
st.x *= u_resolution.x / u_resolution.y;
float time = u_time * 0.5;
// Position betta fish in center, slightly offset
vec2 fishPos = st - vec2(0.1, 0.0);
// Add gentle swimming motion
float swimMotion = sin(time * 0.8) * 0.05;
fishPos.y -= swimMotion;
fishPos.x += cos(time * 0.6) * 0.03;
// Rotate fish slightly for dynamic pose
float swimAngle = sin(time * 0.5) * 0.1;
float c = cos(swimAngle);
float s = sin(swimAngle);
fishPos = vec2(fishPos.x * c - fishPos.y * s, fishPos.x * s + fishPos.y * c);
// Betta body
float body = 1.0 - smoothstep(0.0, 0.02, sdEllipse(fishPos - vec2(0.05, 0.0), vec2(0.15, 0.08)));
// Head
float head = smoothstep(0.12, 0.0, length(fishPos - vec2(0.2, 0.0)));
body = max(body, head);
// Flowing fins
float finMask = fins(fishPos, time);
// Combine body and fins
float fishMask = max(body, finMask * 0.8);
// Generate procedural noise for texture
float noisePattern = fbm(vec3(fishPos * 8.0, time * 0.2));
// Fish colors
vec3 fishColor = bettaColor(fishPos, noisePattern, time);
// Fin colors (more translucent and vibrant)
vec3 finColor = bettaColor(fishPos, noisePattern + 0.5, time + 1.0);
finColor = mix(finColor, vec3(1.0), finMask * 0.3); // Add translucency
// Background gradient (aquarium water)
vec3 bgColor = mix(
vec3(0.02, 0.1, 0.15), // Dark blue-green
vec3(0.05, 0.15, 0.25), // Lighter blue
st.y * 0.5 + 0.5
);
// Add bubbles
float bubbleMask = bubbles(st, time);
bgColor += vec3(bubbleMask * 0.5);
// Add vegetation
float plantMask = vegetation(st, time);
vec3 plantColor = vec3(0.1, 0.4, 0.2);
bgColor = mix(bgColor, plantColor, plantMask);
// Combine all elements
vec3 finalColor = bgColor;
// Apply fish (body and fins)
finalColor = mix(finalColor, fishColor, body);
finalColor = mix(finalColor, finColor, finMask * (1.0 - body));
// Add subtle eye
float eye = smoothstep(0.02, 0.0, length(fishPos - vec2(0.22, 0.02)));
finalColor = mix(finalColor, vec3(0.0), eye);
// Add eye highlight
float eyeHighlight = smoothstep(0.008, 0.0, length(fishPos - vec2(0.225, 0.025)));
finalColor = mix(finalColor, vec3(1.0), eyeHighlight);
// Subtle water caustics
float caustics = snoise(vec3(st * 5.0, time * 0.3));
caustics = pow(max(caustics, 0.0), 2.0) * 0.15;
finalColor += caustics;
// Output color
colour_out = vec4(finalColor, 1.0);
}
Azure Flame (Betta splendens) by AquaArtist
precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
in vec2 coord;
//
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20201014 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r) {
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v) {
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) );
}
//★ここから★
// 楕円の距離関数
float ellipse(vec2 coord, vec2 center, vec2 radius) {
vec2 pos = (coord - center) / radius;
return length(pos) - 1.0;
}
float MainBody(vec2 coord) {
//中心(0,0),半径(0.6,0.2)
float d = ellipse(coord, vec2(0.2, 0.0), vec2(0.6, 0.2));
return 1.0 - smoothstep(0.0, 0.2, d);
}
//腹ヒレ(ちび)
float PelvicFin(vec2 coord) {
vec2 fin_center = vec2(0.45, -0.1); // 腹ひれ位置
vec2 pos_orig = coord - fin_center;
float distortion_scale = pow(length(pos_orig) * 3.0, 1.5);
float wave_noise = snoise(vec3(pos_orig * 5.0, u_time * 2.5));
vec2 pos = pos_orig;
pos.x += sin(pos_orig.y * 20.0 + u_time * 4.0) * wave_noise * 0.03 * distortion_scale;
pos.y += sin(pos_orig.x * 20.0 + u_time * 3.5) * wave_noise * 0.02 * distortion_scale;
float fin_x_scale = 0.08; // 横幅
float fin_y_scale = 0.35; // 縦
float d = (pos.x * pos.x) / (fin_x_scale * fin_x_scale) + (pos.y * pos.y) / (fin_y_scale * fin_y_scale);
// 輪郭ノイズ
float noise_edge = snoise(vec3(pos * 30.0, u_time * 0.5)) * 0.05;
float mask = 1.0 - smoothstep(1.0 + noise_edge, 1.05 + noise_edge, d);
return (pos_orig.y < 0.0) ? mask : 0.0;
}
//台形したがわ
float TrapezoidFin(vec2 coord) {
vec2 fin_center = vec2(0.12, -0.1);
vec2 pos_orig = coord - fin_center;
vec2 pos = pos_orig;
float depth = -pos.y;
// 幅
float width = 0.35 + max(0.0, depth) * 0.2;
float fin_len = 0.7; // ヒレの長さ
float dx = abs(pos.x) / width;
float dy = depth / fin_len;
float wave = snoise(vec3(pos.x * 10.0, u_time * 3.0, 0.0)) * 0.05 * smoothstep(0.2, 1.0, dy);
float mask_x = 1.0 - smoothstep(0.8, 1.0, dx);
float mask_y = smoothstep(0.0, 0.1, dy) * (1.0 - smoothstep(0.85 + wave, 1.0 + wave, dy));
float alpha_fade = 1.0 - smoothstep(0.5, 1.0 + wave, dy);
float mask = mask_x * mask_y * alpha_fade;
return (pos_orig.y < 0.05) ? mask : 0.0;
}
//上側
float DorsalFin(vec2 coord) {
vec2 fin_center = vec2(0.0, 0.1);
vec2 pos_orig = coord - fin_center;
vec2 pos = pos_orig;
float height = pos.y;
float width = 0.25 + max(0.0, height) * 0.15;
float fin_len = 0.6; // ヒレの長さ
float dx = abs(pos.x) / width;
float dy = height / fin_len;
float wave = snoise(vec3(pos.x * 10.0, u_time * 3.0, 10.0)) * 0.05 * smoothstep(0.2, 1.0, dy);
float mask_x = 1.0 - smoothstep(0.8, 1.0, dx);
float mask_y = smoothstep(0.0, 0.1, dy) * (1.0 - smoothstep(0.85 + wave, 1.0 + wave, dy));
float alpha_fade = 1.0 - smoothstep(0.5, 1.0 + wave, dy);
float mask = mask_x * mask_y * alpha_fade;
return (pos_orig.y > -0.05) ? mask : 0.0;
}
float tail(vec2 coord) {
vec2 tail_center = vec2(-0.2, -0.010);
vec2 pos_orig = coord - tail_center;
float distortion_scale = pow(length(pos_orig) * 1.5, 1.5);
float wave_noise = snoise(vec3(pos_orig * 4.0, u_time * 3.0));
vec2 pos = pos_orig;
pos.x -= sin(pos_orig.y * 15.0 + u_time * 5.0) * wave_noise * 0.05 * distortion_scale;
pos.y += sin(pos_orig.x * 15.0 + u_time * 4.0) * wave_noise * 0.03 * distortion_scale;
float r = length(pos);
float angle = atan(pos.y, -pos.x);
float min_angle = -1.7;
float max_angle = 1.7;
float max_r = 0.8;
float tail_mask = step(min_angle, angle) * step(angle, max_angle);
// 形状と先端ノイズ
float tip_noise = snoise(vec3(pos * 10.0, u_time * 1.0)) * 0.05;
tail_mask *= 1.0 - smoothstep(max_r * 0.5, max_r + tip_noise, r);
tail_mask *= smoothstep(0.0, 0.15, r);
return tail_mask;
}
// 胸ビレ
float PectoralFin(vec2 coord) {
vec2 center = vec2(0.35, 0.0);
vec2 pos = coord - center;
// ヒレアニメーション
float flap_speed = u_time * 5.0; //早さ
float angle_sway = sin(flap_speed) * 0.15; // 振れ幅
float c = cos(angle_sway);
float s = sin(angle_sway);
pos = mat2(c, -s, s, c) * pos;
// 貝殻の形
float r = length(pos);
float a = atan(pos.y, -pos.x);
float angle_mask = step(abs(a), 0.8);
float max_len = 0.25;
float shape_edge = max_len * (0.8 + 0.2 * cos(a * 2.0));
float frill = 0.01 * sin(a * 100.0); // 細かい波
float ridges = 0.04 * sin(a * 20.0); // 大きなうねり
float shape_mask = 1.0 - smoothstep(shape_edge + ridges + frill, shape_edge + ridges + frill + 0.03, r);
return shape_mask * angle_mask;
}
float EyeMask(vec2 coord) {
// 位置
vec2 eye_center = vec2(0.55, 0.05);
float d_pupil = length(coord - (eye_center + vec2(0.01, 0.0)));
float pupil = 1.0 - smoothstep(0.02, 0.025, d_pupil);
float d_high = length(coord - (eye_center + vec2(0.02, 0.015)));
float highlight = 1.0 - smoothstep(0.005, 0.01, d_high);
return clamp(pupil + highlight, 0.0, 1.0);
}
vec3 colorMap(vec2 coord, float mask) {
vec3 base = mix(vec3(0.1, 0.3, 0.8), vec3(0.9, 0.1, 0.2), coord.x + 0.5);
float noise = snoise(vec3(coord * 8.0, u_time * 0.2));
return base + noise * 0.1 * mask;
}
vec3 BodyColor(vec2 coord, float noise) {
vec2 center = vec2(0.2, 0.0);
vec2 pos_rel = coord - center;
vec2 normalized_pos = pos_rel / vec2(0.6, 0.2);
float dist = length(normalized_pos);
float blend_factor = smoothstep(0.0, 1.0, dist);
vec3 inner_color = vec3(0.99, 0.77, 0.99); // 濃いピンク
vec3 outer_color = vec3(1.0, 0.85, 0.98); // ほぼ白に近い薄ピンク
// 距離に基づいて内側から外側へ
vec3 base = mix(inner_color, outer_color, blend_factor);
return base + noise * 0.1;
}
float stripePattern(float v, float scale) {
// sin波を使って縞模様を作る。0.95以上の部分だけを1.0にする(細い線)
return smoothstep(0.95, 1.0, sin(v * scale));
}
// 腹ヒレ (ちっちゃいやつ) の色
vec3 PelvicColor(vec2 coord, float noise) {
// (ピンク -> 少し濃いピンク)
vec3 base = mix(vec3(1.0, 0.85, 0.98), vec3(0.9, 0.6, 0.8), -coord.y * 2.0);
return base * 0.9 + noise * 0.05;
}
// 上下の台形ヒレ
vec3 AnalDorsalColor(vec2 coord, float noise) {
float dist = abs(coord.y); // 中心からの距離
vec3 base = mix(vec3(1.0, 0.85, 0.98), vec3(0.8, 0.6, 0.8), dist * 2.0);
float stripes = stripePattern(coord.x, 140.0);
vec3 stripe_color = vec3(0.9, 0.5, 0.7);
// ベース色にストライプ入れる
vec3 final_color = mix(base, stripe_color, stripes * 0.3);
return final_color + noise * 0.05;
}
// 尾鰭
vec3 TailColor(vec2 coord, float noise) {
vec2 center = vec2(-0.2, -0.010);
vec2 pos = coord - center;
float r = length(pos);
vec3 base = mix(vec3(1.0, 0.85, 0.98), vec3(0.9, 0.6, 0.8), r * 1.5);
float angle = atan(pos.y, -pos.x);
float rays = stripePattern(angle, 70.0);
// ラインの色
vec3 ray_color = vec3(0.9, 0.5, 0.7);
vec3 final_color = mix(base, ray_color, rays * 0.3);
return final_color + noise * 0.05;
}
// --- 胸ビレの色 ---
vec3 PectoralColor(vec2 coord, float noise) {
vec2 center = vec2(0.35, 0.0);
vec2 pos = coord - center;
float r = length(pos);
float angle = atan(pos.y, -pos.x);
float stripe_wave = sin(angle * 60.0);
float ridges = smoothstep(0.8, 0.95, stripe_wave);
vec3 root_color = vec3(1.0, 0.85, 0.98); // 根元のピンク
vec3 tip_color = vec3(0.9, 0.7, 0.9); // 先端(少し濃いor白っぽい)
// 外側に行くほど色が変化
vec3 base = mix(root_color, tip_color, r * 4.5);
// ストライプ色
vec3 stripe_col = vec3(0.95, 0.6, 0.8);
// 合成
vec3 col = mix(base, stripe_col, ridges * 0.3);
return col + noise * 0.03;
}
float lighting(vec2 coord) {
vec3 lightDir = normalize(vec3(0.5, 0.5, 1.0)); // 光の方向
vec3 normal = normalize(vec3(coord.x, coord.y, 1.0)); // 疑似法線
float diff = dot(lightDir, normal);
return 0.6 + 0.4 * max(diff, 0.0); // 明暗
}
void main() {
vec2 coord = gl_FragCoord.xy / u_resolution.xy;
coord = coord * 2.0 - 1.0; // [-1,1]空間
float body_mask = MainBody(coord);
float pelvic_mask = PelvicFin(coord);
float anal_dorsal_mask = TrapezoidFin(coord) + DorsalFin(coord);
float tail_mask = tail(coord);
// ★追加: 胸ビレ
float pectoral_mask = PectoralFin(coord);
float noise = snoise(vec3(coord * 8.0, u_time * 0.2));
float light = lighting(coord);
vec3 body_color_rgb = BodyColor(coord, noise) * light;
vec3 pelvic_color_rgb = PelvicColor(coord, noise) * light;
vec3 anal_dorsal_color_rgb = AnalDorsalColor(coord, noise) * light;
vec3 tail_color_rgb = TailColor(coord, noise) * light;
vec3 pectoral_color_rgb = PectoralColor(coord, noise) * light;
float shadow_strength = 0.1; // 影の強さ
// 上下ヒレ
vec3 color_layer1 = anal_dorsal_color_rgb * clamp(anal_dorsal_mask, 0.0, 1.0);
float alpha_layer1 = clamp(anal_dorsal_mask, 0.0, 1.0);
vec3 current_color = color_layer1;
float current_alpha = alpha_layer1;
// ちちゃいひれ
float shadow_pelvic = 1.0 - (anal_dorsal_mask * shadow_strength);
vec3 color_layer2 = pelvic_color_rgb * clamp(pelvic_mask, 0.0, 1.0) * shadow_pelvic;
float alpha_layer2 = clamp(pelvic_mask, 0.0, 1.0);
current_color = mix(current_color, color_layer2, alpha_layer2);
current_alpha = current_alpha + alpha_layer2 * (1.0 - current_alpha);
// 尾鰭
float lower_fins = clamp(anal_dorsal_mask + pelvic_mask, 0.0, 1.0);
float shadow_tail = 1.0 - (lower_fins * shadow_strength);
vec3 color_layer3 = tail_color_rgb * clamp(tail_mask, 0.0, 1.0) * shadow_tail;
float alpha_layer3 = clamp(tail_mask, 0.0, 1.0);
current_color = mix(current_color, color_layer3, alpha_layer3);
current_alpha = current_alpha + alpha_layer3 * (1.0 - current_alpha);
// からだ
float body_alpha = clamp(body_mask, 0.0, 1.0);
current_color = mix(current_color, body_color_rgb, body_alpha);
current_alpha = current_alpha + body_alpha * (1.0 - current_alpha);
float pectoral_alpha = clamp(pectoral_mask, 0.0, 1.0);
current_color = mix(current_color, pectoral_color_rgb, pectoral_alpha * 0.8);
current_alpha = current_alpha + pectoral_alpha * (1.0 - current_alpha);
float pupil_mask = EyeMask(coord);
vec3 eye_color = vec3(0.05);
// ハイライト
vec2 eye_center = vec2(0.55, 0.05);
float d_high = length(coord - (eye_center + vec2(0.015, 0.015)));
float highlight = 1.0 - smoothstep(0.005, 0.01, d_high);
eye_color = mix(eye_color, vec3(1.0), highlight);
current_color = mix(current_color, eye_color, pupil_mask);
current_alpha = max(current_alpha, pupil_mask);
float final_alpha = (body_mask > 0.001 || pupil_mask > 0.001) ? 1.0 : current_alpha;
colour_out = vec4(current_color, final_alpha);
}
unknown by purichan
uniform vec2 u_resolution;
uniform float u_time;
// ========================
// noise function (noise3D)
// ========================
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
// eye
float sdCircle( vec2 p, float r )
{
return length(p) - r;
}
// body
float sdVesica(vec2 p, float w, float h)
{
float d = 0.5*(w*w-h*h)/h;
p = abs(p);
vec3 c = (w*p.y<d*(p.x-w)) ? vec3(0.0,w,0.0) : vec3(-d,0.0,d+h);
return length(p-c.yx) - c.z;
}
// unitility rotation function
vec2 rot(vec2 p, float a) {
float s = sin(a), c = cos(a);
return vec2(c*p.x - s*p.y, s*p.x + c*p.y);
}
// fin
float sdPieRight(vec2 p, vec2 c, float r)
{
// wiggle the outline
float n = snoise(vec3(p * 5.0, u_time * 0.0005));
p.x += n * 0.03;
p.y += n * 0.03;
// rotate -π/2
p = rot(p, radians(-90.0));
p.x = abs(p.x);
float l = length(p) - r;
float m = length(p - c * clamp(dot(p, c), 0.0, r));
float d = max(l, m * sign(c.y*p.x - c.x*p.y));
return d;
}
// small fin
float sdPieRight2(vec2 p, vec2 c, float r)
{
// rotate -π/2
p = rot(p, radians(-90.0));
p.x = abs(p.x);
float l = length(p) - r;
float n = snoise(vec3(p * 4.0, u_time * 0.0005)) * 0.05;
l += n;
float m = length(p - c * clamp(dot(p, c), 0.0, r));
float d = max(l, m * sign(c.y*p.x - c.x*p.y));
return d;
}
void main()
{
vec2 uv = gl_FragCoord.xy/u_resolution.xy*2.0 -1.0;
vec3 temp = vec3(uv, 1.0);
mat3 translate = mat3(
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
sin(u_time * 0.001)/10.0, sin(u_time * 0.001)/15.0, 0.0
);
temp = translate * temp;
vec2 UV = temp.xy;
float eye = sdCircle(vec2(UV.x + 0.495, UV.y - 0.02), 0.02);
float body = sdVesica(UV, 0.6, 0.15);
float fin = sdPieRight(vec2(UV.x, UV.y), vec2(-1.0, 0.2), 0.8);
float sFin = sdPieRight2(vec2(UV.x + 0.3, UV.y + 0.1), vec2(-0.3, 0.5), 0.4);
if (sFin <= 0.0)
{
float rNoise = snoise(vec3(20.0 * UV.x, 2.0 * UV.y, u_time * 0.0005));
rNoise = (rNoise / 2.0) + 0.5;
colour_out = vec4(rNoise + 0.2, 0.5, 0.8, 1.0);
}
else if (eye <= 0.0)
{
colour_out = vec4(0.0, 0.0, 0.0, 1.0);
}
else if (body <= 0.0)
{
float rNoise = snoise(vec3(15.0 * UV.x, 15.0 * UV.y, u_time * 0.0005));
rNoise = (rNoise / 2.0) + 0.5;
colour_out = vec4(rNoise / 3.0, 0.50, 1.0, 1.0);
}
else if (fin <= 0.0)
{
float rNoise = snoise(vec3(8.0 * UV.x, 1.5 * UV.y, u_time * 0.0005));
rNoise = (rNoise / 2.0) + 0.5;
colour_out = vec4(rNoise / 2.0, 0.5, 0.8, 1.0);
}
else
{
colour_out = vec4(0.0, 0.0, 0.3, 1.0);
}
}
Unknown by Rosario
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
vec4 blue = vec4(0., .5, 1.,1.0);
vec4 black = vec4(.1, .1, .2,1.0);
vec4 white = vec4(1.);
vec4 bg = vec4(0.8);
float cross2(vec2 v1, vec2 v2) {
return v1.x*v2.y - v1.y*v2.x;
}
// 鱗柄
vec4 Scales (vec2 xy) {
vec2 st = xy;
st.x *= 10.;st.y *= 6.; // raito
st = fract(st);
st *= 4.; // scale
float index = 0.;
index += step(1., mod(st.x,2.));
index += step(1., mod(st.y,2.))*2.;
st = fract(st);
st -= 0.5;
// index
// 0.:BL 1.:BR 2.:TL 3.:TR
if(index == 1. || index == 2.){
st.x = -st.x;
}
float l1=abs(cross2(st,normalize(vec2(1.,1.))));
float l2=length(vec2(0., st.y));
vec3 c = blue.rgb;
if (l1 <= .12 || l2 <= .07){
c = black.rgb;
}
return vec4(c ,1.);
}
float dot2( in vec2 v ) { return dot(v,v); }
// ハート型 p:中心
float sdHeart( in vec2 p )
{
p.x = abs(p.x);
if( p.y+p.x>1.0 )
return sqrt(dot2(p-vec2(0.25,0.75))) - sqrt(2.0)/4.0;
return sqrt(min(dot2(p-vec2(0.00,1.00)),
dot2(p-0.5*max(p.x+p.y,0.0)))) * sign(p.x-p.y);
}
// 楕円 p:中心 ab:半径(縦, 横)
float sdEllipse( in vec2 p, in vec2 ab )
{
p = abs(p); if( p.x > p.y ) {p=p.yx;ab=ab.yx;}
float l = ab.y*ab.y - ab.x*ab.x;
float m = ab.x*p.x/l; float m2 = m*m;
float n = ab.y*p.y/l; float n2 = n*n;
float c = (m2+n2-1.0)/3.0; float c3 = c*c*c;
float q = c3 + m2*n2*2.0;
float d = c3 + m2*n2;
float g = m + m*n2;
float co;
if( d<0.0 )
{
float h = acos(q/c3)/3.0;
float s = cos(h);
float t = sin(h)*sqrt(3.0);
float rx = sqrt( -c*(s + t + 2.0) + m2 );
float ry = sqrt( -c*(s - t + 2.0) + m2 );
co = (ry+sign(l)*rx+abs(g)/(rx*ry)- m)/2.0;
}
else
{
float h = 2.0*m*n*sqrt( d );
float s = sign(q+h)*pow(abs(q+h), 1.0/3.0);
float u = sign(q-h)*pow(abs(q-h), 1.0/3.0);
float rx = -s - u - c*4.0 + 2.0*m2;
float ry = (s - u)*sqrt(3.0);
float rm = sqrt( rx*rx + ry*ry );
co = (ry/sqrt(rm-rx)+2.0*g/rm-m)/2.0;
}
vec2 r = ab * vec2(co, sqrt(1.0-co*co));
return length(r-p) * sign(p.y-r.y);
}
float sdEgg( in vec2 p, in float ra, in float rb )
{
const float k = sqrt(3.0);
p.x = abs(p.x);
float r = ra - rb;
return ((p.y<0.0) ? length(vec2(p.x, p.y )) - r :
(k*(p.x+r)<p.y) ? length(vec2(p.x, p.y-k*r)) :
length(vec2(p.x+r,p.y )) - 2.0*r) - rb;
}
float sdTriangle( in vec2 p, in vec2 p0, in vec2 p1, in vec2 p2 )
{
vec2 e0 = p1-p0, e1 = p2-p1, e2 = p0-p2;
vec2 v0 = p -p0, v1 = p -p1, v2 = p -p2;
vec2 pq0 = v0 - e0*clamp( dot(v0,e0)/dot(e0,e0), 0.0, 1.0 );
vec2 pq1 = v1 - e1*clamp( dot(v1,e1)/dot(e1,e1), 0.0, 1.0 );
vec2 pq2 = v2 - e2*clamp( dot(v2,e2)/dot(e2,e2), 0.0, 1.0 );
float s = sign( e0.x*e2.y - e0.y*e2.x );
vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
return -sqrt(d.x)*sign(d.y);
}
float sdBox( in vec2 p, in vec2 b )
{
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
mat2 rot2d(float a){
float c = cos(a);
float s = sin(a);
return mat2(c, -s, s, c);
}
// Simplex Noise 2D
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(vec2 v)
{
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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() {
float pi = 3.14159265359;
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float mask = 1.0;
// 目
if (0. > sdEllipse(st.xy - vec2(0.25,0.55), vec2(0.04 ,0.05))){
if (0. > sdEllipse(st.xy - vec2(0.23,0.535) - (u_mouse * 0.0002 ), vec2(0.023 ,0.03))){
colour_out = black;
return;
}
colour_out = white;
return;
}
// 胴
if (0. > sdBox((st.xy - vec2(0.5,0.5))*rot2d(-pi/28.), vec2(0.2,0.11))){
colour_out =Scales(st);
return;
}
// 頭
if (0. > sdEllipse(st.xy - vec2(0.38,0.51), vec2(0.25 ,0.135))){
colour_out =Scales(st);
return;
}
// 尾びれ
float tail = sdHeart((st.xy - vec2(1.,0.5))*rot2d(-pi/2.) /.3);
if (tail < 0.)
{
if (tail > -.02) {
colour_out = black;
return;
}
vec2 center =
vec2(.68,0.5);
//u_mouse * 0.005;
vec2 pos = st.xy - center;
// 極座標に変換
float r = length(pos);
float a = atan(pos.y, pos.x);
float curveStrength =8.;
a = a + (st.y - 0.5) * curveStrength;
vec2 noiseUV = vec2(r * .2, a * 6.0);
float sn = snoise(noiseUV);
float pattern = step(0.3, sn);
colour_out = mix(blue, black, pattern);
return;
}
// 背びれ
if (0. >
sdEgg(
(st.xy - vec2(0.565,0.7))
*rot2d(pi/4.),
0.1, 0.02
)
)
{
vec2 noiseUV = st; noiseUV.x *= 0.4;
float scale = 30.;
float sn = snoise(noiseUV * scale);
float pattern = step(0.3, sn);
colour_out = mix(blue, black, pattern);
return;
}
// 腹びれ
if (0. >
sdEgg(
(st.xy - vec2(0.55,0.3))
* rot2d(-pi/4.),
0.1, 0.02
)
) {
vec2 noiseUV = st; noiseUV.y *= 0.01;
float scale = 80.;
float sn = snoise(noiseUV * scale);
float pattern = step(0.18, sn);
colour_out = mix(blue, black, pattern);
return;
}
// 胸鰭
if (0. >
sdTriangle(
st.xy,
vec2(0.37,0.37),
vec2(0.4,0.1),
vec2(0.3,0.4)
)
) {
vec2 noiseUV = st; noiseUV.y *= 0.5;
float scale = 7.;
float sn = snoise(noiseUV * scale);
float pattern = step(0.5, sn);
colour_out = mix(black, blue, pattern);
return;
}
if (0. >
sdTriangle(
st.xy,
vec2(0.37,0.37),
vec2(0.3,0.1),
vec2(0.3,0.4))
){
colour_out = black;
return;
}
colour_out = bg;
}
gyorogyoro by triw
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
// ============================================================
// Noise Functions
// ============================================================
//
// Description : Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(vec2 v)
{
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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);
}
// ============================================================
// Noise Functions End
// ============================================================
// ============================================================
// Pattern Functions (新しく追加した模様生成関数)
// ============================================================
// 規則正しい鱗(ウロコ)模様を作る関数
float getScalePattern(vec2 p) {
// 1. スケーリング:模様のサイズ調整
vec2 uv = p * vec2(25.0, 20.0);
// 2. 交互配置:行(y)ごとに、列(x)を0.5個分ずらす
float shift = mod(floor(uv.x), 2.0) * 0.5;
uv.y += shift;
// 3. ローカル座標:各タイルの中の座標(0.0~1.0)を取得
vec2 cell = fract(uv);
// 4. 形状作成:タイルの下辺中央からの距離を測る
float d = distance(cell, vec2(0.5, 0.4));
// 5. 描画:距離に応じて白黒をつける(半円のような形)
// 0.5(半径)より内側なら白っぽく、外側なら黒っぽく
// smoothstepを使って境界を少しぼかし、滑らかに
float scale = smoothstep(0.6, 0.4, d);
// 輪郭を少し強調するために、値を調整
return 0.5 + 0.5 * scale;
}
// ▼ ヒレ用の放射状模様▼
// 引数center:放射の中心点
float getFinPattern(vec2 p, vec2 center) {
// 中心点からのベクトルで角度を計算
vec2 dir = p - center;
float angle = atan(dir.y, dir.x);
// ノイズと縞模様の生成
float n = snoise(vec2(angle * 8.0, 0.0));
float stripe = sin(n * 5.0);
stripe = stripe * 0.5 + 0.5;
return mix(0.5, 1.0, stripe);
}
// ============================================================
// Pattern Functions End
// ============================================================
// 回転行列
vec2 rotate(vec2 p, float angle) {
float s = sin(angle);
float c = cos(angle);
return mat2(c, -s, s, c) * p;
}
float sdCircle(vec2 p,float r){
return length(p)-r;
}
// 基本の楕円
float sdEllipse(vec2 p, vec2 r) {
return length(p / r) - 1.0;
}
// 半分の楕円(下半分をカットして、上半分を残す形状)
// 腹ひれとして使う際、平らな面を胴体に接合させるため
float sdHalfEllipse(vec2 p, vec2 r) {
float d = sdEllipse(p, r);
// -p.y で「yが0より小さい部分(下半分)」を切り落とす
return max(d, -p.y);
}
void main() {
// 座標の正規化
vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / min(u_resolution.x, u_resolution.y);
float wave = sin(st.x * 2.0 - u_time * 3.0);
// 魚らしくするため、頭(右側)はあまり揺れず、尾(左側)ほど大きく揺れるように調整
float waveAmp = 0.05 * smoothstep(-0.5, 1.0, 0.4 - st.x);
// Y座標に波の値を足して、空間を歪める
st.y += wave * waveAmp;
// ------------------------------------
// 1. 胴体(Body)
// ------------------------------------
float d_body = sdEllipse(st, vec2(0.5, 0.14));
// ------------------------------------
// 2. 背びれ(Dorsal Fin): 通常の楕円
// ------------------------------------
vec2 p_top = st;
// 位置調整: 胴体の上へ
p_top += vec2(0.15, -0.1);
// 回転: 後ろへ流す
p_top = rotate(p_top, -0.1);
// 描画
float d_top = sdEllipse(p_top, vec2(0.35, 0.15));
// ------------------------------------
// 3. 腹ひれ(Ventral Fin): 半分の楕円
// ------------------------------------
vec2 p_btm = st;
// 位置調整: 胴体の下へ
p_btm += vec2(0.25, -0.05);
// 回転: 後ろへ流す
p_btm = rotate(p_btm, 2.7);
// 描画: 半円関数を使用
// ここでは「上半分」が残る形なので、回転させて平らな面を胴体に向けます
float d_btm = sdHalfEllipse(p_btm, vec2(0.35, 0.3));
// 4. Eye
// 胴体と同じ座標系 st を使い、位置をずらす
vec2 p_eye = st + vec2(-0.35, -0.05); // 右(顔の前の方)へ、少し下へ
float d_eye = sdCircle(p_eye, 0.03); // 半径0.03の小さな円
// ------------------------------------
// 結合 (Union)
// ------------------------------------
// min(A, B) で図形を足し合わせる
float d = min(d_top, d_btm);
d = min(d_body, d);
d = min(d,d_eye);
// 描画
float mask = 1.0 - step(0.0, d);
// 基本の色(元の青系)
vec3 baseColor = vec3(mask * 0.2, mask * 0.4, mask * 1.0);
// ============================================================
// 模様の適用処理
// ============================================================
vec3 finalColor = baseColor;
float pattern = 1.0;
if (mask > 0.5) {
// 「胴体の中にいるか?」を最優先でチェック
if (d_eye <= 0.001) {
finalColor = vec3(0.0); // 黒色
pattern = 0.0; // 模様も適用しない
}
// 胴体の内部(境界線 0.0 より小さい)なら胴体優先
else if (d_body <= 0.001) {
pattern = getScalePattern(st);
pattern *= 0.8;
}
// 胴体じゃなくて、背びれの内部なら背びれ
else if (d_top <= 0.001) {
pattern = getFinPattern(p_top,vec2(0.2, 0.0));
}
// 胴体じゃなくて、腹ひれの内部なら腹ひれ
else if (d_btm <= 0.001) {
pattern = getFinPattern(p_btm,vec2(0.0, 0.0));
}
// 目以外のパーツには模様を適用(目が選ばれたときはpatternが0なので影響なし)
if (d_eye > 0.001) {
finalColor *= pattern;
}
}else{
finalColor = vec3(0.750,0.990,1.000);
}
// ============================================================
colour_out = vec4(finalColor, 1.0);
}
seasky by Ayutaya
uniform vec2 u_resolution;
uniform float u_time;
vec2 rotate2D(vec2 p, float angle){
float c = cos(angle);
float s = sin(angle);
mat2 rot = mat2(c, s, -s, c);
return rot*p;
}
float sdCircle( vec2 p, float r ) {
return length(p) - r;
}
float sdUnion( float d1, float d2 ) {
return min( d1, d2 );
}
float sdSector(vec2 p, float r, float angle){
float l = length(p);
float a = atan(p.y, p.x);
float dist_angle = abs(a) - angle;
float dist_edge = l* sin(dist_angle);
float d_circle = l-r;
if (dist_angle <=0.0){
return d_circle;
}
float dist_rad = l * cos(dist_angle) - r;
return length(max(vec2(dist_rad, dist_edge), 0.0)) + min( max(dist_rad, dist_edge), 0.0);
}
float betta_body_sdf( vec2 p ) {
float angle = -0.35;
vec2 p_body =rotate2D(p, angle);
float s = 1.0 + 0.01 * sin(u_time*3.0 + p_body.x);
p_body.y *= 2.5+ 0.1 * sin(u_time*3.0 + p_body.y);
return sdCircle( p_body + vec2(0.35, -0.25), 0.6*s) ;
}
float betta_fin_sdf1(vec2 p){
vec2 fin_center = vec2(-0.05, 0.21);
vec2 p_fin = p- fin_center;
float wave_distort1 = sin(p.y * 10.0 + u_time * 2.0)* 0.03* length(p_fin);
p_fin.x += wave_distort1;
float fin_radius = 1.0;
float fin_half_angle = 3.14 * 0.3;
p_fin = rotate2D(p_fin,0.2);
return sdSector(p_fin, fin_radius, fin_half_angle);
}
float betta_fin_sdf2(vec2 p){
vec2 fin_up = vec2(0.29, 0.2);
vec2 p_fin3 = p - fin_up;
float wave_distort3 = sin(p.y * 6.0 + u_time * 3.0)* 0.0 * length(p_fin3);
p_fin3.x += wave_distort3;
p_fin3= rotate2D(p_fin3, -2.8);
float fin_half_angle3 = 3.14 * 0.5;
float fin_radius3 = 0.54;
return sdSector(p_fin3, fin_radius3, fin_half_angle3);
}
float betta_fin_sdf(vec2 p){
vec2 fin_down = vec2(-0.09, 0.02);
vec2 p_fin2 = p - fin_down;
float wave_distort2 = cos(p.x * 8.0 + u_time * 3.0) * 0.04 * length(p_fin2);
p_fin2.y += wave_distort2;
p_fin2= rotate2D(p_fin2, 0.9);
float fin_half_angle2 = 3.14 * 0.3;
float fin_radius2 = 0.7;
float d2_fin = sdSector(p_fin2, fin_radius2, fin_half_angle2);
vec2 fin_down2 = vec2(-0.3, -0.2);
vec2 p_fin4 = p - fin_down2;
float wave_distort4 = sin(p.y * 3.0 + u_time * 2.0)*0.03 * length(p_fin4);
p_fin4 += wave_distort4;
p_fin4= rotate2D(p_fin4, 1.2);
float fin_half_angle4 = 3.14 * 0.3;
float fin_radius4 = 0.25;
float d4_fin = sdSector(p_fin4, fin_radius4, fin_half_angle4);
return sdUnion(d4_fin, d2_fin);
}
float small_fin_sdf(vec2 p){
vec2 small_fin = p - vec2(-0.6, -0.25);
float wave_distort_s= sin(p.y * 3.0 + u_time * 9.0)*0.05 * length(small_fin);
small_fin += wave_distort_s;
return sdSector(small_fin, 0.2, 3.14*0.3);
}
float eye_sdf(vec2 p){
return sdCircle(p - vec2(-0.75, -0.2), 0.02);
}
//
// Description : Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20110822 (ijm)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
float snoise(vec2 v)
{
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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);
}
//
// Description : Array and textureless GLSL 2D/3D/4D simplex
// noise functions.
// Author : Ian McEwan, Ashima Arts.
// Maintainer : stegu
// Lastmod : 20201014 (stegu)
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
// Distributed under the MIT License. See LICENSE file.
// https://github.com/ashima/webgl-noise
// https://github.com/stegu/webgl-noise
//
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
// Cellular noise ("Worley noise") in 2D in GLSL.
// Copyright (c) Stefan Gustavson 2011-04-19. All rights reserved.
// This code is released under the conditions of the MIT license.
// See LICENSE file for details.
// https://github.com/stegu/webgl-noise
// Modulo 289 without a division (only multiplications)
// Modulo 7 without a division
vec3 mod7(vec3 x) {
return x - floor(x * (1.0 / 7.0)) * 7.0;
}
// Cellular noise, returning F1 and F2 in a vec2.
// Standard 3x3 search window for good F1 and F2 values
vec2 cellular(vec2 P) {
#define K 0.142857142857 // 1/7
#define Ko 0.428571428571 // 3/7
#define jitter 1.0 // Less gives more regular pattern
vec2 Pi = mod289(floor(P));
vec2 Pf = fract(P);
vec3 oi = vec3(-1.0, 0.0, 1.0);
vec3 of = vec3(-0.5, 0.5, 1.5);
vec3 px = permute(Pi.x + oi);
vec3 p = permute(px.x + Pi.y + oi); // p11, p12, p13
vec3 ox = fract(p*K) - Ko;
vec3 oy = mod7(floor(p*K))*K - Ko;
vec3 dx = Pf.x + 0.5 + jitter*ox;
vec3 dy = Pf.y - of + jitter*oy;
vec3 d1 = dx * dx + dy * dy; // d11, d12 and d13, squared
p = permute(px.y + Pi.y + oi); // p21, p22, p23
ox = fract(p*K) - Ko;
oy = mod7(floor(p*K))*K - Ko;
dx = Pf.x - 0.5 + jitter*ox;
dy = Pf.y - of + jitter*oy;
vec3 d2 = dx * dx + dy * dy; // d21, d22 and d23, squared
p = permute(px.z + Pi.y + oi); // p31, p32, p33
ox = fract(p*K) - Ko;
oy = mod7(floor(p*K))*K - Ko;
dx = Pf.x - 1.5 + jitter*ox;
dy = Pf.y - of + jitter*oy;
vec3 d3 = dx * dx + dy * dy; // d31, d32 and d33, squared
// Sort out the two smallest distances (F1, F2)
vec3 d1a = min(d1, d2);
d2 = max(d1, d2); // Swap to keep candidates for F2
d2 = min(d2, d3); // neither F1 nor F2 are now in d3
d1 = min(d1a, d2); // F1 is now in d1
d2 = max(d1a, d2); // Swap to keep candidates for F2
d1.xy = (d1.x < d1.y) ? d1.xy : d1.yx; // Swap if smaller
d1.xz = (d1.x < d1.z) ? d1.xz : d1.zx; // F1 is in d1.x
d1.yz = min(d1.yz, d2.yz); // F2 is now not in d2.yz
d1.y = min(d1.y, d1.z); // nor in d1.z
d1.y = min(d1.y, d2.x); // F2 is in d1.y, we're done.
return sqrt(d1.xy);
}
float fbm( vec3 p ) {
float f = 0.0, scale;
for (int i=0; i<4; i++) {
scale = pow( pow(2.0, 4.0/3.0), float(i) );
f += snoise( p * scale ) / scale;
}
return f; }
float noise(vec3 v) {
v.xy += vec2( fbm(v), fbm(vec3(v.xy, v.z + 10.)));
return fbm(v) * 0.35 + 0.45;
}
void main() {
vec2 uv = gl_FragCoord.xy/u_resolution.xy;
vec2 p = uv * 2.0 - 1.0;
vec2 noise_coord = gl_FragCoord.xy / 200.0 - vec2(u_time * 0.3, 0.0);
float noise_val = snoise(noise_coord) * 0.5 + 0.5;
vec4 background_color = vec4(vec3(0.4*noise_val, 0.4*noise_val, 0.25)* (1.0 + noise_val * 2.5),1.0);
vec4 color = background_color;
float dist = betta_body_sdf(p);
float dist2 = betta_fin_sdf(p);
float dist2_1 = betta_fin_sdf1(p);
float dist2_2 = betta_fin_sdf2(p);
float dist3 = small_fin_sdf(p);
float dist4 = eye_sdf(p);
if (dist2_2 <= 0.0) {
vec3 uv1 = vec3(0., 0.01*u_time ,length(p)-uv.y*0.8-uv.x*1.);
float noise = noise( uv1 );
vec3 color1 = vec3(cos(length(p))*1.1, abs(sin((u_time*0.8)*0.5+0.5)), sin(length(p))*1.5);
noise = pow( noise, 2. )*7.5;
color = vec4( color1,noise);
}else {
float edge_smooth = fwidth(dist2_2);
float alpha = smoothstep(edge_smooth, 0.0, dist2_2);
vec4 edge_color = vec4(vec3(0.95,0.95,0.95), 1.0);
color = mix(color, edge_color, alpha);
}
if (dist2 <= 0.0) {
vec3 uv1 = vec3(0., 0.01*u_time ,length(p)-uv.y*0.8-uv.x*1.);
float noise = noise( uv1 );
vec3 color1 = vec3(cos(length(p))*1.1, abs(sin((u_time*0.8)*0.5+0.5)), sin(length(p))*1.5);
noise = pow( noise, 2. )*7.5;
color = vec4( color1,noise);
}else {
float edge_smooth = fwidth(dist2);
float alpha = smoothstep(edge_smooth, 0.0, dist2);
vec4 edge_color = vec4(vec3(0.95,0.95, 0.95), 1.0);
color = mix(color, edge_color, alpha);
}
if (dist2_1 <= 0.0) {
vec3 uv1 = vec3(0., 0.01*u_time ,length(p)-uv.y*0.8-uv.x*1.);
float noise = noise( uv1 );
vec3 color1 = vec3(cos(length(p))*1.1, abs(sin((u_time*0.8)*0.5+0.5)), sin(length(p))*1.5);
noise = pow( noise, 2. )*7.5;
color = vec4( color1,noise);
}else {
float edge_smooth = fwidth(dist2_1);
float alpha = smoothstep(edge_smooth, 0.0, dist2_1);
vec4 edge_color = vec4(vec3(0.,0., 0.), 1.0);
color = mix(color, edge_color, alpha);
}
if(dist <= 0.0){
vec2 f = cellular(gl_FragCoord.xy/18.0);
vec2 f1=1.0 - f;
float n =f1.x;
float n2 =f.y;
vec4 color1 = vec4(mix(vec3(1.000,0.133,0.375), vec3(0.175,0.300,1.000), sin(u_time*1.05)*0.5 +0.5),n);
vec4 color2 = vec4(mix(vec3(1.000,0.133,0.375), vec3(0.175,0.300,1.000), sin(u_time*1.05)*0.5 +0.5),n2);
color = mix(color1, color2, sin(u_time*1.4)*0.5+0.5);
}else {
float edge_smooth = fwidth(dist);
float alpha = smoothstep(edge_smooth, 0.0, dist);
vec4 edge_color = vec4(vec3(0.95,0.95,0.95), 1.0);
color = mix(color, edge_color, alpha);
}
if(dist3<=0.0){
float n = snoise( gl_FragCoord.xy / 100.0 );
n = n*0.5 + 0.5;
color = mix(vec4(n, n*0.3, n*0.3,1.0), vec4(n*0.4, n*0.4,n, 1.0), sin(u_time*1.05)*0.5 + 0.5);
}else {
float edge_smooth = fwidth(dist3);
float alpha = smoothstep(edge_smooth, 0.0, dist3);
vec4 edge_color = vec4(vec3(0.95,0.95,0.95), 1.0);
color = mix(color, edge_color, alpha);
}
if(dist4<=0.0){
color= vec4(0.1,0.1,0.1,0.8);
}else {
float edge_smooth = fwidth(dist4);
float alpha = smoothstep(edge_smooth, 0.0, dist4);
vec4 edge_color = vec4(vec3(0.95,0.95,0.95), 1.0);
color = mix(color, edge_color, alpha);
}
colour_out = color;
}
Unknown by Ocean
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
float random1( vec2 p ) {
return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);
}
float finRayPattern(vec2 uv, float angle) {
float rays = sin(angle * 120.0 + sin(uv.x * 20.0));
float rings = sin(length(uv) * 40.0);
float pattern = smoothstep(0.0, 0.7, rays + rings * 0.2);
return pattern;
}
float sectorDist(vec2 uv) {
vec2 p = uv - vec2(0.0, 0.5);
float d = length(p);
d += (1.0 - step(0.0, p.x)) * 10.0;
return d;
}
void main() {
vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / min(u_resolution.x, u_resolution.y);
vec2 pos = st + vec2(0.2, 0.0);
vec2 animPos = pos;
float swim = sin(pos.y * 5.0 - u_time * 3.0) * 0.03;
animPos.x += swim * step(-1.0, pos.x);
// body
float headThinning = smoothstep(-1.3, 0.0, animPos.x);
float bodyThickness = 2.0 + (1.0 - headThinning) * 1.2;
float bodyLen = length((animPos * vec2(0.9, bodyThickness)) + vec2(0.0, -0.080 + 0.1 * sin(animPos.x * 3.0)));
float bodyShape = smoothstep(0.48, 0.45, bodyLen);
// fin
vec2 tailOrigin = animPos - vec2(0.45, 0.0);
float tAngle = atan(tailOrigin.y, tailOrigin.x);
float tDist = length(tailOrigin);
float chestnutCurve = cos(tAngle * 0.8);
float maxTailLen = 0.85 * chestnutCurve;
float tailShape = smoothstep(maxTailLen, maxTailLen - 0.05, tDist);
float fanWidth = 1.2;
tailShape *= smoothstep(fanWidth, fanWidth - 0.2, abs(tAngle));
tailShape *= smoothstep(0.0, 0.2, tDist);
vec2 dorsalPos = animPos - vec2(0.110, 0.190);
dorsalPos.x += dorsalPos.y * 0.5;
float dorsalShape = smoothstep(0.4, 0.35, length(dorsalPos * vec2(1.0, 1.8)));
dorsalShape *= smoothstep(-0.264, 0.1, -dorsalPos.y + 0.1);
dorsalShape *= smoothstep(-0.4, 0.2, dorsalPos.x);
vec2 ventralPos = animPos - vec2(0.130, -0.370);
ventralPos.x -= ventralPos.y * 1.096;
float ventralShape = smoothstep(0.458, 0.024, length(ventralPos * vec2(0.690, -0.600)));
ventralShape *= smoothstep(-0.040, 0.116, ventralPos.y + 0.100);
ventralShape *= smoothstep(0.440, -0.264, ventralPos.x);
float allFins = max(tailShape, max(dorsalShape, ventralShape));
vec3 cBlack = vec3(0.0, 0.0, 0.05);
vec3 cCyan = vec3(0.0, 1.0, 1.0);
vec3 bgColor = vec3(0.02, 0.05, 0.08);
vec2 scaleScale = vec2(18.0, 14.0);
vec2 scaleUV = animPos * scaleScale;
vec2 uv1 = fract(scaleUV);
vec2 id1 = floor(scaleUV);
float dist1 = sectorDist(uv1);
vec2 uv2 = fract(scaleUV + vec2(0.5, 0.5));
vec2 id2 = floor(scaleUV + vec2(0.5, 0.5));
float dist2 = sectorDist(uv2);
float dist = min(dist1, dist2);
float layerMask = step(dist1, dist2);
float rnd = mix(random1(id2), random1(id1), layerMask);
float scaleMask = smoothstep(0.62, 0.58, dist);
float innerMask = smoothstep(0.58, 0.54, dist);
vec3 bodyColor = cBlack;
vec3 scaleColor = mix(cBlack, cCyan, innerMask);
float shimmer = 0.5 + 0.5 * sin(u_time * 4.0 + rnd * 6.28);
scaleColor += cCyan * innerMask * shimmer * 0.7 * smoothstep(0.3, 0.0, dist);
bodyColor = mix(bodyColor, scaleColor, scaleMask);
float tailRays = finRayPattern(tailOrigin, tAngle);
float otherRays = sin(animPos.y * 99.112 + animPos.x * 18.168);
float finalFinTex = mix(otherRays, tailRays, step(-0.99, animPos.x));
vec3 finColor = mix(cBlack, cCyan, finalFinTex * 0.8);
float finAlpha = 0.8 + 0.376 * finalFinTex;
vec3 color = bgColor;
color = mix(color, finColor, allFins * finAlpha);
color = mix(color, bodyColor, bodyShape);
colour_out = vec4(color, 1.0);
}
Unknown by RM
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// worley noise
vec2 cellular(vec2 P)
{
float K = 0.142857142857;
float Ko = 0.428571428571;
vec2 Pi = floor(P);
vec2 Pf = fract(P);
float minDist1 = 8.0;
float minDist2 = 8.0;
for(int j = -1; j <= 1; j++)
for(int i = -1; i <= 1; i++) {
vec2 neighbor = vec2(float(i),float(j));
vec2 point = vec2(
fract(sin(dot(Pi + neighbor, vec2(127.1,311.7))) * 43758.5453),
fract(sin(dot(Pi + neighbor, vec2(269.5,183.3))) * 43758.5453)
);
vec2 diff = neighbor + point - Pf;
float dist = dot(diff, diff);
if (dist < minDist1) {
minDist2 = minDist1;
minDist1 = dist;
} else if (dist < minDist2) {
minDist2 = dist;
}
}
return vec2(minDist1, minDist2);
}
// noise1
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+1.0)*x);
}
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 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod289(i);
vec3 p = permute( permute(i.y + vec3(0.0, i1.y, 1.0))
+ i.x + vec3(0.0, i1.x, 1.0) );
float n_ = 0.142857142857;
vec3 ns = n_ * vec3(1.0, 2.0, 3.0) - vec3(0.0, 1.0, 2.0);
vec3 x_ = fract(p * ns.z) * 2.0 - 1.0;
vec3 y_ = abs(x_) - 0.5;
vec3 s_ = floor(x_ + 0.5);
vec3 gx = x_ - s_;
vec3 g0 = vec3(gx.x, y_.x, 0.0);
vec3 g1 = vec3(gx.y, y_.y, 0.0);
vec3 g2 = vec3(gx.z, y_.z, 0.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 gradDot = vec3(dot(g0, vec3(x0, 0.0)),
dot(g1, vec3(x12.xy, 0.0)),
dot(g2, vec3(x12.zw, 0.0)));
return 150.0 * dot(m, gradDot);
}
// wood fbm noise
float woodfbm(vec2 p) {
float f = 0.0;
float scale;
for(int i = 0; i < 5; i++) {
scale = pow(pow(2.0, 4.0/3.0), float(i));
f += snoise(p * scale) / scale;
}
return f;
}
// fbm noise for fish body
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
}
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);
float a = hash(i);
float b = hash(i + vec2(1.0, 0.0));
float c = hash(i + vec2(0.0, 1.0));
float d = hash(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) +
(c - a) * u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}
float fbm(vec2 st) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;
for(int i = 0; i < 3; i++) {
value += amplitude * noise(st * frequency);
frequency *= 2.0;
amplitude *= 0.5;
}
return value;
}
float fbmception(vec2 st, float t) {
float n1 = fbm(st + t * 0.05);
float n2 = fbm(st * 3.0 + n1 * 2.0 + t * 0.1);
return (n1 + n2 * 0.75) * 0.7;
}
// sdf for fish body
float ellipseSDF(vec2 p, vec2 center, vec2 radius) {
vec2 diff = (p - center) / radius;
return length(diff) - 1.0;
}
// sdf for tail
float triangleSDF(vec2 p, vec2 p0, vec2 p1, vec2 p2) {
vec2 e0 = p1 - p0;
vec2 e1 = p2 - p1;
vec2 e2 = p0 - p2;
vec2 v0 = p - p0;
vec2 v1 = p - p1;
vec2 v2 = p - p2;
vec2 n0 = vec2(e0.y, -e0.x);
vec2 n1 = vec2(e1.y, -e1.x);
vec2 n2 = vec2(e2.y, -e2.x);
float d0 = dot(n0, v0);
float d1 = dot(n1, v1);
float d2 = dot(n2, v2);
if (d0 >= 0.0 && d1 >= 0.0 && d2 >= 0.0) return -min(min(d0, d1), d2);
float dist0 = length(v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0));
float dist1 = length(v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0));
float dist2 = length(v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0));
return min(min(dist0, dist1), dist2);
}
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
vec2 st = (2.0 * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
// animate bg
vec2 move = vec2(u_time * -0.02, u_time * -0.04);
vec2 cellPos = (gl_FragCoord.xy + move * 150.0) / 100.0;
vec2 f = cellular(cellPos);
float nCell = f.x;
vec3 lightBlue = vec3(0.6, 0.8, 1.0);
vec3 darkBlue = vec3(0.764,0.904,0.970);
float brightness = 1.0 - smoothstep(0.35, 0.06, sqrt(nCell));
vec3 bgColor = mix(darkBlue, lightBlue, brightness);
float body = ellipseSDF(uv, vec2(0.58,0.500), vec2(0.3, 0.08));
float headCut = length(uv - vec2(0.65, 0.5)) - 0.26;
float bodyWithHead = max(body, headCut);
float bodyMask = smoothstep(0.15, -0.01, bodyWithHead);
// fbm noise pattern for fish body
float fbmNoise = fbmception(st * 8.0, u_time);
vec3 pink = vec3(1.000,0.767,0.738);
vec3 yellow = vec3(1.000,0.989,0.900);
vec3 white = vec3(1.0);
vec3 tint = mix(pink, yellow, fbmNoise);
vec3 bodyColor = mix(white, tint, 0.55 + fbmNoise * 0.3);
float topFin = ellipseSDF(uv, vec2(0.46, 0.6), vec2(0.15, 0.08));
float bottomFin = ellipseSDF(uv, vec2(0.54, 0.4), vec2(0.17, 0.15));
float tail = ellipseSDF(uv, vec2(0.28, 0.48), vec2(0.20, 0.23));
float finsTail = min(min(topFin, bottomFin), tail);
float finsTailMask = smoothstep(0.1, -0.01, finsTail);
// wood fbm noise
vec2 ringCenter = vec2(-0.010,0.000);
float nWood = woodfbm(st + u_time * 0.045);
float radiusFromCenter = length(st - ringCenter) * 150.0;
float woodRings = sin(radiusFromCenter + 12.0 * nWood);
woodRings = smoothstep(0.4, 0.2, woodRings);
vec3 pinkPurple = vec3(0.975,0.857,0.848);
vec3 whiteColor = vec3(1.0);
vec3 finsTailColor = pinkPurple * (1.0 - woodRings) + white * woodRings;
vec3 fishColor = mix(finsTailColor, bodyColor, bodyMask);
float fishShape = min(bodyWithHead, finsTail);
float mask = smoothstep(0.1, 0.0, fishShape);
vec3 color = mix(bgColor, fishColor, mask);
// eye
vec2 eyePos = vec2(0.82, 0.52);
float eyeRadius = 0.02;
float distToEye = distance(uv, eyePos);
float eyeMask = smoothstep(eyeRadius, eyeRadius - 0.02, distToEye);
color = mix(color, vec3(0.255,0.154,0.076), eyeMask * mask);
colour_out = vec4(color, 1.0);
}
Unknown by nn
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
float sdBody(vec2 p) {
p *= rotate2d(0.1);
float taper = smoothstep(-0.6, 0.6, p.x);
return length(vec2(p.x * 0.5 + 0.1, p.y / (0.45 + 0.25*taper))) - 0.25;
}
float sdTail(vec2 p) {
vec2 q = p - vec2(-0.25, 0.0);
q *= rotate2d(0.1);
float waveY = sin(q.y * 6.0 - u_time * 3.0) * 0.05;
float waveX = cos(q.y * 5.0 - u_time * 2.0) * 0.02;
q.x -= waveY; q.y -= waveX;
float spread = 1.0 - q.x * 0.4;
float d = length(vec2(q.x * 0.6, q.y * spread)) - 0.5;
float dClip = max(-(q.x + 0.25), q.x - 0.9);
d = max(d, dClip);
d += sin(q.y * 20.0) * 0.005;
return d;
}
float getFinPattern(vec2 p) {
vec2 q = p - vec2(-0.25, 0.0);
q *= rotate2d(0.1);
float angle = atan(q.y, q.x);
float rays = abs(sin(angle * 40.0 + sin(q.x * 10.0)));
return smoothstep(0.0, 0.8, rays);
}
void main() {
vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / min(u_resolution.x, u_resolution.y);
st.x *= -1.0;
vec3 bgColor = vec3(0.0, 0.1, 0.15);
vec3 finalColor = bgColor;
vec3 commonRed = vec3(0.8, 0.05, 0.1);
vec3 headWhite = vec3(0.95, 0.92, 0.92);
vec3 bodyBlue = vec3(0.05, 0.2, 0.6);
vec3 finTipBlue = vec3(0.0, 0.3, 0.8);
float dTail = sdTail(st);
vec3 tailCol = vec3(0.0);
float tFinHorizontal = smoothstep(-0.35, -0.05, st.x);
tailCol = mix(commonRed, finTipBlue, tFinHorizontal);
float pattern = getFinPattern(st);
tailCol += pattern * 0.1;
tailCol += vec3(0.0, 0.2, 0.6) * tFinHorizontal * 0.4;
float tailAlpha = 1.0 - smoothstep(-0.01, 0.01, dTail);
finalColor = mix(finalColor, tailCol, tailAlpha);
float dBody = sdBody(st);
vec3 bodyCol = vec3(0.0);
float tHead = smoothstep(0.3, 0.6, st.x);
float tBody = smoothstep(-0.05, -0.35, st.x);
bodyCol = mix(bodyBlue, commonRed, tBody);
bodyCol = mix(bodyCol, headWhite, tHead);
bodyCol += (sin(st.x * 60.0)*sin(st.y * 60.0)) * 0.03;
float light = smoothstep(-0.5, 0.5, st.y + 0.2);
bodyCol *= (0.6 + 0.4 * light);
float highlight = smoothstep(0.95, 1.0, sin(st.y * 20.0 - st.x * 5.0 + u_time));
bodyCol += highlight * 0.1;
float bodyAlpha = 1.0 - smoothstep(-0.01, 0.01, dBody);
finalColor = mix(finalColor, bodyCol, bodyAlpha);
colour_out = vec4(finalColor, 1.0);
}
Unknown by MT
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// ノイズ
float hash(vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); }
float noise(vec2 x) {
vec2 i = floor(x); vec2 f = fract(x);
float a = hash(i); float b = hash(i + vec2(1.0, 0.0));
float c = hash(i + vec2(0.0, 1.0)); float d = hash(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}
float fbm(vec2 x) {
float v = 0.0; float a = 0.5; mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50));
for (int i = 0; i < 4; ++i) { v += a * noise(x); x = rot * x * 2.0; a *= 0.5; }
return v;
}
mat2 rotate2d(float angle){ return mat2(cos(angle),-sin(angle), sin(angle),cos(angle)); }
//SDF関数
// 紡錘形
float sdVesica(vec2 p, float r, float d) {
p = abs(p);
float b = sqrt(r*r-d*d);
if ((p.y-b)*d > p.x*b) {
return length(p - vec2(0.0, b));
} else {
return length(p - vec2(-d, 0.0)) - r;
}
}
// 楕円
float sdEllipse(vec2 p, vec2 r) {
float k0 = length(p/r); float k1 = length(p/(r*r)); return k0*(k0-1.0)/k1;
}
// 鱗パターン生成
float scalePattern(vec2 p) {
p.x -= p.y * p.y * 0.8;
vec2 grid = fract(p * vec2(25.0, 18.0)) - 0.5;
return smoothstep(0.4, 0.15, length(grid));
}
void main() {
vec2 st = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;
float t = u_time * 0.5;
st.x += 0.1; // 位置調整
// 流線型
vec2 bodyPos = st;
bodyPos *= rotate2d(0.1);
// 紡錘形 SDF
float bodyDist = sdVesica(bodyPos - vec2(-0.15, 0.0), 0.55, 0.22);
float bodyMask = 1.0 - smoothstep(0.0, 0.015, bodyDist);
// 口元の微調整
float mouthMap = smoothstep(0.3, 0.4, bodyPos.x) * smoothstep(0.1, 0.0, abs(bodyPos.y));
bodyMask *= (1.0 - mouthMap * 0.5);
//ヒレの定義
float combinedFinMask = 0.0;
vec2 wavePos = st + vec2(t*0.3, 0.0);
float globalWave = fbm(wavePos*2.0);
//尾びれ
vec2 tailCenter = vec2(0.3, 0.0);
vec2 tailPos = st - tailCenter;
float tailA = atan(tailPos.y, tailPos.x);
float tailLen = length(tailPos);
float tailShape = smoothstep(1.0, 0.0, abs(tailA)) * smoothstep(0.0, 0.8, tailPos.x);
float currentTailLen = 0.6 + globalWave*0.2 + noise(tailPos*8.0)*0.05;
float tailMask = tailShape * (1.0 - smoothstep(currentTailLen, currentTailLen+0.05, tailLen));
combinedFinMask = max(combinedFinMask, tailMask);
//背びれ
vec2 dorsalPos = st - vec2(0.0, 0.15);
dorsalPos *= rotate2d(-0.6);
float dorsalShape = smoothstep(0.0, 0.4, dorsalPos.x) * smoothstep(0.4, 0.0, abs(dorsalPos.y));
float dorsalMask = dorsalShape * smoothstep(0.5 + globalWave*0.2, 0.0, dorsalPos.x);
combinedFinMask = max(combinedFinMask, dorsalMask);
//尻びれ
vec2 analPos = st - vec2(0.1, -0.15);
analPos *= rotate2d(0.3);
float analShape = smoothstep(-0.1, 0.6, analPos.x) * smoothstep(0.5, 0.0, abs(analPos.y + analPos.x*0.3));
float analMask = analShape * smoothstep(0.7 + globalWave*0.3, 0.0, analPos.x);
combinedFinMask = max(combinedFinMask, analMask);
//腹びれ
vec2 pelvicPos = st - vec2(-0.2, -0.1);
pelvicPos *= rotate2d(0.8);
float pelvicMask = (1.0-smoothstep(0.02, 0.05, abs(pelvicPos.y))) * smoothstep(0.0, 0.4, pelvicPos.x) * smoothstep(0.5, 0.4, pelvicPos.x);
combinedFinMask = max(combinedFinMask, pelvicMask);
combinedFinMask *= smoothstep(-0.05, 0.1, bodyDist);
//カラーリングと質
vec3 bgColor = vec3(0.05, 0.06, 0.08);
// ヒレの色
vec3 finColorRed = vec3(0.8, 0.05, 0.1);
vec3 finColorDark = vec3(0.2, 0.0, 0.05);
float rayAngle = atan(st.y, st.x - 0.5);
float rays = sin(rayAngle * 150.0 + fbm(st*10.0)*5.0);
rays = smoothstep(0.2, 0.8, rays);
float finGrad = smoothstep(-0.2, 0.6, st.x);
vec3 finFill = mix(finColorDark, finColorRed, finGrad);
finFill += vec3(1.0, 0.5, 0.3) * rays * 0.5 * finGrad;
// 体の色
vec3 bodyColorBlue = vec3(0.05, 0.3, 0.9);
vec3 bodyColorDark = vec3(0.02, 0.05, 0.2);
float scales = scalePattern(bodyPos * 1.5);
float lighting = smoothstep(0.5, -0.5, bodyPos.y - bodyPos.x*0.3);
vec3 bodyFill = mix(bodyColorDark, bodyColorBlue, lighting);
bodyFill += vec3(0.2, 0.6, 1.0) * scales * lighting;
// 目
vec2 eyePos = bodyPos - vec2(-0.35, 0.03);
float eyeMask = 1.0 - smoothstep(0.03, 0.035, length(eyePos));
float pupilMask = 1.0 - smoothstep(0.012, 0.015, length(eyePos));
vec3 eyeColor = mix(vec3(0.9, 0.7, 0.1), vec3(0.0), pupilMask);
eyeColor += smoothstep(0.01, 0.005, length(eyePos+vec2(-0.005,0.005)));
vec3 color = bgColor;
color = mix(color, finFill, combinedFinMask);
color = mix(color, bodyFill, bodyMask);
color = mix(color, eyeColor, eyeMask*bodyMask);
colour_out = vec4(color, 1.0);
}
Unknown by Earl
uniform vec2 u_resolution;
uniform float u_time;
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
// FBM: fractal brownian motion
float fbm(vec3 p) {
float f = 0.0;
f += 0.5000 * snoise(p); p *= 2.01;
f += 0.2500 * snoise(p); p *= 2.02;
f += 0.1250 * snoise(p); p *= 2.03;
f += 0.0625 * snoise(p);
return f;
}
float ridge(float h) {
h = abs(h);
return 1.0 - h;
}
// Turbulence noise
float turbulence(vec3 p) {
float t = 0.0;
t += abs(snoise(p));
t += abs(snoise(p * 2.0));
t += abs(snoise(p * 4.0));
t += abs(snoise(p * 8.0));
return t;
}
float circleMask(vec2 p, float r, float blur) {
float d = length(p);
return 1.0 - smoothstep(r - blur, r + blur, d);
}
float ellipseMask(vec2 p, vec2 r, float blur) {
vec2 q = p / r;
float d = length(q);
return 1.0 - smoothstep(1.0 - blur, 1.0 + blur, d);
}
vec3 bettaDesign(vec2 st) {
vec2 bodyP = st - vec2(0.63, 0.50);
float body = ellipseMask(bodyP, vec2(0.33, 0.16), 0.015);
float sway = 0.03 * sin(u_time * 1.2);
vec2 tailCenter = vec2(0.42 + sway, 0.50);
vec2 tailP = st - tailCenter;
float angle = atan(tailP.y, tailP.x);
float radius = length(tailP);
float baseR = 0.45;
float wave1 = sin(angle * 9.0 + u_time * 2.0);
float wave2 = sin(angle * 21.0 + u_time * 3.3);
float wave3 = sin(angle * 37.0 - radius * 12.0 + u_time * 1.7);
float waves = 0.12 * wave1 + 0.10 * wave2 + 0.07 * wave3;
float tailR = baseR + waves;
float tail = 1.0 - smoothstep(tailR - 0.008, tailR + 0.008, radius);
float fishMask = max(tail, body);
float tNoise =
fbm(vec3(tailP * 12.0, u_time * 0.2)) * 0.65 +
ridge(snoise(vec3(tailP * 6.0, u_time * 0.3))) * 0.35;
float dir = abs(sin(angle * 10.0));
float radialMask = smoothstep(0.1, 0.38, radius);
float tailStripe = mix(1.0,
1.0 + tNoise * dir,
radialMask);
float xGrad = smoothstep(0.30, 0.95, st.x);
vec3 baseRed = mix(vec3(1.0, 0.45, 0.25),
vec3(0.7, 0.05, 0.02),
xGrad);
vec3 tailColor = baseRed * tailStripe;
vec3 fishColor = tailColor;
float scaleBand = body * smoothstep(0.52, 0.70, st.x);
float grid = step(0.5,
fract(st.x * 32.0) +
fract(st.y * 24.0));
vec3 scaleColor = mix(vec3(0.95, 0.6, 0.45),
vec3(0.35, 0.55, 1.0),
grid);
fishColor = mix(fishColor, scaleColor, scaleBand * 0.8);
float shade = 0.4 + 0.6 * st.y;
fishColor *= shade;
vec2 eyeP = st - vec2(0.84, 0.55);
float eye = circleMask(eyeP, 0.018, 0.005);
vec3 eyeCol = vec3(0.02, 0.02, 0.05);
fishColor = mix(fishColor, eyeCol, eye);
vec3 finalColor = mix(vec3(0.0), fishColor, fishMask);
return finalColor;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec3 col = bettaDesign(st);
colour_out = vec4(col, 1.0);
}
Betta splendens by bbbleu
uniform vec2 u_resolution;
uniform float u_time;
// === noise2D from stegu ===
vec4 permute(vec4 x){
return mod(((x*34.0)+1.0)*x, 289.0);
}
vec2 fade(vec2 t){
return t*t*t*(t*(t*6.0-15.0)+10.0);
}
float noise(vec2 P){
vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
Pi = mod(Pi, 289.0);
vec4 ix = Pi.xzxz;
vec4 iy = Pi.yyww;
vec4 fx = Pf.xzxz;
vec4 fy = Pf.yyww;
vec4 i = permute(permute(ix) + iy);
vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0;
vec4 gy = abs(gx) - 0.5;
vec4 tx = floor(gx + 0.5);
gx = gx - tx;
vec2 g00 = vec2(gx.x,gy.x);
vec2 g10 = vec2(gx.y,gy.y);
vec2 g01 = vec2(gx.z,gy.z);
vec2 g11 = vec2(gx.w,gy.w);
vec4 norm = 1.7928429 - 0.8537347 *
vec4(dot(g00,g00), dot(g10,g10),
dot(g01,g01), dot(g11,g11));
g00 *= norm.x;
g10 *= norm.y;
g01 *= norm.z;
g11 *= norm.w;
float n00 = dot(g00, vec2(fx.x,fy.x));
float n10 = dot(g10, vec2(fx.y,fy.y));
float n01 = dot(g01, vec2(fx.z,fy.x));
float n11 = dot(g11, vec2(fx.w,fy.w));
vec2 fade_xy = fade(Pf.xy);
vec2 n_x = mix(vec2(n00,n01), vec2(n10,n11), fade_xy.x);
return mix(n_x.x, n_x.y, fade_xy.y);
}
// Signed distance shapes
float fishSideFin(vec2 p) {
p -= vec2(0.020,-0.120);
float outer = length(p / vec2(0.38, 0.58)) - 0.85;
float indent = length((p - vec2(-0.010,0.090)) / vec2(0.32, 0.50)) - 0.188;
float lobe = length((p - vec2(0.010,0.030)) / vec2(0.42, 0.62)) - 0.126;
return max(outer, min(indent, lobe));
}
float fishBottomFin(vec2 p) {
p -= vec2(-0.020,-0.060);
p.x /= 0.646;
p.y /= 0.328;
float a = atan(p.y, p.x);
float ripple = 0.015 * sin(a * 28.0)
+ 0.008 * sin(a * 52.0);
float upCut = p.y + ripple;
float feather = abs(p.x) - (0.272 + 0.068 * -p.y);
float arc = length(p + vec2(0.180,0.320)) - (0.498 + ripple);
return max(max(upCut, feather), arc);
}
float fishBody(vec2 p) {
float taper = mix(1.0, 0.4, smoothstep(0.4, 0.9, p.x));
vec2 r = vec2(0.22 * taper, 0.10);
float body = length(p / r) - 1.0;
float nose = (p.x - 0.78) * 4.0;
return max(body, nose);
}
float fishTail(vec2 p) {
p -= vec2(-0.200, 0.000);
float a = atan(p.y, p.x);
float ripple = 0.006 * sin(a * 32.0)
+ 0.003 * sin(a * 64.0);
float circle = length(p) - (0.268 + ripple);
float halfMask = p.x;
return max(circle, halfMask);
}
float fishTailInner(vec2 p) {
p -= vec2(-0.200, 0.000);
float a = atan(p.y, p.x);
float ripple = 0.005 * sin(a * 32.0)
+ 0.002 * sin(a * 64.0);
float circle = length(p) - (0.180 + ripple);
float halfMask = p.x;
return max(circle, halfMask);
}
float fishFin(vec2 p) {
p -= vec2(-0.060, 0.060);
float a = radians(20.0);
p = mat2(cos(a),-sin(a), sin(a),cos(a)) * p;
float arc = length(p / vec2(-0.370, -0.980)) - 0.320;
float up = -p.y;
float baseTaper = abs(p.x) - (0.05 + 0.35 * p.y);
float roundTop = length(p - vec2(0.0, 0.15)) - 0.25;
return max(max(arc, up), max(baseTaper, roundTop));
}
float fishEye(vec2 p) {
p -= vec2(0.140,0.010);
return length(p) - 0.030;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec2 p = st - vec2(0.55, 0.5);
// Underwater background
vec3 waterDeep = vec3(0.0, 0.25, 0.55);
vec3 waterShallow = vec3(0.10, 0.52, 0.85);
vec3 base = mix(waterDeep, waterShallow, st.y);
float ripple = noise(st * 6.0 + u_time * 0.15);
ripple += 0.5 * noise(st * 12.0 - u_time * 0.25);
ripple = smoothstep(0.4, 1.0, ripple);
base += ripple * 0.10;
// Aquatic plants
vec3 weedColor = vec3(0.07, 0.45, 0.22);
float plantMaskTotal = 0.0;
for(int i = 0; i < 7; i++){
float anchorX = fract(st.x + float(i) * 0.21);
float sway = sin(u_time * 0.7 + anchorX * 10.0) * 0.03;
float xOff = st.x - anchorX - sway;
float h = 0.55 + 0.1 * sin(u_time + float(i));
float width = 0.04 + 0.02 * sin(st.y * 30.0 + u_time * 0.4);
float leaf = smoothstep(width, 0.0, abs(xOff));
leaf *= smoothstep(0.0, h, st.y);
float branch = smoothstep(0.28, 0.29, st.y + 0.05 * sin(st.y * 40.0 + float(i)*1.7)) * 0.5;
float weedMask = leaf * (0.8 + branch);
plantMaskTotal = max(plantMaskTotal, weedMask);
}
base = mix(base, weedColor, plantMaskTotal);
base = mix(vec3(0.02,0.10,0.18), base, smoothstep(0.05, 0.5, st.y));
// Distance fields
float dBody = fishBody(p);
float dFin = fishFin(p);
float dBottom = fishBottomFin(p);
float dSide = fishSideFin(p);
float dTailOuter = fishTail(p);
float dTailInner = fishTailInner(p);
float dEye = fishEye(p);
float dMain = min(min(min(dBody, dFin), dBottom), dSide);
float fishMask = 1.0 - step(0.0, min(dMain, dTailInner));
float tailMaskOuter = 1.0 - step(0.0, dTailOuter);
float tailMaskInner = 1.0 - step(0.0, dTailInner);
float eyeMask = 1.0 - step(0.0, dEye);
float finMask = 1.0 - step(0.0, dFin);
float bottomMask = 1.0 - step(0.0, dBottom);
float sideMask = 1.0 - step(0.0, dSide);
vec3 fishCol = vec3(1.0, 0.05, 0.05);
vec3 whiteCol = vec3(1.0);
vec3 blackCol = vec3(0.0);
base = mix(base, fishCol, fishMask);
base = mix(base, whiteCol, tailMaskOuter * (1.0 - tailMaskInner));
float a = atan(p.y, p.x);
float rippleMask = 0.015 * sin(a * 28.0)
+ 0.008 * sin(a * 52.0);
float bottomWhiteMask = bottomMask * step(p.y + rippleMask, -0.188);
base = mix(base, whiteCol, bottomWhiteMask);
vec2 pf = p - vec2(-0.060, 0.060);
float ang = radians(20.0);
pf = mat2(cos(ang),-sin(ang), sin(ang),cos(ang)) * pf;
float af = atan(pf.y, pf.x);
float topRipple = 0.025 * sin(af * 21.168)
+ 0.012 * sin(af * 35.720);
float finUpper = step(0.192, pf.y + topRipple);
base = mix(base, whiteCol, finMask * finUpper);
base = mix(base, whiteCol, sideMask);
float bodyMask = 1.0 - step(0.0, dBody);
if (bodyMask > 0.0 && sideMask == 0.0) {
float n1 = noise(p * 65.0 + u_time * 0.4);
float n2 = noise(p * 130.0 + u_time * 0.6);
float ns = (n1 * 0.6 + n2 * 0.4);
ns = clamp(ns * 2.5, -1.0, 1.0);
base.rgb += ns * 0.28;
}
{
float finRayMask = finMask + bottomMask + sideMask + tailMaskOuter;
finRayMask = clamp(finRayMask, 0.0, 1.0);
float angFin = atan(p.y, p.x);
float rays = sin(angFin * 80.0 + u_time * 0.2);
float distFade = smoothstep(0.03, 0.22, length(p));
base.rgb += rays * 0.09 * distFade * finRayMask;
}
base = mix(base, blackCol, eyeMask * fishMask);
colour_out = vec4(base, 1.0);
}
Siamese Fighting Fish by lls
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// random generator
float hash(vec2 p) {
return fract(sin( dot(p, vec2(99.0, 358.0))) * 500.0);
}
//used as noise
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float a = hash(i );
float b = hash(i + vec2(1.0, 0.0 ));
float c = hash(i + vec2(0.0, 1.0 ));
float d = hash(i + vec2(1.0, 1.0 ));
vec2 u = f * f *(3.0 - 2.0 * f);
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float sdCircle(vec2 p, vec2 c, float r) {
return length(p - c) - r;
}
float sdEllipse(vec2 p, vec2 c, vec2 r) {
vec2 q = (p - c) / r;
return length(q) - 1.0;
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
//aspect ratio
float aspect = u_resolution.x / u_resolution.y;
st.x *= aspect;
//center the fish(added laterr)
float fishCenterCurrent = 0.45;
float fishCenterTarget = 0.5 * aspect;
float fishOffsetX = fishCenterTarget - fishCenterCurrent;
vec2 bodyCenter =vec2(0.45 + fishOffsetX, 0.5);
vec2 headCenter =vec2(0.63 + fishOffsetX, 0.5);
vec2 tailCenter =vec2(0.25 + fishOffsetX, 0.5);
vec2 dorsalCenter =vec2(0.45 + fishOffsetX, 0.62);
vec2 ventralCenter=vec2(0.45 + fishOffsetX, 0.38);
vec2 finRoot =vec2(0.38 + fishOffsetX, 0.5);
vec2 eyeCenter =vec2(0.64 + fishOffsetX, 0.515);
vec2 eyeHighlight =vec2(0.647 + fishOffsetX, 0.522);
//blue background
float waterDepth = st.y;
vec3 bgTop = vec3(0.10, 0.55, 0.95); //light sea blue
vec3 bgBottom = vec3(0.00, 0.05, 0.25); //deep ocean blue
float shaft = noise(vec2(st.x * 4.0, st.y * 3.0 + u_time * 0.1));
shaft = smoothstep(0.7, 1.0, shaft );
vec3 background = mix(bgBottom, bgTop, waterDepth);
background += shaft * vec3(0.10, 0.25, 0.45) * 0.4;
//fish body shape
float body = sdEllipse(st, bodyCenter, vec2(0.23, 0.12));
float head = sdCircle(st, headCenter, 0.06);
float tailWarp = 0.04 * sin(st.y * 10.0 + u_time * 2.0);
float tail = sdEllipse(st + vec2(tailWarp, 0.0), tailCenter, vec2(0.24, 0.18));
float dorsal = sdEllipse(st, dorsalCenter, vec2(0.23, 0.16 ));
float ventral= sdEllipse(st, ventralCenter, vec2(0.23, 0.18));
float bodyOnly= min(body, head);
float finsOnly= min(min(tail,dorsal), ventral);
float fishDist= min(bodyOnly, finsOnly);
float fishMask= smoothstep( 0.02, 0.0, fishDist);
float bodyMask= smoothstep( 0.015, 0.0, bodyOnly);
float finsMask= smoothstep( 0.02, 0.0, finsOnly) * (1.0 - bodyMask);
//local coords
vec2 local = st - bodyCenter;
float r = length(local);
//0= tail side, 1= head side along body
float headToTail = clamp((local.x + 0.22) / 0.44,0.0, 1.0);
//0= belly, 1= dorsal line
float dorsalFactor = clamp((local.y + 0.12) / 0.24,0.0,1.0);
//base gradient: dark blue head/dorsal, red tail/belly
vec3 deepBlue =vec3(0.02, 0.12, 0.60);
vec3 pureRed =vec3(0.95, 0.15, 0.15);
//more blue near head, more red near tail
vec3 baseBody = mix(pureRed, deepBlue, headToTail);
// shift toward red at lower part, blue at upper part
baseBody = mix(baseBody, pureRed, (1.0 - dorsalFactor) * 0.5);
baseBody = mix(baseBody, deepBlue, dorsalFactor * 0.6);
// narrow bright lateral line along body
float lateral = smoothstep(0.02, 0.0, abs(local.y) - 0.01);
lateral *= smoothstep(-0.2, 0.15, local.x); // mostly middle of body
// vetical liness
float verticalBands = 0.5 + 0.5 * cos(local.x * 28.0 + noise(local * 5.0) * 3.0);
verticalBands = smoothstep(0.5, 0.95, verticalBands);
//texture
float longitudinal = 0.5 + 0.5 * sin(local.y * 30.0 + u_time * 1.2);
float bands = mix(verticalBands, longitudinal, 0.35);
// irregular pattern
float nBody = noise(local * 10.0 + vec2(u_time * 0.3, 0.0));
float marble = smoothstep(0.4, 0.9, nBody);
//micro pattern added
float scaleGrid = sin(local.x * 38.0) * sin(local.y * 32.0);
float scales = smoothstep(0.65, 0.95, 0.5 + 0.5 * scaleGrid);
// time-based shimmer along body
float shimmer = 0.5 + 0.5 * sin(r * 16.0 + u_time * 3.0 + local.x * 5.0);
shimmer *= smoothstep(0.01, 0.18, r);
// body color:
vec3 bodyColor = baseBody;
// deepen red/blue contrast via bands and marble
bodyColor = mix(bodyColor, pureRed, bands * 0.3);
bodyColor = mix(bodyColor, deepBlue, (1.0 - bands) * 0.25 * headToTail);
// lateral line highlight
bodyColor += lateral * vec3(0.7, 0.8, 1.0) *0.5;
bodyColor += scales * vec3(0.5, 0.6, 1.0) *0.45;
bodyColor += shimmer * vec3(0.3, 0.3, 0.7) *0.45;
// darken head slightly (many bettas have darker mask)
float headMask = smoothstep(0.05, -0.06, sdCircle(st, headCenter, 0.08));
bodyColor = mix(bodyColor * 0.6, bodyColor, 1.0 - headMask);
//fins
vec2 finLocal = st - finRoot;
float finR = length(finLocal);
//rays radial
float angle = atan(finLocal.y, finLocal.x);
float rays = 0.5 + 0.5 * cos(angle * 16.0 + finR * 14.0 - u_time * 1.5);
float finWaves = 0.5 + 0.5 * sin(finR * 20.0 - u_time * 2.2);
float nFins = noise(finLocal * 8.0 + vec2(u_time * 0.4, -u_time * 0.25));
float finPattern = mix(rays, finWaves, 0.5);
finPattern = mix(finPattern, nFins, 0.35);
finPattern = smoothstep(0.25, 0.95, finPattern);
vec3 finRed = vec3(0.97, 0.20, 0.16);
vec3 finDarkBlue = vec3(0.05, 0.25, 0.80); // strong blue
vec3 finColor = mix(finRed, finDarkBlue, finPattern * 0.6);
float finEdge = smoothstep(0.03, 0.15, abs(fishDist));
finColor += finEdge * 0.22;
//eye
float eye = sdCircle(st, eyeCenter, 0.015 );
float eyeMask = smoothstep(0.01, 0.0, eye);
vec3 eyeColor = vec3( 0.02, 0.02, 0.02);
float highlight = smoothstep(0.008, 0.0, sdCircle(st, eyeHighlight, 0.006));
eyeColor += highlight * vec3(0.9, 0.9, 0.9);
// final colors
vec3 color = background;
vec3 fishColor =bodyColor * bodyMask + finColor * finsMask;
color = mix(color, fishColor, fishMask);
color = mix(color, eyeColor, eyeMask * bodyMask);
vec2 cent = st -vec2(0.5* aspect, 0.5);
float vign = smoothstep(0.9, 0.2, length(cent));
color *= vign;
colour_out= vec4(color,1.0);
}
red and blue betta by anonymous
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// Your environment provides: vec4 colour_out;
// ===== Helpers =====
mat2 rot(float a){
float c = cos(a), s = sin(a);
return mat2(c,-s, s,c);
}
// Smooth-min for blending SDFs
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);
}
// ---- Basic shapes ----
// Body ellipse
float sdEllipse(vec2 p, vec2 r){
vec2 k = abs(p);
return (length(k / r) - 1.0) * min(r.x, r.y);
}
// Fin triangle
float sdTri(vec2 p, float h){
p.x = abs(p.x);
vec2 a = vec2(0.0,-h);
vec2 b = vec2(-h,h);
vec2 ba = b-a;
float t = clamp(dot(p-a, ba)/dot(ba,ba), 0.0, 1.0);
vec2 proj = a + t*ba;
return length(p - proj) - 0.05;
}
// Tail fan
float sdTail(vec2 p){
p.x += 0.55;
float r = length(p);
float ang = abs(atan(p.y, p.x));
float fan = radians(70.0);
float cutoff = smoothstep(fan, fan - 0.2, ang);
return r - 0.8 + cutoff*0.1;
}
// ===== Fish shape =====
float mapFish(vec2 p){
vec2 q = p;
// swim motion
q.x += sin(u_time * 2.0 + q.y * 4.0) * 0.04;
float body = sdEllipse((q - vec2(0.05,0.0)) * rot(0.1), vec2(0.55, 0.22));
float tail = sdTail(q);
float topFin = sdTri((q + vec2(-0.1, -0.25))*vec2(1.4,1.0), 0.5);
float botFin = sdTri((q + vec2(-0.1, 0.25))*vec2(1.4,1.0), 0.5);
float fish = body;
fish = smin(fish, tail, 0.25);
fish = smin(fish, topFin, 0.15);
fish = smin(fish, botFin, 0.15);
return fish; // negative = inside fish
}
// ===== Colors =====
// Light blue body + dark edge
vec3 fishColor(vec2 p, float dist){
// Light blue base
vec3 base = vec3(0.3, 0.7, 1.0);
// Dist is negative inside, fade to black near edge
float edge = smoothstep(0.0, 0.08, abs(dist));
// Darken toward edges
vec3 shaded = mix(base, vec3(0.0), edge * 0.8);
// Slight head darkening
float head = smoothstep(-0.5, -0.25, p.x);
shaded *= mix(0.5, 1.0, head);
return shaded;
}
// Water background
vec3 background(vec2 uv){
vec3 top = vec3(0.95, 0.98, 1.0);
vec3 bottom = vec3(0.85, 0.92, 0.98);
return mix(bottom, top, uv.y);
}
void main(){
vec2 uv = gl_FragCoord.xy / u_resolution.xy;
float aspect = u_resolution.x / u_resolution.y;
// Normalized, centered
vec2 p = (gl_FragCoord.xy - 0.5*u_resolution.xy) / u_resolution.y;
p.x *= aspect;
p.y -= 0.05;
p *= 0.8; // fit in frame
float d = mapFish(p); // signed distance
vec3 col = background(uv);
// Inside mask (1 = inside fish)
float inside = 1.0 - smoothstep(0.0, 0.02, d);
// Blend fish into background
col = mix(col, fishColor(p, d), inside);
colour_out = vec4(col, 1.0);
}
unknown by anonymous
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
// 2D and 3D noise functions from https://github.com/stegu/webgl-noise
vec2 mod289(vec2 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec3 permute(vec3 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec2 v)
{
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0
// First corner
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1;
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
//i1.y = 1.0 - i1.x;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
// x0 = x0 - 0.0 + 0.0 * C.xx ;
// x1 = x0 - i1 + 1.0 * C.xx ;
// x2 = x0 - 1.0 + 2.0 * C.xx ;
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i); // Avoid truncation effects in permutation
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 ;
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
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;
// Normalise gradients implicitly by scaling m
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
// Compute final noise value at P
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);
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
// Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.0);
float mask = 0.0;
// Position of main body
vec2 bodyCenter = vec2(0.65, 0.5);
vec2 toBody = st - bodyCenter;
// Construct oval for main body
float bodyDist = length(toBody / vec2(2.0, 0.85));
float body = smoothstep(0.13, 0.12, bodyDist);
// Color and noise of main body
vec3 bodyColor = vec3(0.96, 0.8, 0.77);
float bodyNoise = snoise(st * 15.0 + u_time * 0.1) * 0.05;
bodyColor += bodyNoise;
// Add scale pattern using noise
float scales = snoise(st * 40.0) * 0.5 + 0.5;
scales = pow(scales, 3.0) * 0.15;
bodyColor -= scales * body;
vec2 eyePos = bodyCenter + vec2(0.19, 0.02); // Center of eye
float eyeOuter = smoothstep(0.025, 0.023, distance(st, eyePos)); // Outer circle of eye
float eyeInner = smoothstep(0.012, 0.010, distance(st, eyePos)); // Inner circle of eye
vec3 eyeSilver = vec3(0.85, 0.88, 0.90); // Outer color: silver
vec3 eyeBlack = vec3(0.0); // Inner color: black
vec3 eyeColor = mix(eyeSilver, eyeBlack, eyeInner);
// Position of jaw fin
vec2 jawFinCenter = eyePos + vec2(-0.05, -0.03);
vec2 toJawFin = st - jawFinCenter;
// Construct circular sector (-180 to -90 degrees) for jaw fin
float jawFinAngle = atan(toJawFin.y, toJawFin.x);
float jawFinDist = length(toJawFin);
float jawFin = smoothstep(0.12, 0.10, jawFinDist);
jawFin *= step(-3.14159, jawFinAngle) * step(jawFinAngle, -1.5708);
// Add ray texture to jaw fin
float jawFinRays = abs(sin(jawFinAngle * 10.0)) * 0.5 + 0.5;
jawFin *= jawFinRays;
// Color of jaw fin
vec3 jawFinColor = vec3(0.98, 0.92, 0.94); // Lighter pink-white color for fins
// Position of tail fin (large circular spread from left side of body)
vec2 tailCenter = bodyCenter - vec2(0.15, 0.0);
vec2 toTail = st - tailCenter;
// Construct flowing tail with multiple lobes
float tailAngle = atan(toTail.y, toTail.x);
float tailDist = length(toTail);
float tailNoise = snoise(vec3(tailAngle * 3.0, tailDist * 5.0, u_time * 0.1));
float tailRadius = 0.35 + tailNoise * 0.08;
// By default only show to the left of the eye position
float tailMask = step(toTail.x, eyePos.x - tailCenter.x);
// For upper half of tail, stop at a line tilted upper-right at 60 degrees
if (toTail.y > 0.0) {
// tan(60 degrees) = 1.732
tailMask = step(toTail.x - toTail.y / 1.732, 0.1);
}
float tail = smoothstep(tailRadius + 0.02, tailRadius - 0.05, tailDist) * tailMask;
// Add radial pattern to tail fin
float radialPattern = abs(sin(tailAngle * 12.0)) * 0.3 + 0.7;
tail *= radialPattern;
// Color and noise of tail fin
vec3 tailColor = vec3(0.98, 0.92, 0.94); // Lighter pink-white color for fins
float tailFlow = snoise(vec2(tailAngle * 2.0, tailDist * 8.0 - u_time * 0.1)); // Flowing pattern
tailColor += tailFlow * 0.1;
// Add ray texture to tail fin
float finRays = smoothstep(0.6, 0.8, abs(sin(tailAngle * 25.0 + tailDist * 10.0)));
tailColor -= finRays * 0.1 * tail;
// Combine all elements
color = mix(color, tailColor, tail);
color = mix(color, bodyColor, body);
color = mix(color, eyeColor, eyeOuter);
color = mix(color, jawFinColor, jawFin);
// Add subtle shimmer
float shimmer = snoise(st * 20.0 + u_time) * 0.03;
color += shimmer * (body + tail);
colour_out = vec4(color, 1.0);
}
Pink-White Betta by nakanokumin
// ===== NOISE FUNCTIONS =====
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 mod289(vec4 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}
vec4 permute(vec4 x) {
return mod289(((x*34.0)+10.0)*x);
}
vec4 taylorInvSqrt(vec4 r)
{
return 1.79284291400159 - 0.85373472095314 * r;
}
float snoise(vec3 v)
{
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ;
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
// First corner
vec3 i = floor(v + dot(v, C.yyy) );
vec3 x0 = v - i + dot(i, C.xxx) ;
// Other corners
vec3 g = step(x0.yzx, x0.xyz);
vec3 l = 1.0 - g;
vec3 i1 = min( g.xyz, l.zxy );
vec3 i2 = max( g.xyz, l.zxy );
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
vec3 x1 = x0 - i1 + C.xxx;
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
i = mod289(i);
vec4 p = permute( permute( permute(
i.z + vec4(0.0, i1.z, i2.z, 1.0 ))
+ i.y + vec4(0.0, i1.y, i2.y, 1.0 ))
+ i.x + vec4(0.0, i1.x, i2.x, 1.0 ));
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
float n_ = 0.142857142857; // 1.0/7.0
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
vec4 x_ = floor(j * ns.z);
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N)
vec4 x = x_ *ns.x + ns.yyyy;
vec4 y = y_ *ns.x + ns.yyyy;
vec4 h = 1.0 - abs(x) - abs(y);
vec4 b0 = vec4( x.xy, y.xy );
vec4 b1 = vec4( x.zw, y.zw );
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
vec4 s0 = floor(b0)*2.0 + 1.0;
vec4 s1 = floor(b1)*2.0 + 1.0;
vec4 sh = -step(h, vec4(0.0));
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ;
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ;
vec3 p0 = vec3(a0.xy,h.x);
vec3 p1 = vec3(a0.zw,h.y);
vec3 p2 = vec3(a1.xy,h.z);
vec3 p3 = vec3(a1.zw,h.w);
//Normalise gradients
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
p0 *= norm.x;
p1 *= norm.y;
p2 *= norm.z;
p3 *= norm.w;
// Mix final noise value
vec4 m = max(0.5 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0);
m = m * m;
return 105.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1),
dot(p2,x2), dot(p3,x3) ) );
}
// fractal brownian motion
float fbm(vec3 p) {
float value = 0.0;
float amplitude = 0.5;
for(int i = 0; i < 6; i++) {
value += amplitude * snoise(p);
p *= 2.1;
amplitude *= 0.5;
}
return value;
}
// ===== MAIN SHADER =====
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec2 center = vec2(0.5, 0.5);
//calculate the distance to the edge to put the red tail
float distFromCenter = length(st - center);
float edgeMask = smoothstep(0.2, 0.5, distFromCenter); // 边缘是1,中心是0
//to put the noise to mimic the movement and color changing
float noise1 = fbm(vec3(st * 2.5, u_time * 0.3)) * 0.5 + 0.5;
float noise2 = fbm(vec3(st * 4.0, u_time * 0.4)) * 0.5 + 0.5;
float noise3 = fbm(vec3(st * 6.0, u_time * 0.5)) * 0.5 + 0.5;
// the more detailed noise
float scales = snoise(vec3(st * 30.0, u_time * 0.2)) * 0.5 + 0.5;
// To define the basic blue color
vec3 deepColor = vec3(0.05, 0.03, 0.12); // dark purple
vec3 darkBlue = vec3(0.12, 0.10, 0.28); // dark blue
vec3 midBlue = vec3(0.20, 0.20, 0.45); // blue
vec3 brightBlue = vec3(0.30, 0.35, 0.60); // bright blue
// To define the basic red color
vec3 darkRed = vec3(0.25, 0.02, 0.04); // dark red
vec3 brightRed = vec3(0.75, 0.10, 0.15); // red
vec3 vividRed = vec3(0.95, 0.20, 0.25); // bright red
// achieve the transition of blue part
vec3 baseBlue = mix(deepColor, darkBlue, noise1);
baseBlue = mix(baseBlue, midBlue, noise2 * 0.6);
baseBlue = mix(baseBlue, brightBlue, noise3 * 0.3);
// add the detail scale
baseBlue += (scales - 0.5) * 0.08;
// achieve the transition of red part
vec3 redColor = mix(darkRed, brightRed, noise1 * 0.7 + 0.3);
redColor = mix(redColor, vividRed, noise2 * 0.5);
// to achieve the movement
float redNoise = fbm(vec3(st * 3.0, u_time * 0.35)) * 0.5 + 0.5;
float redEdge = edgeMask * smoothstep(0.3, 0.7, redNoise);
// mix blue and red to do the fish color
vec3 color = mix(baseBlue, redColor, redEdge * 0.8);
// basic of highlight
float gloss1 = pow(noise1, 3.0) * 0.15;
float gloss2 = pow(noise2, 4.0) * 0.12;
float gloss3 = pow(noise3, 5.0) * 0.10;
// blue gloss
vec3 blueGloss = vec3(0.3, 0.35, 0.5) * (gloss1 + gloss2);
// red gloss
vec3 redGloss = vec3(0.4, 0.15, 0.2) * gloss2;
color += mix(blueGloss, redGloss, redEdge);
color += vec3(gloss3);
// Iridescent effect
float iridescence = snoise(vec3(st * 15.0, u_time * 0.3)) * 0.05;
color += vec3(iridescence * 0.8, iridescence, iridescence * 1.2);
// breathing
float pulse = sin(u_time * 1.2) * 0.03 + 0.97;
color *= pulse;
colour_out = vec4(color, 1.0);
}
redtail by WANG
SHAN
uniform float u_time;
uniform vec2 u_resolution;
// =====================
// webgl-noise style helpers (2D simplex noise)
// =====================
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) {
return mod289((x * 34.0 + 1.0) * x);
}
// 2D simplex noise, roughly in [-1,1]
// based on Stefan Gustavson's webgl-noise implementation
float snoise(vec2 v) {
const vec4 C = vec4(
0.211324865405187, // (3.0 - sqrt(3.0)) / 6.0
0.366025403784439, // 0.5 * (sqrt(3.0) - 1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439 // 1.0 / 41.0
);
// First corner
vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
// Other corners
vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
// Permutations
i = mod289(i);
vec3 p = permute(
permute(i.y + vec3(0.0, i1.y, 1.0)) +
i.x + vec3(0.0, i1.x, 1.0)
);
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
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;
// Normalize gradients implicitly by scaling m
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
// Compute final noise value at P
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.y = a0.y * x12.x + h.y * x12.y;
g.z = a0.z * x12.z + h.z * x12.w;
return 130.0 * dot(m, g);
}
// =====================
// SDF helpers & fan shapes
// =====================
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
float sdEllipse(vec2 p, vec2 r) {
vec2 q = p / r;
return length(q) - 1.0;
}
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);
}
vec2 rotate2D(vec2 p, float a) {
float c = cos(a), s = sin(a);
return mat2(c, -s, s, c) * p;
}
// Generic fan shape (used for tail and fins)
// flipX = -1.0 for fan opening to the left, +1.0 for right
float fanShape(vec2 p, vec2 base, float flipX,
float maxAng, float maxR,
float time, float rippleAmp) {
vec2 q = p - base;
q.x *= flipX;
float ang = atan(q.y, q.x);
float r = length(q);
float dAngle = abs(ang) - maxAng;
float dRadius = r - maxR;
float d = max(dAngle, dRadius);
float edge = maxR - r;
float ruf = rippleAmp *
sin(ang * 4.0 + time * 1.2) *
smoothstep(0.0, -0.25, edge);
d += ruf;
return d;
}
void main() {
vec2 vUV = gl_FragCoord.xy / u_resolution;
float t = u_time;
// Normalized coords with aspect
vec2 uv = vUV - 0.5;
float aspect = u_resolution.x / u_resolution.y;
uv.x *= aspect;
// ===== Background gradient =====
float gy = uv.y * 0.5 + 0.5;
vec3 colTop = vec3(0.94, 0.97, 1.0);
vec3 colBottom = vec3(0.65, 0.72, 0.88);
vec3 col = mix(colBottom, colTop, gy);
// ===== Ray-marched blue water with noise =====
vec2 scr = (vUV - 0.5) * 2.0;
scr.x *= aspect;
vec3 ro = vec3(0.0, 0.0, 2.0);
vec3 rd = normalize(vec3(scr, -1.5));
float s = 0.0;
float maxDist = 4.0;
float radius = 1.8;
vec3 waterAccum = vec3(0.0);
float waterAlpha = 0.0;
for (int i = 0; i < 72; ++i) {
if (s > maxDist || waterAlpha > 0.99) break;
vec3 pos = ro + rd * s;
float r = length(pos);
if (r < radius) {
float vert = exp(-1.2 * abs(pos.y));
float wave1 = sin(pos.x * 5.0 + t * 0.7);
float wave2 = cos(pos.z * 4.0 - t * 0.5);
float wave = 0.5 * (wave1 + wave2);
// simplex noise over xz plane for extra turbulence
float n = snoise(pos.xz * 1.2 + vec2(t * 0.15, -t * 0.1));
float baseDensity = max(wave, 0.0) * 0.06 * vert;
float density = baseDensity * (0.8 + 0.4 * n); // noise-modulated
vec3 sampleCol = vec3(0.20, 0.40, 0.85);
waterAccum += (1.0 - waterAlpha) * density * sampleCol;
waterAlpha += (1.0 - waterAlpha) * density;
}
s += 0.06;
}
vec3 baseWater = vec3(0.30, 0.50, 0.90);
float wMix = clamp(waterAlpha * 1.8, 0.0, 1.0);
col = mix(col, baseWater + waterAccum, wMix);
// ===== Betta coordinates =====
vec2 p = uv;
p.y += 0.02 * sin(t * 0.7);
p.x += 0.02 * sin(t * 0.4);
// ===== Body & head =====
float dBody = sdEllipse(p - vec2(0.15, 0.0), vec2(0.25, 0.12));
float dHead = sdCircle (p - vec2(0.37, 0.02), 0.07);
float dCore = smin(dBody, dHead, 0.08);
float bodyMask = smoothstep(0.03, 0.0, dCore);
// ===== Tail fan (left) =====
float tailMaxR = 0.55;
float tailMaxAng = 1.05;
vec2 tailBase = vec2(0.00, 0.0);
float dTail = fanShape(p, tailBase, -1.0,
tailMaxAng, tailMaxR,
t, 0.03);
float tailMask = smoothstep(0.03, 0.0, dTail);
// ===== Dorsal & ventral fins (fans, closer to head) =====
float dFinTop = fanShape(p, vec2(0.28, 0.11), -1.0,
0.40, 0.22, t, 0.015);
float dFinBot = fanShape(p, vec2(0.28, -0.11), -1.0,
0.40, 0.22, t, 0.015);
float finTopMask = smoothstep(0.03, 0.0, dFinTop);
float finBotMask = smoothstep(0.03, 0.0, dFinBot);
// ===== Colors =====
vec3 pastelBlue = vec3(0.70, 0.80, 1.00);
vec3 pastelPink = vec3(1.00, 0.70, 0.90);
vec3 pastelLilac = vec3(0.90, 0.80, 1.00);
// Tail color with simplex noise veins
vec2 qTail = p - tailBase;
qTail.x = -qTail.x;
float tailR = clamp(length(qTail) / tailMaxR, 0.0, 1.0);
float tailAng = atan(qTail.y, qTail.x);
vec3 tailColor = mix(pastelPink, pastelBlue, tailR * 0.7 + 0.1);
float vein = 0.5 + 0.5 * sin(tailAng * 10.0 - t * 0.8);
float veinNoise = snoise(qTail * 4.0 + vec2(0.0, t * 0.3));
float veinMask = tailMask * smoothstep(0.3, 1.0, tailR);
tailColor *= 1.0 + 0.25 * (vein * 0.6 + veinNoise * 0.4) * veinMask;
// Body gradient – light pink overall
float gx = clamp((p.x - 0.10) * 2.0, 0.0, 1.0);
vec3 bodyTail = mix(pastelPink, pastelBlue, 0.25);
vec3 bodyHead = pastelPink;
vec3 bodyColor = mix(bodyTail, bodyHead, gx);
// Body simplex noise for subtle scales
float bodyTex = snoise(p * 6.0 + vec2(t * 0.3, -t * 0.2));
float bodyTexN = 0.5 + 0.5 * bodyTex; // [0,1]
bodyColor *= 0.9 + 0.1 * bodyTexN;
// Body stripes (kept, but now modulated)
float stripeScale = 16.0;
float stripe = 0.5 + 0.5 * sin(p.x * stripeScale + p.y * 4.0);
vec3 stripeTint = vec3(1.05, 1.02, 1.10);
bodyColor = mix(bodyColor, bodyColor * stripeTint,
bodyMask * 0.35 * stripe);
// Fin colors
vec3 finTopColor = mix(pastelLilac, pastelBlue, 0.5);
vec3 finBotColor = mix(pastelPink, pastelBlue, 0.4);
// ===== Draw order: tail → fins → body → eye =====
// Tail
col = mix(col, tailColor, tailMask);
// Fins
col = mix(col, finTopColor, finTopMask);
col = mix(col, finBotColor, finBotMask);
// Rim light for body then draw body
float dFish = smin(dCore, dTail, 0.10);
float rim = smoothstep(0.10, 0.02, dFish + p.y * 0.35);
bodyColor += rim * 0.25;
col = mix(col, bodyColor, bodyMask);
// Eye
float dEyeWhite = sdCircle(p - vec2(0.39, 0.03), 0.018);
float eyeWhiteMask = smoothstep(0.014, 0.0, dEyeWhite);
col = mix(col, vec3(0.98, 0.98, 1.00), eyeWhiteMask);
float dEye = sdCircle(p - vec2(0.39, 0.03), 0.010);
float eyeMask = smoothstep(0.007, 0.0, dEye);
col = mix(col, vec3(0.02, 0.02, 0.06), eyeMask);
colour_out = vec4(col, 1.0);
}
unknown by anonymous
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
vec3 mod289(vec3 x) { return x - floor(x / 289.0) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x / 289.0) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x * 34.0) + 1.0) * x); }
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 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod289(i);
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);
}
/*========= Tail Swing ==========*/
float tailSwing(vec2 p, float t) {
// p.x
return sin(t * 2.0 + p.x * 6.0) * 0.04;
}
/* ========= Fish body ========= */
float fishBody(vec2 p) {
float body = length(vec2(p.x , p.y * 3.0));
return smoothstep(0.28, 0.24, body);
}
/* ========= tail ========= */
float fanTail(vec2 p, float t) {
p.x -= 0.05;
float r = length(p);
float swing = tailSwing(p, u_time);
float a = atan(p.y, p.x + swing);
float alpha = smoothstep(0.2, 0.5, r);
float fan = smoothstep(1.4, 0.6, abs(a));
float radius = 0.4 + 0.15 * cos(a * 2.0);
float ripple = sin(a * 20.0 + t * 3.0) * 0.03;
float tail = smoothstep(radius, radius - 0.02, r + ripple);
return tail * fan * (1.0 - alpha);
}
/*=============== Rays ===================*/
float finRays(vec2 p) {
p.x -= 0.05;
float r = length(p);
float swing = tailSwing(p, u_time);
float a = atan(p.y, p.x + swing);
float fanMask = smoothstep(1.4, 0.6, abs(a));
float rayCount = 28.0;
float rayID = fract((a / 3.1415926 + 0.5) * rayCount);
float angleNorm = abs(a) / 1.4;
float maxR = mix(0.45, 0.25, angleNorm);
float t = clamp(r / maxR, 0.0, 1.0);
float width = mix(2.0, 0.2, t * t);
float ray = smoothstep(width, 0.0, abs(rayID - 0.5));
float lengthMask = smoothstep(0.02, maxR, r);
return ray * fanMask * lengthMask;
}
/*================背鳍腹鳍&眼睛=====================*/
float dorsalFin(vec2 p, float t) {
vec2 q = p;
q.y -= 0.02; //up
q.x += 0.25;
return fanTail(q, t) * 0.2;
}
float analFin(vec2 p, float t) {
vec2 q = p;
q.y += 0.02; //down
q.x += 0.25;
return fanTail(q, t) * 0.8;
}
float eye(vec2 p, vec2 offset) {
return smoothstep(0.023, 0.002, length(p - offset));
}
/*==============鱼须子===========*/
float whisker(vec2 p, vec2 offset, float t, float phase) {
vec2 pos = p - offset;
float sway = sin(length(pos)*15.0 + t*2.0 + phase)*0.02;
float d = abs(pos.x + sway) + abs(pos.y*0.5);
return smoothstep(0.01,0.0,d);
}
/* ========= Vegetation ========= */
float vegetation(vec2 st) {
float n = snoise(st * vec2(3.0, 8.0) + vec2(0.0, u_time * 0.3));
return smoothstep(0.2, 0.6, n + st.y);
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
st.x *= u_resolution.x / u_resolution.y;
vec2 p = st - vec2(0.5, 0.5);
p.y += sin(u_time + p.x * 3.0) * 0.03;
float body = fishBody(p);
float fin = fanTail(p, u_time);
float rays = finRays(p);
float fins = max(fin, max(dorsalFin(p,u_time), analFin(p,u_time)));
float fish = max(body, fins);
float eyes = eye(p, vec2(-0.210,-0.000));
// float headMask = smoothstep(0.18, 0.05, length(p + vec2(0.15, 0.0)));
//float spots = snoise(p * 20.0) * 0.5 + 0.5;
//spots *= headMask;
// float yBody = st.y/3.0- length(vec2(p.x , p.y *3.0));
// float bodyH=0.0;
float bodyLen= 0.28 * 2.0;
// Red zone
//float bodyMask = smoothstep(0.28, 0.24, length(vec2(p.x , p.y * 3.0)));
float redWeight = smoothstep(-bodyLen/3.0, -bodyLen*5.0/24.0, p.x) * (1.0 - smoothstep(-bodyLen*5.0/24.0, -bodyLen/12.0, p.x));
//vec3 bodyColor = mix(vec3(0.8,0.8,0.9), vec3(0.8,0.1,0.1), redWeight);
vec3 redColor = vec3(0.885,0.218,0.117);
// Fish color (iridescent)
vec3 fishColor = vec3(
0.99 + 0.03 * sin(u_time + p.y * 6.0),
0.881 + 0.04 * body,
0.881 + 0.02 * fin
);
// Vegetation background
float veg = vegetation(st);
vec3 vegColor = mix(
vec3(0.0, 0.1, 0.05),
vec3(0.0, 0.3, 0.15),
veg
);
// Water gradient
vec3 water = mix(
vec3(0.072,0.143,0.430),
vec3(0.076,0.535,0.256),
st.y
);
// little shadow
float bodyGrad = smoothstep(-bodyLen/2.0, bodyLen/2.0, p.x);
// little light
float frontBack = mix(1.08, 0.92, bodyGrad);
vec3 color = water + vegColor;
//vec3 color = vec3(0.05,0.1,0.3);
vec3 rayColor = vec3(0.090,0.080,0.100); //
vec3 fishDetail = mix(fishColor, rayColor, rays * 0.7);
color = mix(color, fishDetail, fish);
color = mix(color, vec3(0.05), eyes);
//color = mix(color, vec3(0.8, 0.1, 0.1), spots * 0.6);
//color = mix(color, bodyColor, body);
color = mix(color, redColor, redWeight * body);
/* ===== 鳞片噪声 =====*/
vec2 scaleUV = vec2(p.x * 18.0, p.y * 70.0);
vec2 gv = fract(scaleUV) - 0.5;
float d = length(gv);
float scalePattern = smoothstep(0.25, 0.15, d);
float jitter = sin(p.x * 12.0 + p.y * 7.0) * 0.15;
scalePattern *= (1.0 + jitter);
float scaleRange = smoothstep(-bodyLen * 0.35, -bodyLen * 0.15, p.x)* (1.0 - smoothstep(bodyLen * 0.15, bodyLen * 0.35, p.x));
float scaleLight = 1.0 + scalePattern * 0.9;
color = mix(color, color * scaleLight, body*scaleRange);
color = mix(color, color * frontBack, body);
colour_out = vec4(color, 1.0);
}
Red Tancho Betta Fish by Allyssa