Mesh Art
SF映画・SFアニメなどにありそうなデータ群を近未来的に視覚化したアニメーションです。 複雑そうな動きに見えますが仕組みを説明すると、 球面を細くカットし、色をつけ、回転させているだけです。 これは球面すなわち曲面を作り出すためのテクニックを理解すれば、簡単に実装できます。 球を描画すること自体は、sphere()関数を使うことが最も速いですが、欲しいのは球体の一部分です。 これらの部分的な曲面にアクセスするためには、球を数式で作るところから始めました。 立方体や球、複雑な3次元の立体図形を生成するには、数式を利用するのが最も簡単です。 また立体図形の全ての基礎となるものは、2次元グリットに並べられた点です。 この点が出来上がれば、グリッド上にできた点xとyの値を使い、点zの位置を決めていきます。 球面お方程式は空間座標,ベクトル,極座標といった様々な方法で表すことができますが、processing(というか機械の世界全般)で扱いやすい 三角関数を使った極座標で球を実装します。

x = sin(α)・sin(β)・r;
y = sin(α)・cos(β)・r;
z = cos(α)・r;


出来上がった球面の媒介変数α、βを調整して、球面を細くカットしていきます。 あとはそれらのオブジェクトをどうデザインするかの問題ですが、 オブジェクトの半径rや色を乱数や段階的な透過度・色の変化をつけることにより、近未来風に仕上げました。
		int num = 300;
		ArrayList spheres;

			void setup() {
				size(1280, 720, P3D);

				spheres = new ArrayList();
					for (int i = 0; i < num; i++) {
						addSphere(i);
					}
				}

				void draw() {

					background(0);

					//control camera
					float r = 800;
					float a = frameCount*0.01;
					float b = frameCount*0.01/2;
					float x = sin(a)*cos(b)*r;
					float y = sin(a)*sin(b)*r;
					float z = cos(a)*r;
					camera(x, y, z, 0, 0, 0, 0, 1, 0);

					for (int i = spheres.size()-1; i >= 0; i--) {
						Sphere sp = spheres.get(i);
						sp.update();
						sp.display();
						if (sp.isDead()) {
							spheres.remove(i);
							addSphere(i);
						}
					}
				}

				void addSphere(int i) {
					float len1 = random(PI/(40*noise(i/10) + 10));
					float len2 = random(PI);
					float xmin = random(-PI, PI-len1);
					float ymin = random(-PI/10, PI/10-len2);
					float xmax = xmin + len1;
					float ymax = ymin + len2;
					spheres.add( new Sphere(xmin, xmax, ymin, ymax, map(noise(i/5), 0, 1, 100, 400), i));
				}

				class Sphere {
					float xMin, xMax;
					float yMin, yMax;
					int xCount, yCount;
					float radius;
					PVector[][] points;

					color startColor;
					color endColor;
					color col;

					float angle;
					float randomAngle;

					float velocity;

					float lifespan;
					float lifespeed;

					int id;



					Sphere(float _xMin, float _xMax, float _yMin, float _yMax, float _radius, int _id) {
						xMin = _xMin;
						xMax = _xMax;
						yMin = _yMin;
						yMax = _yMax;

						xCount = 5;
						yCount = 20;
						radius = _radius;

						id = _id;

						points = new PVector[yCount+1][xCount+1];

						startColor = color(204, 102, 0);
						endColor = color(46, 211, 2);
						col = lerpColor(startColor, endColor, map(id, 0, num, 0, 1));

						angle = 0;
						randomAngle = TWO_PI*noise(id/10);

						velocity = random(-0.03, 0.03);

						lifespan = 1;
						lifespeed = random(1, 3);

						init();
					}

					void init() {
						for (int iv = 0; iv <= yCount; iv++) {
							for (int iu = 0; iu <= xCount; iu++) {
								float x = map(iu, 0, xCount, xMin, xMax);
								float y = map(iv, 0, yCount, yMin, yMax);
								points[iv][iu] = new PVector();
								points[iv][iu].x = sin(x)*sin(y) * radius;
								points[iv][iu].y = sin(x)*cos(y) * radius;
								points[iv][iu].z = cos(x) * radius;
							}
						}
					}

					void update() {
						angle += velocity;
						if (lifespan > 255) {
							lifespan = 255;
							lifespeed *= -1;
						}
						lifespan += lifespeed;
						startColor = color(204, 102, 0);
						endColor = color(46, 211, 2);
						col = lerpColor(startColor, endColor, map(id, 0, num, 0, 1));
					}

					void display() {
						fill(col, lifespan);
						stroke(col, 50);

						pushMatrix();
						rotateX(randomAngle);
						rotateZ(angle);

						for (int iv = 0; iv < yCount; iv++) {
							beginShape(TRIANGLE_STRIP);
							for (int iu = 0; iu <= xCount; iu++) {
								vertex(points[iv][iu].x, points[iv][iu].y, points[iv][iu].z);
								vertex(points[iv+1][iu].x, points[iv+1][iu].y, points[iv+1][iu].z);
							}
							endShape();
						}
						popMatrix();
					}

					boolean isDead() {
						if (lifespan < 0) return true;
						else return false;
					}
				}