CG関連

【GLSL(シェーダー)】波のつくり方簡易まとめ。波もプログラムでつくれます【コピペスタイル】

プログラミングでかっこいい映像をつくりたいと始めた『GLSL』。

関連記事

いろんなサイトを見ているうちに、
同じようなコードをよく見かけるようになりました。

それは『波』

英語だと『Wave』。
『波』は文字通り水を表すこともあれば、

  • 電波
  • 音波
  • 振動
  • 波動
  • 波紋
  • 地震波
  • 波形
  • 津波

などなど、いろんな自然現象にも『波』という漢字が使われています。

現実世界でも『波』の理論を使うことで、

  • 携帯電話(スマホ)
  • パソコン
  • デジカメ
  • ラジオ
  • 地震
  • 音響ホールの設計
  • 声紋分析
  • 音声圧縮
  • 画像圧縮
  • CTスキャン

などなど、いろんな技術に使われています。

穏やかな『波』と激しい『波』。
規則的な『波』とガヤガヤした不規則な『波』。
1つの『波』があればいくつかの『波』が混ざることもあり。

アオキ
どうやら『波』を使いこなせればかなり表現の幅が広がるらしい・・

と思い、いろいろググっていると、

どうやら学術的には『フーリエ解析』なるものを使いこなせればいいようなのですが、

試しに読んでみたところ、

アオキ
これはさすがにさくっと理解はできないで・・マジメな理系大学生さんのシロモノやで・・

となってしまったので、

『コピペ』ありきで『波』を表現しつつ、後から理論を調べることにしてみました。

アオキ
動いてなんぼですからね、まずは動かすことに専念しとこ。(開き直り)
Sponsored link

『波』のつくり方 プログラミングで温泉をつくったらしい

早稲田の学生さん?がプログラミングで『温泉』をつくったそうで、
こちらの記事を参考にしています。

湯を沸かすほどの熱いGLSL

完成画像はこちら。

アオキ
も、もはや温泉にしか見えない・・・っ!

リンク先の記事でわかりやすく?つくり方が載っていたので、
記事の補足という形でメモしていきます。

さっそく完成版のコード。

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;

//===================================
// ・ランダム / ノイズ / 非整数ブラウン運動
//   https://thebookofshaders.com/13/?lan=jp
//===================================

//ランダム関数 
float random (in vec2 p) { 
    return fract(sin(dot(p.xy,vec2(12.9898,78.233)))*43758.5453123);
}

