139 lines
5.5 KiB
GLSL
139 lines
5.5 KiB
GLSL
#version 460 core
|
|
#include <flutter/runtime_effect.glsl>
|
|
|
|
out vec4 fragColor;
|
|
|
|
uniform vec2 uSize;
|
|
uniform vec2 uTilt;
|
|
uniform float uPrismatic;
|
|
uniform float uSparkle;
|
|
uniform float uSpecular;
|
|
uniform float uDiffraction;
|
|
uniform float uOpacity;
|
|
|
|
#define TWO_PI 6.28318530718
|
|
|
|
float hash(vec2 p) {
|
|
vec3 p3 = fract(vec3(p.xyx) * 0.1031);
|
|
p3 += dot(p3, p3.yzx + 33.33);
|
|
return fract((p3.x + p3.y) * p3.z);
|
|
}
|
|
|
|
float noise(vec2 p) {
|
|
vec2 i = floor(p);
|
|
vec2 f = fract(p);
|
|
vec2 u = 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, u.x), mix(c, d, u.x), u.y);
|
|
}
|
|
|
|
vec3 hsv2rgb(float h, float s, float v) {
|
|
vec3 k = vec3(1.0, 2.0 / 3.0, 1.0 / 3.0);
|
|
vec3 p = abs(fract(vec3(h) + k) * 6.0 - 3.0);
|
|
return v * mix(vec3(1.0), clamp(p - 1.0, 0.0, 1.0), s);
|
|
}
|
|
|
|
vec3 rainbow(float phase, float saturation, float value) {
|
|
return hsv2rgb(fract(phase), saturation, value);
|
|
}
|
|
|
|
vec2 safeNormalize(vec2 p) {
|
|
return p * inversesqrt(max(dot(p, p), 0.000001));
|
|
}
|
|
|
|
float sdRegularPolygon(vec2 p, float sides, float radius) {
|
|
float angle = atan(p.y, p.x);
|
|
float sector = TWO_PI / sides;
|
|
return cos(floor(0.5 + angle / sector) * sector - angle) * length(p) - radius;
|
|
}
|
|
|
|
float sparklePolygonMask(vec2 p, float sides, float aspectRatio, float rotation) {
|
|
float c = cos(rotation);
|
|
float s = sin(rotation);
|
|
vec2 q = vec2(c * p.x - s * p.y, s * p.x + c * p.y);
|
|
q.x /= aspectRatio;
|
|
float poly = sdRegularPolygon(q, sides, 0.26);
|
|
return smoothstep(0.03, -0.03, poly);
|
|
}
|
|
|
|
vec3 styleBase(vec2 uv, vec2 tilt) {
|
|
vec2 g = uv * 6.0;
|
|
vec2 id = floor(g);
|
|
vec2 f = fract(g) - 0.5;
|
|
vec2 rotatedF = vec2(-f.y, f.x);
|
|
f = mix(f, rotatedF, step(0.5, mod(id.x + id.y, 2.0)));
|
|
vec2 radialDir = safeNormalize(f + vec2(0.0001));
|
|
vec2 lightDir = safeNormalize(tilt + vec2(0.001));
|
|
float alignment = abs(dot(radialDir, lightDir));
|
|
float highlight = pow(alignment, 12.0);
|
|
float angleDiff = acos(clamp(alignment, 0.0, 1.0));
|
|
float side = sign(radialDir.x * lightDir.y - radialDir.y * lightDir.x);
|
|
float basePhase = length(tilt) * 2.5 + dot(uv, vec2(0.9, -0.7));
|
|
float phase = basePhase + side * angleDiff * 1.8;
|
|
vec3 holoColor = rainbow(phase, 0.85, 1.0);
|
|
vec3 core = vec3(1.0) * smoothstep(0.98, 1.0, alignment);
|
|
vec3 foilBase = vec3(0.25, 0.27, 0.30);
|
|
vec3 finalColor = foilBase + (holoColor * highlight * 1.5) + (core * 0.8);
|
|
float edgeX = 0.5 - abs(f.x);
|
|
float edgeY = 0.5 - abs(f.y);
|
|
float border = smoothstep(0.0, 0.015, min(edgeX, edgeY));
|
|
float dist = length(f);
|
|
finalColor *= mix(0.7, 1.0, 1.0 - smoothstep(0.0, 0.5, dist) * 0.3);
|
|
return clamp(finalColor * border, 0.0, 1.0);
|
|
}
|
|
|
|
vec3 sparkleLayer(vec2 aspectUV, vec2 tilt, vec2 tiltDir) {
|
|
vec2 sparkleGrid = aspectUV * 14.0;
|
|
vec2 grid = floor(sparkleGrid);
|
|
vec2 cell = fract(sparkleGrid) - 0.5;
|
|
float sparkleHash = hash(grid);
|
|
vec2 sparkleNormal = safeNormalize(vec2(sparkleHash * 2.0 - 1.0, hash(grid + 19.7) * 2.0 - 1.0));
|
|
float rarity = step(0.88, hash(grid + 0.31));
|
|
float alignment = max(0.0, dot(tiltDir, sparkleNormal));
|
|
float twinkle = 0.45 + 0.55 * sin(dot(cell, vec2(21.0, -17.0)) + dot(tilt, vec2(5.3, -4.1)) + sparkleHash * TWO_PI);
|
|
float shapeMask = sparklePolygonMask(cell, 6.0, 1.0, 0.0);
|
|
float sparkleMask = pow(alignment, 3.8) * twinkle * rarity * shapeMask;
|
|
vec3 sparkleColor = mix(vec3(1.0), rainbow(sparkleHash + dot(tilt, vec2(0.2, -0.15)), 0.55, 1.0), 0.35);
|
|
return sparkleColor * sparkleMask * uSparkle * 0.55 * 0.80;
|
|
}
|
|
|
|
void main() {
|
|
vec2 frag = FlutterFragCoord().xy;
|
|
vec2 uv = frag / uSize;
|
|
vec2 fromCenter = uv - vec2(0.5);
|
|
float maxDim = max(uSize.x, uSize.y);
|
|
vec2 aspectUV = frag / maxDim;
|
|
float tiltMag = length(uTilt);
|
|
vec2 tiltDir = safeNormalize(uTilt + vec2(0.001));
|
|
float highlightDistance = length(uv - (vec2(0.5) + (uTilt * 0.35)));
|
|
float specularMask = pow(max(0.0, 1.0 - highlightDistance * 2.6), 3.4);
|
|
|
|
vec3 base = styleBase(aspectUV, uTilt);
|
|
vec3 sparkle = sparkleLayer(aspectUV, uTilt, tiltDir);
|
|
float baseLuma = dot(base, vec3(0.299, 0.587, 0.114));
|
|
vec3 chromaAdjusted = mix(vec3(baseLuma), base, 0.2 + 0.8 * uPrismatic);
|
|
|
|
vec2 normal2d = safeNormalize(fromCenter + vec2(0.001));
|
|
float directional = 0.5 + 0.5 * dot(normal2d, tiltDir);
|
|
float tiltLighting = mix(0.86, 1.20, pow(directional, 1.2));
|
|
chromaAdjusted *= tiltLighting;
|
|
|
|
float edgeSpec = pow(1.0 - directional, 2.2);
|
|
vec3 specular = vec3(specularMask) * (0.3 + 0.7 * edgeSpec) * uSpecular * (0.35 + 0.65 * tiltMag) * 1.15;
|
|
float prismaticPhase = dot(aspectUV, vec2(3.6, -2.1)) + dot(uTilt, vec2(0.9, -0.7));
|
|
vec3 prismaticTint = rainbow(prismaticPhase, 0.72, 1.0) * uPrismatic * 1.30 * 1.15 * (0.08 + 0.14 * edgeSpec);
|
|
float microMask = 0.5 + 0.5 * sin(dot(aspectUV, vec2(137.0, 57.0)) + noise(aspectUV * 14.0) * 4.0 + dot(uTilt, vec2(9.0, 4.0)) * 2.0);
|
|
vec3 microShimmer = rainbow(noise(aspectUV * 10.0) + dot(uTilt, vec2(0.4, -0.3)) * 0.3, 0.65, 1.0) * microMask * uDiffraction * 0.18;
|
|
|
|
vec3 styleColor = chromaAdjusted + microShimmer + prismaticTint + (specular * 0.22) + sparkle;
|
|
vec3 mappedColor = styleColor / (1.0 + styleColor * 0.3);
|
|
float luma = dot(mappedColor, vec3(0.299, 0.587, 0.114));
|
|
vec3 vibrantColor = mix(vec3(luma), mappedColor, 1.4);
|
|
float foilBrightness = dot(vibrantColor, vec3(0.333));
|
|
float alpha = clamp(foilBrightness * 0.5, 0.0, 0.35) * clamp(uOpacity, 0.0, 1.0);
|
|
vec3 finalColor = clamp(vibrantColor, 0.0, 1.0);
|
|
fragColor = vec4(finalColor * alpha, alpha);
|
|
} |