148 lines
4.2 KiB
Text
148 lines
4.2 KiB
Text
// Original code is MIT licensed by Cory Petkovsek
|
|
// https://github.com/TokisanGames/godot-fractal-art
|
|
|
|
shader_type canvas_item;
|
|
|
|
uniform bool smoothing = true;
|
|
uniform bool use_color_gradient = false;
|
|
uniform vec4 gradient_start : source_color = vec4(0.18, 0., 0.45, 1.);
|
|
uniform vec4 gradient_end : source_color = vec4(1., 1., 0., 1.);
|
|
uniform vec4 gradient_accent : source_color = vec4(1., 1., 0., 1.);
|
|
uniform float accent_position = 0.65;
|
|
uniform float accent_width = 0.34;
|
|
uniform float red_frequency = 1.6615;
|
|
uniform float green_frequency = 1.246;
|
|
uniform float blue_frequency = 0.831;
|
|
uniform float red_phase = 6.3;
|
|
uniform float green_phase = 6.3;
|
|
uniform float blue_phase = 6.3;
|
|
|
|
uniform highp float scale = 0.5;
|
|
uniform highp vec2 position = vec2(0, 0);
|
|
uniform float aspect_ratio = 1.33333;
|
|
|
|
uniform highp vec2 seed = vec2(-0.794084, 0.136444);
|
|
uniform int power = 2;
|
|
uniform float iterations = 50.0;
|
|
uniform float escape = 4.0;
|
|
|
|
// Convert from rectangular to polar
|
|
highp vec2 c_pol(highp vec2 c) {
|
|
highp float radius = length(c);
|
|
highp float theta = atan(c.y, c.x);
|
|
return vec2(radius, theta);
|
|
}
|
|
|
|
// Convert from rectangular to Polar
|
|
highp vec2 c_rec(highp vec2 c) {
|
|
highp float radius = abs(c.x);
|
|
highp float theta = c.y;
|
|
highp float a = radius * cos(theta);
|
|
highp float b = radius * sin(theta);
|
|
return vec2(a, b);
|
|
}
|
|
|
|
// Calculate base ^ exponent
|
|
highp vec2 c_pow(highp vec2 base, highp float ex) {
|
|
highp vec2 b = c_pol(base);
|
|
return c_rec(vec2(pow(b.x, ex), b.y * ex));
|
|
}
|
|
|
|
vec4 alpha_blend(vec4 top, vec4 bot) {
|
|
return vec4(top.r * top.a + bot.r * bot.a * (1. - top.a),
|
|
top.g * top.a + bot.g * bot.a * (1. - top.a),
|
|
top.b * top.a + bot.b * bot.a * (1. - top.a),
|
|
1.0);
|
|
}
|
|
|
|
vec4 getColor(float i) {
|
|
if (use_color_gradient) {
|
|
// Create gradient
|
|
vec4 ramp = mix(gradient_start, gradient_end, i);
|
|
|
|
// gaussian formula ae^( -(x-b)^2 / 2c^2 )
|
|
// a = curve's peak = 1.0
|
|
// b = center of peak position
|
|
// c = standard deviation which controls width of bell
|
|
|
|
float gaussianx = exp(-((i - accent_position) * (i - accent_position)) / (2. * accent_width * accent_width));
|
|
vec4 accent = vec4(gradient_accent.r * gaussianx,
|
|
gradient_accent.g * gaussianx,
|
|
gradient_accent.b * gaussianx,
|
|
gaussianx);
|
|
|
|
return alpha_blend(accent, ramp);
|
|
} else {
|
|
/* Sin/Cos creates a smooth wave between 1 and -1, offset from each other.
|
|
* You can have 4 evenly distributed offsets from sin, cos, -sin, -cos
|
|
* (sin(x) +1) / 2 -> changes the wave to go between 0 and 1 with the same frequency, +2../4 will go from 0.5 and 1.0
|
|
* Calculate full cycles with: sin(cycles*6.5*i) or (sin(cycles*5.4*i)+1.0)/2.0 or (cos(cycles*3.8*i)+1.0)/2.0
|
|
*/
|
|
return vec4((sin(red_frequency * 6.5 * i + red_phase) + 1.0) / 2.0,
|
|
(sin(green_frequency * 6.5 * i + green_phase) + 1.0) / 2.0,
|
|
(sin(blue_frequency * 6.5 * i + blue_phase) + 1.0) / 2.0,
|
|
1.);
|
|
}
|
|
}
|
|
|
|
vec2 random(vec2 uv) {
|
|
return vec2(fract(sin(dot(uv.xy,
|
|
vec2(12.9898,78.233))) * 43758.5453123));
|
|
}
|
|
|
|
vec2 voronoi(vec2 uv, float columns, float rows) {
|
|
vec2 index_uv = floor(vec2(uv.x * columns, uv.y * rows));
|
|
vec2 fract_uv = fract(vec2(uv.x * columns, uv.y * rows));
|
|
|
|
float minimum_dist = 1.0;
|
|
vec2 minimum_point;
|
|
|
|
for (int y= -1; y <= 1; y++) {
|
|
for (int x= -1; x <= 1; x++) {
|
|
vec2 neighbor = vec2(float(x),float(y));
|
|
vec2 point = random(index_uv + neighbor);
|
|
|
|
vec2 diff = neighbor + point - fract_uv;
|
|
float dist = length(diff);
|
|
|
|
if(dist < minimum_dist) {
|
|
minimum_dist = dist;
|
|
minimum_point = point;
|
|
}
|
|
}
|
|
}
|
|
return minimum_point;
|
|
}
|
|
|
|
|
|
void fragment() {
|
|
float i = 0.0;
|
|
|
|
highp vec2 c = seed;
|
|
|
|
highp vec2 z;
|
|
z.x = aspect_ratio * (UV.x - 0.5) / scale - position.x;
|
|
z.y = (UV.y - 0.5) / scale + position.y;
|
|
|
|
if (power == 2) {
|
|
while (i < iterations && length(z) <= escape) {
|
|
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c; // 20fps
|
|
i++;
|
|
}
|
|
} else {
|
|
while (i < iterations && length(z) <= escape) {
|
|
z = c_pow(z, float(power)) + c; // 6-7fps
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i >= iterations) {
|
|
float r = voronoi(UV + seed, 10.0, 5.0).r;
|
|
COLOR = getColor(r);
|
|
} else {
|
|
if (smoothing && power > 1) {
|
|
i -= log(log(length(z))) / log(float(power));
|
|
}
|
|
COLOR = getColor(i / iterations);
|
|
}
|
|
}
|