//ノイズ関数 
float noise (in vec2 p) {
    vec2 i = floor(p);
    vec2 f = fract(p);
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

// FBMを定義
#define OCTAVES 4
float fbm (in vec2 p) {
    float value = 0.0;
    float amplitud = 0.2;
    float frequency = .9;
    for (int i = 0; i < OCTAVES; i++) {
        value += amplitud * noise(p);
        p *= 2.0;
        amplitud *= 0.8;
    }
    return value;
}

//===================================
// ・距離関数
// http://iquilezles.org/www/articles/distfunctions/distfunctions.htm
//===================================

float dSpring(vec3 p) {
    vec3 n = normalize(vec3(0.0, 1.0, 0.0));

    // 複数の非整数ブラウン運動を重ね合わせて、不規則っぽい揺らぎにする
    float s = fbm(vec2(p.x, length(p * 1.5) - u_time * 1.25) * .075);
    float t = fbm(vec2(p.x, length(p * 2.5) - u_time * 2.75) * .125);
    float u = fbm(vec2(p.x, length(p * 3.5) - u_time * 0.75) * .075);
    float v = s + t + u;
    return dot(p, n) + v;
}

//===================================
// ・法線の取得
// https://wgld.org/d/glsl/g010.html
//===================================

vec3 genNormal(vec3 p) {
    float d = 0.001;
    return normalize(vec3(
        dSpring(p + vec3(  d, 0.0, 0.0)) - dSpring(p + vec3( -d, 0.0, 0.0)),
        dSpring(p + vec3(0.0,   d, 0.0)) - dSpring(p + vec3(0.0,  -d, 0.0)),
        dSpring(p + vec3(0.0, 0.0,   d)) - dSpring(p + vec3(0.0, 0.0,  -d))
    ));
}

//===================================
// ・メイン関数
//===================================

void main() {
    // 色の宣言
    vec3 spring = vec3(0.9, 0.9, 0.6);

    // colorの初期化
    vec3 color = vec3(0.0);

    // 座標の正規化(range: -1.0 ~ 1.0)
    vec2 p = (gl_FragCoord.xy * 2.0 - u_resolution) / min(u_resolution.x, u_resolution.y);

    // カメラのセッティング
    vec3 cPos = vec3(0.0,  3.0,   6.0);     // カメラの位置(GLSLおじさんの立ち位置)
    vec3 cDir = vec3(0.0,  -1.0,  -1.0);        // カメラの注視点(GLSLおじさんの視点)
    vec3 cUp  = vec3(0.0,   0.5,   1.0);    // カメラの上方向(GLSLおじさんの頭上)
    vec3 cSide = cross(cDir, cUp);          // 外積を使って横方向を算出
    float targetDepth = 1.0;                // 深度

    // レイの生成
    vec3 ray = normalize(cSide * p.x + cUp * p.y + cDir * targetDepth);

    // レイマーチングループ
    float dist = 0.0;   // レイと穴の距離
    float rLen = 0.0;   // レイの長さ
    vec3  rPos = cPos;  // レイの先端
    for (int i = 0; i < 32; i++) {
        dist = dSpring(rPos);
        rLen += dist;
        rPos = cPos + ray * rLen;
    }

    // 衝突判定で色の出しわけ
    if (abs(dist) < 0.001) {
        vec3 normal = genNormal(rPos);  // 物体の法線情報を取得
        vec3 light = normalize(vec3(sin(u_time), 1.2, 0.0));    // ライトの位置
        float diff = max(dot(normal, light), 0.1);  // 拡散反射光を内積で算出

        vec3 eye = reflect(normalize(rPos - cPos), normal);
        float speculer = pow(clamp(dot(eye, light), 0.0, 1.0) * 1.025, 30.0);   // 反射光を算出

        color = (spring + speculer) * diff;
    } else {
        color = vec3(0.0);
    }

    // 最終的に該当ピクセルに出力する色
    gl_FragColor = vec4(color, 1.0);
}

theBookOfShaders.comなどにコピペすれば動きます。

コメント内にいくつか外部リンクがあったので、

それらのページも読みつつまとめて見ることにしました。

『波』をつくるために知っておきたい知識 『三角関数』

まず大前提として、

『波』をつくるためには『三角関数』が必要になります。

『三角関数』は『円』で考えるとわかりやすいです。

参考記事

『円』の半径が1とすると、サイン(sinθ)の場合、

  • 0度・・0
  • 90度・・1
  • 180度・・0
  • 270度・・-1
  • 360度・・0

という規則で変化して、『波』のような動きをします。

『サインウェーブ』と言ったりします。

コサイン(cosθ)の場合は下記になります。

  • 0度・・1
  • 90度・・0
  • 180度・・-1
  • 270度・・0
  • 360度・・1

これらの値を変えたり合成したりなんやかんやして、

きれいな『波』から不規則な『波』に変えていくことができます。

なめらかに動かすとこんな感じになります。

ちなみに角度は『ラジアン』で渡す必要があります。

参考記事

『波』をつくるために知っておきたい知識 『波』は合成できる

『フーリエ解析』に絡んでくるのですが、

複雑な『波』は、実はいくつかのシンプルな『波』を足し合わせてできているそうです。

アオキ
うーん、なんで?

と思ってしまうんですが、調べだすときりがないのでいったんは飲み込むことに。

2019/7/22追記
『高校生からわかるフーリエ解析』という本の中のグラフを見て、あぁそうかと納得しました。

グレーの線が3本ともプラスなら、青の線もグイーンとプラスに伸びて、
グレーの線がプラスマイナス混ざっていたら、青の線は微妙な幅になっています。

アオキ
波を足し合わせると面白い動き方が表現できるんですね。

先ほどのコードの中でも、いくつかの『波』を足し合わせているのがわかります。

    //ノイズ関数
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    vec2 u = f * f * (3.0 - 2.0 * f);
    return mix(a, b, u.x) + (c - a)* u.y * (1.0 - u.x) + (d - b) * u.x * u.y;

 〜中略〜

    // 複数の非整数ブラウン運動を重ね合わせて、不規則っぽい揺らぎにする
    float s = fbm(vec2(p.x, length(p * 1.5) - u_time * 1.25) * .075);
    float t = fbm(vec2(p.x, length(p * 2.5) - u_time * 2.75) * .125);
    float u = fbm(vec2(p.x, length(p * 3.5) - u_time * 0.75) * .075);
    float v = s + t + u;

ノイズ関数は、
a波、b波、c波、d波をつくって最終的に全部足してます。

下の段のコードも、
s波、t波、u波をつくって、

v波 = s波 + t波 + u波 と3つの『波』を足し合わせた『v波』をつくっています。

Sponsored link

『波』をつくるために知っておきたい知識 ランダム・ノイズ・FBM

オリジナルの『波』表現をするためには、
下記3つを使いこなすといいようです。

  • ランダム
  • ノイズ(パーリンノイズ)
  • FBM(Fractal Browniam Motion)非整数ブラウン運動

外部リンクはこちら。
ランダム
ノイズ
セルラーノイズ
非整数ブラウン運動

実際に値を変えて『波』が変わっていくのを体感できるサイトになっています。

アオキ
このサイトめっちゃ勉強になります・・

詳細は外部リンク先に譲りつつ、

サンプルコードでは、ランダム関数、ノイズ関数、FBM関数は外部リンクの内容そのまま使われています。

アオキ
ランダム、ノイズ、FBMの3点セットは他のコードでもしょっちゅう目にするので、とりあえずコピペ+調整で扱い慣れていこうと思います。

サンプルコードでは、他の技術として、

  • レイマーチング・・レイ(光)をあてて物体にあたったら画面に描写する手法
  • 法線ベクトル・・光の反射。偏微分で計算。
  • 距離関数・・物体との距離を計算する。物体の形によってさまざま。

なども使われています。

参考記事

特に『距離関数』はひねりが必要で、ぱっと把握は難しいので、時間を作ってゆっくり理解しなきゃなと思っています。

『波』をつくる方法 まとめ

学生時代ろくに勉強してなかった身としては、

『フーリエ解析』をしっかり理解するにはまだまだ時間がかかりそうですが、

幸いしっかり動いているプログラミングコードがあるので、

外部リンクの記事も参考にしつつ、

  • 三角関数
  • ランダム
  • ノイズ(パーリンノイズ)
  • FBM(非整数ブラウン運動)

あたりの知識をちょっとずつ脳みそになじませて、

数ヶ月後にはしっかり使いこなせるようになりたいなと思っております。

アオキ
ずっと数式解くだけだと挫折してたかも。やっぱり動かしつつ把握していくスタイルの方が楽しいし向いていると思いますわ。
created by Rinker
ベレ出版
¥2,200 (2024/10/10 10:14:00時点 Amazon調べ-詳細)

『GLSL(シェーディング)』関係ではこんな記事も読まれています。

1. 【GLSL】プログラムでかっこいい映像をつくりたい! 〜『TouchDesigner』を見据えて

2. 【WebGL】入門 わかりやすく【図解】してみた

3. 【OpenGL】と【DirectX】のバージョンをまとめてみた【シェーダーメイン】【初心者向け】

4. 【GLSL(シェーディング)】でよく使う関数とユーザー関数のまとめ※随時更新

5. 【GLSL】プログラムでかっこいい映像をつくるには『レイマーチング』なるものを覚えればいいらしい

6. 【GLSL】『レイマーチング』入門その1 距離関数とレイとカメラの設定

7. 【GLSL】『レイマーチング』入門(2) 立体的に見せる方法〜光の反射は『内積』で〜

8. 【GLSL】『レイマーチング』入門(3) 距離関数を使ってみる・回転・合成・量産

9. 【TouchDesigner】で『GLSL』を使う方法まとめ【画像あり】

10. 【TouchDesigner】『GLSL MAT』の使い方 3次元でぐりぐり動かしてみる

11. 【GLSL】波のつくり方簡易まとめ。波もプログラムでつくれます【コピペスタイル】

アオキ
ツイッターでも記事ネタ含めちょろちょろ書いていくので、よろしければぜひフォローお願いしますm(_ _ )m

アオキのツイッターアカウント


関連記事一覧 (一部広告あり)

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

CAPTCHA


最近の記事

アーカイブ

  1. バックエンド

    【Laravel第4弾】Vue.js3(CompositionAPI+Scrip…
  2. 生成AI

    Dify講座をリリースしました【非エンジニア向け】
  3. データベース

    MySQLの講座をリリースしました
  4. オンライン教材

    【ChatGPT】エンジニア編をリリースしました
  5. オンライン教材

    【React】初心者向け講座をリリースしました【MUI】【Udemy】
PAGE TOP
Ads Blocker Image Powered by Code Help Pro

広告ブロックを摘出しました!!

ブラウザ拡張を使用して広告をブロックしていることが摘出されました。

ブラウザの広告ブロッカーの機能を無効にするか、
当サイトのドメインをホワイトリストに追加し、「更新」をクリックして下さい。

あなたが広告をブロックする権利があるように、
当方も広告をブロックしている人にコンテンツを提供しない権利と自由があります。

Powered By
100% Free SEO Tools - Tool Kits PRO