Files
SliceBeam/app/src/main/assets/shaders/beam_intro.fs
T
2024-11-01 08:28:55 +03:00

165 lines
4.6 KiB
GLSL

#version 300 es
precision highp float;
uniform vec4 top_color;
uniform vec4 bottom_color;
uniform vec2 resolution;
uniform float time;
uniform float progress;
in vec2 tex_coord;
out vec4 fragment_color;
//
// 2-D tiling simplex noise with rotating gradients and analytical derivative.
// "vec2 x" is the point (x,y) to evaluate,
// "vec2 period" is the desired periods along x and y, and
// "float alpha" is the rotation (in radians) for the swirling gradients.
// The "float" return value is the noise value, and
// the "out vec2 gradient" argument returns the x,y partial derivatives.
//
// Setting either period to 0.0 or a negative value will skip the wrapping
// along that dimension. Setting both periods to 0.0 makes the function
// execute about 15% faster.
//
// Not using the return value for the gradient will make the compiler
// eliminate the code for computing it. This speeds up the function
// by 10-15%.
//
// The rotation by alpha uses one single addition. Unlike the 3-D version
// of psrdnoise(), setting alpha == 0.0 gives no speedup.
//
float psrdnoise(vec2 x, vec2 period, float alpha, out vec2 gradient) {
// Transform to simplex space (axis-aligned hexagonal grid)
vec2 uv = vec2(x.x + x.y*0.5, x.y);
// Determine which simplex we're in, with i0 being the "base"
vec2 i0 = floor(uv);
vec2 f0 = fract(uv);
// o1 is the offset in simplex space to the second corner
float cmp = step(f0.y, f0.x);
vec2 o1 = vec2(cmp, 1.0-cmp);
// Enumerate the remaining simplex corners
vec2 i1 = i0 + o1;
vec2 i2 = i0 + vec2(1.0, 1.0);
// Transform corners back to texture space
vec2 v0 = vec2(i0.x - i0.y * 0.5, i0.y);
vec2 v1 = vec2(v0.x + o1.x - o1.y * 0.5, v0.y + o1.y);
vec2 v2 = vec2(v0.x + 0.5, v0.y + 1.0);
// Compute vectors from v to each of the simplex corners
vec2 x0 = x - v0;
vec2 x1 = x - v1;
vec2 x2 = x - v2;
vec3 iu, iv;
vec3 xw, yw;
// Wrap to periods, if desired
if(any(greaterThan(period, vec2(0.0)))) {
xw = vec3(v0.x, v1.x, v2.x);
yw = vec3(v0.y, v1.y, v2.y);
if(period.x > 0.0)
xw = mod(vec3(v0.x, v1.x, v2.x), period.x);
if(period.y > 0.0)
yw = mod(vec3(v0.y, v1.y, v2.y), period.y);
// Transform back to simplex space and fix rounding errors
iu = floor(xw + 0.5*yw + 0.5);
iv = floor(yw + 0.5);
} else { // Shortcut if neither x nor y periods are specified
iu = vec3(i0.x, i1.x, i2.x);
iv = vec3(i0.y, i1.y, i2.y);
}
// Compute one pseudo-random hash value for each corner
vec3 hash = mod(iu, 289.0);
hash = mod((hash*51.0 + 2.0)*hash + iv, 289.0);
hash = mod((hash*34.0 + 10.0)*hash, 289.0);
// Pick a pseudo-random angle and add the desired rotation
vec3 psi = hash * 0.07482 + alpha;
vec3 gx = cos(psi);
vec3 gy = sin(psi);
// Reorganize for dot products below
vec2 g0 = vec2(gx.x,gy.x);
vec2 g1 = vec2(gx.y,gy.y);
vec2 g2 = vec2(gx.z,gy.z);
// Radial decay with distance from each simplex corner
vec3 w = 0.8 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2));
w = max(w, 0.0);
vec3 w2 = w * w;
vec3 w4 = w2 * w2;
// The value of the linear ramp from each of the corners
vec3 gdotx = vec3(dot(g0, x0), dot(g1, x1), dot(g2, x2));
// Multiply by the radial decay and sum up the noise value
float n = dot(w4, gdotx);
// Compute the first order partial derivatives
vec3 w3 = w2 * w;
vec3 dw = -8.0 * w3 * gdotx;
vec2 dn0 = w4.x * g0 + dw.x * x0;
vec2 dn1 = w4.y * g1 + dw.y * x1;
vec2 dn2 = w4.z * g2 + dw.z * x2;
gradient = 10.9 * (dn0 + dn1 + dn2);
// Scale the return value to fit nicely into the range [-1,1]
return 10.9 * n;
}
float bounceOut(in float t) {
const float a = 4.0 / 11.0;
const float b = 8.0 / 11.0;
const float c = 9.0 / 10.0;
const float ca = 4356.0 / 361.0;
const float cb = 35442.0 / 1805.0;
const float cc = 16061.0 / 1805.0;
float t2 = t * t;
return t < a
? 7.5625 * t2
: t < b
? 9.075 * t2 - 9.9 * t + 3.4
: t < c
? ca * t2 - cb * t + cc
: 10.8 * t * t - 20.52 * t + 10.72;
}
vec2 rot(vec2 v, float a){
return mat2x2(
cos(a), -sin(a),
sin(a), cos(a)
) * v;
}
float bounceIn(in float t) {
return 1.0 - bounceOut(1.0 - t);
}
void main() {
float PI = radians(180.0);
vec2 st = tex_coord;
st = rot(st, -PI / 2.0);
vec2 gradient;
float n = psrdnoise(vec2(3.) * st, vec2(0.), 3.0 * time, gradient);
float lines = cos((st.x + n * 0.05 + progress * 0.8 + 0.1) * PI);
if (tex_coord.y < 0.1 + progress * 0.9) {
fragment_color = bottom_color;
} else {
fragment_color = mix(top_color, bottom_color, bounceIn(lines * 0.5 + 0.5));
}
}