Processingで万華鏡を作ってみた

高井です。

夏といえば夏休み。夏休みといえば自由研究。
自由研究気分で万華鏡を作ってみます。

使う言語は[こちら](https://qiita.com/pesysyon/items/cfb25e2bc3fbf731a5b0)で紹介したProcessingです。

やってみよう！！！

## 万華鏡の仕組み
### 参考サイト１
ニコン キッズアイランド「万華鏡のしくみを学ぼう」
https://www.jp.nikon.com/company/corporate/sp/kids/kaleidoscope/

まさに夏休みの自由研究でできそうな工作が紹介されています。
透明な筒にビーズを入れて周りを鏡で三角形に囲むことで、簡単な万華鏡が作れるみたいです。

### 参考サイト２
ナゾロジー「万華鏡はどうやって美しい幾何学模様を作るのか？秘密は三角形の角度！」
https://nazology.net/archives/130704

パンダの絵が鏡映しになっているイメージ図が分かりやすいです。
鏡は三角形が好ましいみたいです。

### プログラミング方針
上記２サイトを踏まえ、ざっくりした方針を決めました↓
・ビーズクラスを作る
・位置や色が異なるビーズオブジェクトを大量に作る
・三角形のエリアに、大量生成したビーズを描画する
・隣にはそれを左右反転した三角形を、上下には上下反転した三角形を描画する

## 先駆者
なんと先駆者がいました！
https://github.com/abekzk/kaleidoscope

こちらのソースコードを参考にさせていただきました。

## 万華鏡作ってみた
ということでできたのがこちらです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/3532c267-e2f4-439b-0d0a-1fe621dc8c2b.gif" width="40%"> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780649/86be31d4-458a-eb7e-9384-0708806fc8e6.gif" width="40%">

※録画の都合でカクカクしています…すみません

## ソースコード
### main.pde
```java
Ball[] balls = new Ball[50]; // ビーズ50個
Mirror[] mirrors = new Mirror[6]; // 鏡6枚
PGraphics texture; // 鏡に反射させる、元の絵（ビーズを描画するエリア）

void setup(){
 size(600, 600, P2D);
 
 // ビーズ初期化
 for(int i = 0; i < 50; i++){
   balls[i] = new Ball();
 }
 
 // テクスチャ初期化
 texture = createGraphics(600, 600);
 
 // 鏡初期化
 for(int i = 0; i < 6; i++){
  mirrors[i] = new Mirror(i, texture);
 }
}

void draw(){
 background(0);
 
 // ビーズを描画する（元の絵になる）
 drawTexture();
  
 // 元の絵を反射した鏡を描画する 
 for(Mirror mirror:mirrors){
  mirror.display();
 }
 
 // 録画のためこのフレームを保存
 saveFrame("frames/####.png");
}

// 毎フレーム、ビーズ描画
void drawTexture(){
 texture.beginDraw();
 
 texture.background(255);
 
 // ビーズをゆっくり回転させる
 texture.translate(texture.width / 2, texture.height / 2);
 texture.rotate(radians(millis()) / 50 % 360);
 
 for(Ball ball:balls){
  texture.shape(ball.shape, ball.x - texture.width / 2, ball.y - texture.height / 2);
 }
 
 texture.endDraw();
}
```
### Ball.pde
```java
// ビーズクラス
class Ball {
 PShape shape; // 形（丸、三角形、四角形）
 int x;
 int y;
 int size;
 color c;
 
 Ball(){
  // 位置、サイズ、色をランダム生成
  this.x = int(random(600));
  this.y = int(random(600));
  this.size = int(random(30, 60));
  this.c = color(int(random(256)), int(random(256)), int(random(256)), int(random(256)));
  
  // 形をランダム生成
  int type = int(random(3));
  if(type == 0){
   shape = createShape(ELLIPSE, 0, 0, size, size);
  }else if(type == 1){
   shape = createShape(RECT, 0, 0, size, size); 
  }else if(type == 2){
    shape = createShape(TRIANGLE, 0, 0, size, 0, size/2, size);
  }
  
  shape.setFill(c);
  shape.setStroke(false);
 }
}
```

### Mirror.pde
```java
// 鏡クラス
class Mirror{
  PShape pShape; //描画する三角形
  
  Mirror(int mirrorNum, PGraphics texture){
   int r = 150;                                       // 鏡のサイズ
   int rad = 90 + 60 * mirrorNum;                     // 鏡の角度
   int  x = int(width / 2 + r * cos(radians(rad)));   // 鏡のx座標
   int  y = int(height / 2 + r * sin(radians(rad)));  // 鏡のy座標
   
   textureMode(NORMAL);
   pShape = createShape();
   pShape.beginShape();
   
   // 三角形に元の絵を貼り付ける設定
   pShape.texture(texture);
   
   // 三角形の縁をグレーで描画
   pShape.stroke(200);
   
   // 三角形の頂点の座標を描画する
   for(int i = 0; i < 3; i++){
    float theta = radians(60 * mirrorNum - 90 + 120 * i);
    float thetaTexture = radians(-90 + 120 * i);
    
    if(mirrorNum % 2 == 1){
      // 奇数枚目ならテクスチャをそのまま貼り付ける
      pShape.vertex(x + r * cos(theta), y + r * sin(theta), (cos(thetaTexture) + 1) * 0.5, (sin(thetaTexture) + 1) * 0.5);
    }else{
      // 偶数枚目ならテクスチャを反転して貼り付ける
      pShape.vertex(x + r * cos(theta), y + r * sin(theta), 1 - (cos(thetaTexture) + 1) * 0.5, (sin(thetaTexture) + 1) * 0.5);
    }
   } 
   
   pShape.endShape(CLOSE);
  }
  
  // 毎フレーム、三角形を描画する
  void display(){
   shape(pShape); 
  }
}
```

## ポイント
**こだわりポイント**
・半透明のビーズ（カワイイ）
・最終的に記事にするので、ソースコードを簡潔に書く

**今後の改良ポイント**や**簡潔なソースコードのため断念したこと**
・ビーズをぼんやり光らせたい（より"万華鏡"感ある見た目の研究）
・ハートとか星型とか、ビーズの形を増やしたい
・鏡が6枚しかないので、敷き詰めたい

以上、高井でした:art: