precision mediump float; in vec2 v_texCoord; uniform vec2 resolution; uniform float time; const int SIZE_X = 40; const int SIZE_Y = 12; const int OBJ_SIZE = SIZE_X * SIZE_Y; const int[OBJ_SIZE] tiles = int[](0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 1, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 0, 0, 0, 5, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 6, 1, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 5, 6, 6, 5, 0, 0, 0, 3, 2, 4, 4, 1, 4, 1, 4, 1, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 5, 6, 6, 5, 0, 0, 0, 0, 0, 3, 2, 2, 6, 2, 3, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 3, 2, 4, 4, 6, 6, 5, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 1, 4, 6, 3, 4, 4, 1, 4, 1, 1, 0, 0, 3, 2, 6, 6, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 3, 4, 4, 1, 4, 1, 4, 1, 1, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 5, 0, 0, 0, 3, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); //uniform int[OBJ_SIZE] tiles; const int SIZE_16MS_X = 45; const int SIZE_16MS_Y = 12; const int OBJ_SIZE_16MS = SIZE_16MS_X * SIZE_16MS_Y; const int[OBJ_SIZE_16MS] tiles16ms = int[](0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 1, 0, 0, 0, 5, 1, 4, 1, 4, 1, 4, 1, 1, 0, 0, 0, 5, 1, 1, 0, 5, 1, 1, 0, 5, 1, 1, 0, 5, 1, 4, 1, 4, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 3, 2, 4, 1, 3, 2, 4, 1, 3, 2, 4, 1, 3, 3, 5, 0, 0, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 3, 2, 4, 1, 3, 2, 4, 1, 3, 2, 4, 1, 0, 2, 2, 3, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 4, 1, 0, 0, 3, 2, 4, 1, 3, 2, 4, 1, 3, 6, 4, 1, 3, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 4, 1, 4, 1, 6, 5, 0, 0, 0, 3, 2, 2, 6, 2, 3, 2, 3, 2, 3, 5, 0, 3, 3, 2, 3, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 5, 1, 1, 0, 0, 3, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 3, 2, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 1, 4, 6, 6, 4, 1, 0, 0, 3, 2, 4, 4, 1, 4, 6, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 2, 3, 2, 3, 2, 3, 5, 0, 0, 0, 3, 3, 2, 3, 2, 3, 2, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); const int TILE_NONE = 0; const int TILE_TOP = 1; const int TILE_BOTTOM = 2; const int TILE_TOP_RIGHT = 3; const int TILE_BOTTOM_RIGHT = 4; const int TILE_TOP_LEFT = 5; const int TILE_BOTTOM_LEFT = 6; const float PI = 3.14159265359; const float PI_2 = PI * 0.5; const float PI_3 = PI / 3.0; const vec2 TRIANGLE_LEFT = vec2(0); const vec2 TRIANGLE_RIGHT = vec2(1, 0); const vec2 TRIANGLE_TOP = vec2(cos(PI_3), sin(PI_3)); const vec2 TRIANGLE_CENTER = (TRIANGLE_LEFT + TRIANGLE_RIGHT + TRIANGLE_TOP) / vec2(3); const float TRIANGLE_HEIGHT = sin(PI_3); const float TRIANGLE_EDGE_LENGTH = 1.0; const mat2 ROT_120 = mat2(cos(2. * PI_3), -sin(2. * PI_3), sin(2. * PI_3), cos(2. * PI_3)); const mat2 ROT_120_REV = mat2(cos(2. * -PI_3), -sin(2. * -PI_3), sin(2. * -PI_3), cos(2. * -PI_3)); //w: start time //s: duration float scene(in float t, in float w, in float s){ return clamp(t - w, 0.0, s) / s; } float expEasingIn(float t){ return pow( 2., 13. * (t - 1.) ); } float expEasingOut(float t) { return -pow( 2., -10. * t) + 1.; } float circEasingInOut(float t){ t /= .5; if (t < 1.) return -.5 * (sqrt(1. - t*t) - 1.); t -= 2.; return .5 * (sqrt(1. - t*t) + 1.); } float circEasingIn(float t){ return - (sqrt(1. - t*t) - 1.); } vec3 computeColor(const int tileType, vec2 p, const vec3 backgroundColor, const vec3 tileTopColor, const vec3 tileBottomColor) { if(tileType == TILE_NONE) { return backgroundColor; } else if(tileType == TILE_TOP) { if(p.y > TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } else if(tileType == TILE_BOTTOM) { if(p.y <= TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } else if(tileType == TILE_TOP_RIGHT) { vec2 np = ROT_120_REV * (p - TRIANGLE_CENTER) + TRIANGLE_CENTER; if(np.y > TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } else if(tileType == TILE_BOTTOM_RIGHT) { vec2 np = ROT_120_REV * (p - TRIANGLE_CENTER) + TRIANGLE_CENTER; if(np.y <= TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } else if(tileType == TILE_TOP_LEFT) { vec2 np = ROT_120 * (p - TRIANGLE_CENTER) + TRIANGLE_CENTER; if(np.y > TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } else if(tileType == TILE_BOTTOM_LEFT) { vec2 np = ROT_120 * (p - TRIANGLE_CENTER) + TRIANGLE_CENTER; if(np.y <= TRIANGLE_HEIGHT * 0.5) { return tileTopColor; } return tileBottomColor; } return backgroundColor; } //vec2 rand2n(vec2 co, float sampleIndex); float random (vec2 st) { return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123); } int g_currentLine = 90; int getTile(const int x, const int y) { const int translateX = 0; const int translateY = 0; //a[0] = int(mod(time * 5., 7.)); if(x - translateX * 2 < 0 || SIZE_X <= x - translateX * 2 || y - translateY < 0 || SIZE_Y <= y - translateY) { //return TILE_NONE; if(g_currentLine < x) { return int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); } else { return TILE_NONE; } } int index = (x - translateX * 2) + (y - translateY) * SIZE_X; if(0 <= index && index < OBJ_SIZE) { //return int(random(vec2(float(x) + time, float(y) - time)) * 7.);//a[index]; //return a[index]; // if(tiles[index] == TILE_NONE) { // return TILE_NONE; // } if(g_currentLine < x) { return tiles[index] + int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); } else { return tiles[index]; } } return TILE_NONE; } int getTileRandom(const int x, const int y) { const int translateX = 0; const int translateY = 0; //a[0] = int(mod(time * 5., 7.)); if(x - translateX * 2 < 0 || SIZE_X <= x - translateX * 2 || y - translateY < 0 || SIZE_Y <= y - translateY) { //return TILE_NONE; return TILE_NONE; } int index = (x - translateX * 2) + (y - translateY) * SIZE_X; if((0 <= index && index < OBJ_SIZE)) { if(tiles[index] != TILE_NONE) { for(int xx = -1 ; xx <= 1; xx++) { for(int yy = -1 ; yy <= 1; yy++) { int ii = (x + xx - translateX * 2) + (y + yy - translateY) * SIZE_X; if((0 <= ii && ii < OBJ_SIZE)) { //return tiles[index] + int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); return int(mod(float(tiles[ii]) + (time * 5. + (random(vec2(x + xx, y + yy)) * 10.0)), 7.)); } } } } } return TILE_NONE; } int getTileRandom2(const int x, const int y) { const int translateX = 0; const int translateY = 0; //a[0] = int(mod(time * 5., 7.)); if(x - translateX * 2 < 0 || SIZE_X <= x - translateX * 2 || y - translateY < 0 || SIZE_Y <= y - translateY) { //return TILE_NONE; return TILE_NONE; } int index = (x - translateX * 2) + (y - translateY) * SIZE_X; if(0 <= index && index < OBJ_SIZE) { if(tiles[index] != TILE_NONE) { //return tiles[index] + int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); return int(mod(float(tiles16ms[index]) + (time * 5. + (random(vec2(x, y)) * 10.0)), 7.)); } } int index2 = (x - translateX * 2) + (y - translateY) * SIZE_16MS_X; if(0 <= index2 && index2 < OBJ_SIZE_16MS) { if(tiles16ms[index2] != TILE_NONE) { //return tiles16ms[index2] + int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); return int(mod(float(tiles16ms[index2]) + (time * 5. + (random(vec2(x, y)) * 10.0)), 7.)); } } return TILE_NONE; } int getTileRandom16ms(const int x, const int y) { const int translateX = 0; const int translateY = 0; //a[0] = int(mod(time * 5., 7.)); if(x - translateX * 2 < 0 || SIZE_16MS_X <= x - translateX * 2 || y - translateY < 0 || SIZE_16MS_Y <= y - translateY) { //return TILE_NONE; return TILE_NONE; } int index = (x - translateX * 2) + (y - translateY) * SIZE_16MS_X; if((0 <= index && index < OBJ_SIZE_16MS)) { if(tiles16ms[index] != TILE_NONE) { for(int xx = -1 ; xx <= 1; xx++) { for(int yy = -1 ; yy <= 1; yy++) { int ii = (x + xx - translateX * 2) + (y + yy - translateY) * SIZE_16MS_X; if((0 <= ii && ii < OBJ_SIZE_16MS)) { return int(mod(float(tiles16ms[ii]) + (time * 5. + (random(vec2(x + xx, y + yy)) * 10.0)), 7.)); } } } } } return TILE_NONE; } int getTile16ms(const int x, const int y) { const int translateX = 0; const int translateY = 0; //a[0] = int(mod(time * 5., 7.)); if(x - translateX * 2 < 0 || SIZE_16MS_X <= x - translateX * 2 || y - translateY < 0 || SIZE_16MS_Y <= y - translateY) { //return TILE_NONE; if(g_currentLine < x) { return int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); } else { return TILE_NONE; } } int index = (x - translateX * 2) + (y - translateY) * SIZE_16MS_X; if(0 <= index && index < OBJ_SIZE_16MS) { //return int(random(vec2(float(x) + time, float(y) - time)) * 7.);//a[index]; //return a[index]; // if(tiles[index] == TILE_NONE) { // return TILE_NONE; // } if(g_currentLine < x) { return tiles16ms[index] + int(mod(time * 5. + floor(random(vec2(x, y)) * 10.0), 7.0)); } else { return tiles16ms[index]; } } return TILE_NONE; } // from Syntopia http://blog.hvidtfeldts.net/index.php/2015/01/path-tracing-3d-fractals/ vec2 rand2n(vec2 co, float sampleIndex) { vec2 seed = co * (sampleIndex + 1.0); seed+=vec2(-1,1); // implementation based on: lumina.sourceforge.net/Tutorials/Noise.html return vec2(fract(sin(dot(seed.xy ,vec2(12.9898,78.233))) * 43758.5453), fract(cos(dot(seed.xy ,vec2(4.898,7.23))) * 23421.631)); } vec3 hsv2rgb(float h, float s, float v){ vec3 c = vec3(h, s, v); const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } const float DISPLAY_GAMMA_COEFF = 1. / 2.2; vec4 gammaCorrect(vec4 rgba) { return vec4((min(pow(rgba.r, DISPLAY_GAMMA_COEFF), 1.)), (min(pow(rgba.g, DISPLAY_GAMMA_COEFF), 1.)), (min(pow(rgba.b, DISPLAY_GAMMA_COEFF), 1.)), rgba.a); } vec4 plane1 = vec4(0, 0, 0, 1); // (x, y, normalX, normalY) vec4 plane2 = vec4(0, 0, sin(PI_3), -cos(PI_3)); vec4 plane3 = vec4(1, 0, -sin(2. * PI_3), cos(2. * PI_3)); int IIS(vec2 pos) { int invNum = 0; for (int i = 0; i < 1000; i++) { pos -= plane1.xy; float dHalfPlane1 = dot(pos, plane1.zw); if(dot(pos, plane1.zw) < 0. ) { invNum++; pos -= 2.0 * min(0., dHalfPlane1) * plane1.zw; pos += plane1.xy; continue; } pos += plane1.xy; pos -= plane2.xy; float dHalfPlane2 = dot(pos, plane2.zw); if(dot(pos, plane2.zw) < 0. ) { invNum++; pos -= 2.0 * min(0., dHalfPlane2) * plane2.zw; pos += plane2.xy; continue; } pos += plane2.xy; pos -= plane3.xy; float dHalfPlane3 = dot(pos, plane3.zw); if(dot(pos, plane3.zw) < 0. ) { invNum++; pos -= 2.0 * min(0., dHalfPlane3) * plane3.zw; pos += plane3.xy; continue; } pos += plane3.xy; } return invNum; } const float SAMPLE_NUM = 20.; out vec4 fragColor; void main(){ vec3 sum = vec3(0); float ratio = resolution.x / resolution.y / 2.0; for(float i = 0. ; i < SAMPLE_NUM ; i++){ vec2 pos = ((gl_FragCoord.xy + rand2n(gl_FragCoord.xy, i)) / resolution.yy ) - vec2(ratio, 0.5); pos *= 12.; pos += vec2(14, 5); float a = TRIANGLE_TOP.y / TRIANGLE_TOP.x; float x = pos.y / a; float translatedX = mod(pos.x - x, 1.) + x; float xIndex = floor(pos.x - x); float yIndex = floor(pos.y / TRIANGLE_HEIGHT); vec2 fundamentalPos = vec2(translatedX, pos.y) - TRIANGLE_TOP * yIndex; xIndex *= 2.0; fundamentalPos -= plane3.xy; float dplane = dot(fundamentalPos, normalize(plane3.zw)); if(dplane < 0.) { xIndex++; } fundamentalPos -= 2.0 * min(0., dplane) * plane3.zw; fundamentalPos += plane3.xy; float t = mod(time, 19.); float strokeWeight = 3.; //float strokeWeight = 0.01; float startTime = 0.; float durations = 3.; strokeWeight = mix(2., 0., scene(t, startTime, durations)); startTime += durations; durations = 8.; g_currentLine = int(mix(-15., 80., scene(t, startTime, durations))); startTime += durations; startTime += 3.; durations = 3.; strokeWeight += mix(0., 0.5, scene(t, startTime, durations)); startTime += durations; if(abs(dot(fundamentalPos - plane1.xy, plane1.zw)) < strokeWeight || abs(dot(fundamentalPos - plane2.xy, plane2.zw)) < strokeWeight || abs(dot(fundamentalPos - plane3.xy, plane3.zw)) < strokeWeight) { continue; } if(t < 10.) { int tile = getTile(int(xIndex), int(yIndex)); sum += computeColor(tile, fundamentalPos, vec3(0.4), vec3(1, 0, 0), vec3(1)); } else if(t < 10.5){ g_currentLine = -15; int tile = getTileRandom(int(xIndex), int(yIndex)); sum += computeColor(tile, fundamentalPos, vec3(0.4), vec3(1, 0, 0), vec3(1)); } else if(t < 11.){ g_currentLine = -15; int tile = getTileRandom2(int(xIndex), int(yIndex)); sum += computeColor(tile, fundamentalPos, vec3(0.4), vec3(1, 0, 0), vec3(1)); } else if(t < 11.5){ g_currentLine = -15; int tile = getTileRandom16ms(int(xIndex), int(yIndex)); sum += computeColor(tile, fundamentalPos, vec3(0.4), vec3(1, 0, 0), vec3(1)); } else { int tile = getTile16ms(int(xIndex), int(yIndex)); sum += computeColor(tile, fundamentalPos, vec3(0.4), vec3(1, 0, 0), vec3(1)); } } vec3 col = (sum/SAMPLE_NUM); fragColor = gammaCorrect(vec4(col, 1.)); }