Last active
October 26, 2017 18:31
-
-
Save oveddan/509d9510974a5a1494c58a0d0b648a09 to your computer and use it in GitHub Desktop.
Cellular Voronoi Zoetrope Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PShader frag; | |
int frames = 33; | |
float frameTheta = 2. * PI / frames; | |
int h = 520; | |
int w = 520; | |
float base = 2 * tan(frameTheta / 2.)* h; | |
int renderSize = ceil(base); | |
float sliceAspect = sin(1. / frames * 0.5 * 2 * PI) * 2.; | |
int frameWidth = ceil(h * sliceAspect); | |
void settings() { | |
size(w, h, P2D); | |
} | |
PGraphics pg; | |
void setup() { | |
frag = loadShader("frag.glsl"); | |
frag.set("u_resolution", float(frameWidth), float(h)); | |
frag.set("u_cells", float(3), float(14)); | |
frag.set("u_miny", 0.1); | |
background(255); | |
} | |
String getFrameNumber(int frame) { | |
if (frame < 10) | |
return "0" + frame; | |
return "" + frame + ""; | |
} | |
int frame = 0; | |
int layer = 0; | |
int layers = 4; | |
PVector blue = new PVector(0., 0., 1.); | |
PVector purple = new PVector(1., 0., 1.); | |
PVector white = new PVector(1., 1., 1.); | |
float[] layerBorderSizes = { 1., 0.4, 0.2, 0.07 }; | |
float[] meatballSizes = { 1., 0.6, 0.45, 0.31 }; | |
PVector[] layerColors = { blue, purple, blue, white }; | |
void draw() { | |
if (frame > frames) { | |
frame = 0; | |
layer++; | |
if (layer >= layers) | |
noLoop(); | |
} | |
noStroke(); | |
frag.set("u_time", frame * 1.0 / frames); | |
frag.set("u_bordersize", layerBorderSizes[layer]); | |
frag.set("u_meatballsize", meatballSizes[layer]); | |
frag.set("u_color", layerColors[layer]); | |
//frag.set("u_frame", frame); | |
pg = createGraphics(frameWidth, h, P2D); | |
pg.beginDraw(); | |
//pg.translate(-w/2, 0); | |
pg.filter(frag); | |
//pg.arc(0, 0, h*2, h*2, PI/2 - frameTheta / 2, PI/2 + frameTheta / 2); | |
//pg.rect(0, 0, 200, 200); | |
pg.endDraw(); | |
translate(w/2, h/2); | |
scale(0.5); | |
rotate(lerp(0, -2. * PI, float(frame) / frames)); | |
translate(-frameWidth/2, 0); | |
image(pg, 0,0 ); | |
// saveFrame("frame-" + getFrameNumber(frame) + ".gif"); | |
frame++; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Created by Dan Oved | |
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. | |
// With code by by inigo quilez - iq/2013 | |
// http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm | |
// and code by @patriciogv - 2015 | |
// from: https://thebookofshaders.com/edit.php#12/metaballs.frag | |
#ifdef GL_ES | |
precision mediump float; | |
#endif | |
// uniform mat4 transform; | |
uniform vec2 u_resolution; | |
uniform float u_bordersize; | |
uniform float u_meatballsize; | |
uniform float u_time; | |
uniform vec2 u_cells; | |
uniform vec3 u_color; | |
uniform float u_miny; | |
#define PI 3.1415926535897932384626433832795 | |
vec2 hash2( vec2 p ) { | |
return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); | |
} | |
int frames = 33; | |
float totalTheta = 2. * PI / float(frames); | |
float minTheta = -totalTheta / 2.; | |
vec2 origin = vec2(u_resolution.x / u_resolution.y / 2., 1.); | |
vec2 getRadialCoords(vec2 point) { | |
float y = length(point - origin); | |
float xMagnitude = point.x - origin.x; | |
float theta = sin(xMagnitude / y); | |
return vec2((theta - minTheta) / totalTheta, y); | |
} | |
vec2 getWrappedPoint(vec2 point, vec2 cells) { | |
int x; | |
int y; | |
//vec2 result = point; | |
int rows = int(cells.y); | |
int cols = int(cells.x); | |
if (point.x < 0.) { | |
x = cols - 1; | |
} | |
else if(point.x >= float(cols)) { | |
x = 0; | |
} | |
else { | |
x = int(point.x); | |
} | |
if (point.y < 0.) { | |
y = rows - 1; | |
} else if(point.y >= float(rows)) { | |
y = 0; | |
} else { | |
y = int(point.y); | |
} | |
return vec2(x, y); | |
} | |
float voronoi( in vec2 x, in vec2 cells) | |
{ | |
vec2 n = floor(x); | |
vec2 f = fract(x); | |
//---------------------------------- | |
// first pass: regular voronoi | |
//---------------------------------- | |
vec2 mg, mr; | |
float md = 8.0; | |
for( int j=-1; j<=1; j++ ) | |
for( int i=-1; i<=1; i++ ) | |
{ | |
vec2 g = vec2(float(i),float(j)); | |
vec2 o = hash2(getWrappedPoint(n+g, cells)); | |
o = 0.5 + 0.5*sin(u_time * 2. * PI + 6.2831*o ); | |
vec2 r = g + o - f; | |
float d = dot(r,r); | |
if( d<md ) | |
{ | |
md = d; | |
mr = r; | |
mg = g; | |
} | |
} | |
//---------------------------------- | |
// second pass: distance to borders | |
//---------------------------------- | |
md = 8.0; | |
for( int j=-2; j<=2; j++ ) | |
for( int i=-2; i<=2; i++ ) | |
{ | |
vec2 g = mg + vec2(float(i),float(j)); | |
vec2 o = hash2(getWrappedPoint(n+g, cells)); | |
o = 0.5 + 0.5*sin(u_time * 2. * PI + 6.2831*o ); | |
vec2 r = g + o - f; | |
if( dot(mr-r,mr-r)>0.00001 ) | |
md = min( md, dot( 0.5*(mr+r), normalize(r-mr) ) ); | |
} | |
return md; | |
} | |
vec2 random2( vec2 p ) { | |
return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453); | |
} | |
float meatballs(vec2 st, vec2 cells) { | |
vec2 i_st = floor(st); | |
vec2 f_st = fract(st); | |
float m_dist = 1.; // minimun distance | |
for (int j= -1; j <= 1; j++ ) { | |
for (int i= -1; i <= 1; i++ ) { | |
// Neighbor place in the grid | |
vec2 neighbor = vec2(float(i),float(j)); | |
// Random position from current + neighbor place in the grid | |
vec2 offset = random2(getWrappedPoint(i_st + neighbor, cells)); | |
// Animate the offset | |
offset = 0.5 + 0.5*sin(u_time * 2. * PI + 6.2831*offset); | |
// Position of the cell | |
vec2 pos = neighbor + offset - f_st; | |
// Cell distance | |
float dist = length(pos); | |
// Metaball it! | |
m_dist = min(m_dist, m_dist*dist); | |
} | |
} | |
// Draw cells | |
return m_dist; | |
} | |
float divider = 0.5; | |
float bordersize = 0.005; | |
void main() { | |
vec2 st = gl_FragCoord.xy/u_resolution.xy; | |
st.x *= u_resolution.x/u_resolution.y; | |
st = getRadialCoords(st); | |
float show = (1. - step(1. - bordersize, st.y)) * step(u_miny, st.y); | |
show *= step(0., st.x) * (1.-step(1., st.x)); | |
float color; | |
if(st.y < divider) { | |
vec2 cells = u_cells * vec2(1., 6.); | |
st *= cells; | |
float meatball = meatballs(st, cells); | |
show *= 1.-step(u_meatballsize, meatball); | |
} else { | |
st *= u_cells; | |
float c = voronoi(st, u_cells); | |
show *= (1.-step(u_bordersize, c)); | |
} | |
gl_FragColor = vec4(u_color, show); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment