【夏休みの自由研究】ついに完成!「万華鏡」(第5回)

第1回の「とりあえず遊んじゃおう!完成版コード」を覚えていますか?

これは、世界のクリエイターを熱狂させた Kishimisuさん の魔法です。
これまでの第1回〜第4回を通ってきた今のキミなら、もう読み解けるはず!

今日は、今まで準備してきた「色のバケツ」と「コピー機」を組み合わせて、
「光を輪っかにする魔法」と「奥行きを出す魔法」をトッピングします。

スポンサーリンク

光を「輪っか」にする(波の魔法)

[ 光る点 ] float d = length(q);
float strength = 0.01 / d;

中心が一番まぶしい、普通の星だね。

[光る輪っか ] float d = length(q);
d = sin(d * 8.0 + u_time) / 8.0;
d = abs(d);
float strength = 0.01 / d;

なぜ「輪っか」になるの?(波の折り返し術)

「1本の線」が「キラキラの輪」に変わる3つの変化を見てみよう!

1 sin で「なみ」を作る
d = sin(d * 8.0) / 8.0;

中心からの距離を「なみ(〰)」をつくる「sinマシン」に入れます。すると、数字は「1 ➔ 0 ➔ -1 ➔ 0 ➔ 1」と、上がったり下がったりを繰り返します。

2 abs で「谷」を「山」にひっくり返す
d = abs(d);

ここがポイント! abs(絶対値)を使うと、マイナス(谷)だった部分がプラス(山)にはね返ります。これで、地面(0)にぶつかってはね返るような、鋭い「Vの字」がたくさんできます。

3 「0」の場所を光らせる
float strength = 0.01 / d;

さいごに「0.01 ÷ d」をします。dが0に近い場所(Vの字の底)だけが、爆発するようにまぶしく光ります。この「0」の場所が円状に並んでいるので、きれいな「光の輪っか」に見えるんです!

💡「ボールを地面に何度もバウンドさせてみて!ボールが地面(0)についた瞬間だけ、パチッ!と火花が散る場所が円の上にあるから、きれいな輪っか模様ができるんだよ。」

「かける」と「わる」のコンビネーション魔法

d = sin(d * 8.0) / 8.0 ; のナゾを解こう!

かける(* 8.0)
🪗|||||||🪗

「輪っかの数」をふやす!
アコーディオンをギュッと押しつぶして、しましまを細かく増やすよ。

わる(/ 8.0)
👉

「線の太さ」をふっくらさせる!
波の傾きをゆるやかにして、光がじわ〜っと広がる「太い輪っか」にするよ。

🤔 なぜわり算で太くなるの?:
このあとの 0.01 / d は、d0 に近いほど明るくなる 魔法。
あらかじめ波をペチャンコ(/ 8.0)にしておくと、d がなかなか 0 から離れない「ゆるやかな坂道」になるんだ。

➔ だから、光がすぐに消えずに「ふっくらとした太い線」になって、きれいに見えるんだよ!

最初は、コピーを1回だけ
for (float i = 0.0; i < 1.0; i++) で、輪っかを作ってみよう!

void main() {
  vec2 uv = vTexCoord * 2.0 - 1.0;
  uv.x *= u_resolution.x / u_resolution.y;
  vec2 uv0 = uv;

  vec3 finalColor = vec3(0.0);

  // ループを1回だけに変更
  for (float i = 0.0; i < 1.0; i++) {
    vec3 col = palette(length(uv0) + i * 0.4 - u_time);
    uv = fract(uv *  3.0) - 0.5;
    vec2 q = uv + i * 0.1;
 
    float d = length(q);

    // この2行を追加
    d = sin(d * 8.0 + u_time) / 8.0;
    d = abs(d);
   
    float strength = 0.01 / d;


    strength *= abs(sin(u_time + i));
    finalColor += col * strength;
  }

  gl_FragColor = vec4(finalColor, 1.0);
}

expマシンで奥行きを出そう

exp(イー・エックス・ピー)は、数学の世界では「指数関数」と呼ばれる、ちょっと強そうな名前の持ち主。 でも難しく考えなくてOK!シェーダーの世界では、「数字をものすごい勢いで大きくしたり、小さくしたりするマシン」だと思ってね

今回は、画面の真ん中をライトで照らすイメージだよ。
真ん中はまぶしいけど、ちょっと離れると暗くするんだ。

マイナス(➖)は「爆発」を「消滅」にかえるスイッチ

🚀 マイナスなし:exp(x)

💥

中心から離れるほど、数字が爆発!
画面のハシっこが真っ白に!

🌌 マイナスあり:exp(-x)

🌌

中心から離れるほど、数字が消滅!
ハシっこが闇に吸い込まれるよ。

💡 つまり、どうすればいい?
画面の真ん中をライトで照らすように、中心をまぶしく、ハシを暗くしたいなら……
マシンの設定に「マイナス(➖)」をガチャン!と入れればいいんだね。

expマシンをつかってみよう

「どこに」×「いつ」魔法をかけるかが、隠し味だよ!

📍 住所は「uv0」をえらぼう

fract で切り刻む前の住所 uv0 を使います。

なぜ?: タイル1枚ずつじゃなく、「画面全体」に大きな霧をかけたいからだよ!

⏳輪っかをつくる前(sinの前)にかけよう

形が決まる前の d に、expマシンを合体させます。

なぜ?: 形ができた後に暗くするんじゃなくて、「粘土の形そのもの」をグニャリと歪ませて、奥行きを出したいからだよ!
// 1. 粘土をこねる
float d = length(q);

// 「uv0」を使って、「sinの前」に魔法をかける
d *= exp(-length(uv0));

// 2. そのあとで、しましま(sin)にする
d = sin(d * 8.0 + u_time) / 8.0;

👨‍🔬実験:万華鏡のカスタマイズ!

次は数字を自由にいじって「自分の好きな」を「万華鏡」探してみよう。

いじる場所 魔法の効果 おすすめの数字
for (float i = 0.0; i < 1.0; i++)
i < 4.0 程度
万華鏡の密度 4.0 〜 8.0
uv = fract(uv * 3.0) - 0.5;
uv * 1.5 程度
タイルの数 1.2 〜 2.5
✅ ヒント:
数字を大きくしすぎると画面がチカチカして目が疲れちゃうから、少しずつ変えて「ここだ!」というポイントを見つけてね。

「なんかゴチャついてる?」と思ったらよね😅

☝️最後の仕上げ:ここを変更するのがポイント

「なんかゴチャついてる?」と思ったら、この魔法の出番だよ。

たくさんの「光の輪っか」をどう並べるか、考えてみよう!

❶ バラバラに置く(ずらす)

⭕️ ⭕️ ⭕️

「床に散らばったドーナツ」
ひとつひとつの形は見やすいけど、奥行きは感じられないね。

uv + i * 0.1

❷ 重ねて置く(そろえる)

「棒に通したドーナツ」
真ん中をそろえて重ねると、奥まで続く「トンネル」に見えてくるよ!

length(uv)


ループの回数を増やしたあと、この1行を書き換えてみて!

// 住所をずらすのをやめて・・・
vec2 q = uv + i * 0.1;
float d = length(q);

// タイルの真ん中(uv)をそのまま使う!
float d = length(uv);
今回は、たくさんの光がピッタリ同じ場所で重なり合うほうが綺麗だね!

「pow」のヤスリがけで光をみがく

「ぼんやりした光」を「キラリと鋭い光」に変える魔法だよ!

🕯️

そのまま(powなし)
光が外側までボヤ〜っと広がっていて、少しねむたい感じ。

💎

pow を使うと!
弱い光はバッサリ削られ、中心の強い光だけが「シュッ!」と細く残るよ。

// 0.01 / d を 1.2乗(ちょっとだけ鋭く)する!
float strength = pow(0.01 / d, 1.2);
🤔 なぜ鋭くなるの?:
pow(x, 1.2) は「xを1.2回かけ算してね」という意味。
大きい数字(中心の光)は、かけ算しても大きいまま
小さい数字(ハシっこの弱い光)は、かけ算するともっともっと小さくなる!
この「格差」が生まれることで、光が鋭く見えるんだよ!
void main() {
  vec2 uv = vTexCoord * 2.0 - 1.0;
  uv.x *= u_resolution.x / u_resolution.y;
  vec2 uv0 = uv;

  vec3 finalColor = vec3(0.0);

  for (float i = 0.0; i < 4.0; i++) {
    vec3 col = palette(length(uv0) + i * 0.4 - u_time);
    uv = fract(uv *  1.5) - 0.5;
 
    float d = length(uv);
    d *= exp(-length(uv0));
    d = sin(d * 8.0 + u_time) / 8.0;
    d = abs(d);
   
    float strength = pow(0.01 / d, 1.2);
    strength *= abs(sin(u_time + i));

    finalColor += col * strength;
  }

  gl_FragColor = vec4(finalColor, 1.0);
}

おまけ:Palette(パレット)関数のカスタマイズ

Palette(パレット)関数の(a, b, c, d の数字を入れ替えてみよう!)

🚀 世界中の魔法使いが使っている「色の一覧表」はこちら!

👉 パレットの神様(Inigo Quilez)のサイトを見る
コピーする数字(a, b, c, d) 色のイメージ
a(0.5, 0.5, 0.5), b(0.5, 0.5, 0.5),
c(1.0, 1.0, 1.0), d(0.00, 0.33, 0.67)
🌈 ザ・虹色(Rainbow)
💡 ヒント: サイト内の画像をみて「これだ!」と思った横にある数字を、同じように当てはめるだけでOKだよ!

🎓CONGRATULATIONS!

全5回の冒険、本当にお疲れさまでした!

最初はただの真っ黒な画面だったかもしれない。でも、もうキミは数学を使って、画面の中に自分だけの作品を生み出す方法を知っています。

OpenProcessing という世界中のクリエイターが集まるギャラリーで公開できるよ!

やりかたはカンタン:
① OpenProcessingで新しいスケッチを作る
② 作ったコードをまるごとコピー&ペースト!
③ 「Submit(公開)」ボタンをポチッと押すだけ!

➔ これだけで、キミの作品は世界中の人が見られる「デジタルアート」になるんだよ。

👨‍👩‍👧 保護者の方へ:作品の公開について

OpenProcessingは世界中のクリエイターが集まる安全なコミュニティですが、海外サイトのため、13歳未満のお子様が利用される際は保護者の方によるアカウントの作成・管理を推奨しています。

ぜひ、本名ではなくニックネームを使うなどのSNSマナーを一緒に確認しながら、親子でクリエイティブな世界を楽しんでみてください!

スポンサーリンク