CG関連

【GLSL(シェーダー)】『レイマーチング』入門その1 距離関数とレイとカメラの設定

かっこいい『3Dプログラミング』をつくりたいと
ググって見つけた『レイマーチング(Ray Marching)』という手法。

参考記事

いろいろググるとなかなか難しいようなので、

まずは先輩方のソースコードを真似てみることからやってみることにしました。

早速Youtubeでぴったりな動画を発見。

アオキ
ありがたやありがたや。

りやちゃんというVtuber?女性キャラクターなのに、
コード書いている人は思いっきり男性という謎な世界観を完全スルーし、

ただひたすらに『レイマーチング(Ray Marching)』のコードの書き方を真似てみました。

Sponsored link

『レイマーチング』入門〜まずは2D設定

動画冒頭から、2Dのコードが記載されていて、
別の動画で解説されてはいるものの、
ハズキルーペよろしく、

アオキ
コードの文字サイズが小さすぎて読めないっ!

っとなってしまったので、とりあえずコピペしてスタートすることにしました。

2D初期のコードはこちら。

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time; //時間
uniform vec2 mouse; //マウス位置
uniform vec2 resolution; //解像度
    
void main( void ) {
    vec2 pos = ( gl_FragCoord.xy * 2.0 - resolution) / max(resolution.x, resolution.y); //現在の画素位置を0.0-1.0に正規化
    vec2 mouse_pos = (mouse - 0.5) * 2.0;
    mouse_pos.y *= resolution.y / resolution.x;
    
    gl_FragColor = vec4(pos, 0.0, 1.0); //最終的な色の描画
    
}

このコードをGLSLオンラインエディタにコピペすればOKです。

GLSL Sandbox

『レイマーチング』入門〜距離関数

『レイマーチング(Ray Marching)』は、
各オブジェクトまでの距離を測って描画するという仕組みで、
図形ごとに『距離関数』なるものが決まっています。

球の場合はこれ。

// 1. 球の距離関数
float sphere_d(vec3 pos){
    return length(pos) - 2.0; // 原点にある位置ベクトルから半径を引くと算出できる
}
アオキ
なぜにこれで球が表示できるの?

っと思ってしまいますが、
きっと証明するには時間がかかりそうなので、

走りながら考えるスタイルで、今回はスルーする事にします。

他にもたくさんの距離関数があって、組み合わせることもできます。(こちらも別記事で書く予定です)

距離関数のサイト

Sponsored link

『レイマーチング』入門〜始点の位置 (カメラの位置)

つぎに『カメラ』の位置と向き。

2次元の時は全く意識しないのですが、

3次元の場合、奥行きが存在するので、

『カメラ』の位置も考える必要がでてきます。

  • 手前で撮るか
  • 奥から撮るか
  • 斜め上から撮るか
  • 右側から撮るかなど

現実世界と同じように、カメラの位置を自由に変えることができます。

今回の動画で紹介されていたコードはこちら。

//2. 始点の定義 (カメラの姿勢が定まる
 vec3 camera_pos = vec3(0.0, 0.0, -4.0); //カメラの位置
 vec3 camera_up = vec3(0.0, 1.0, 0.0);  //カメラの上向きベクトル
 vec3 camera_dir = vec3(0.0, 0.0, 1.0); //カメラの前向きベクトル
 vec3 camera_side = cross(camera_up, camera_dir); //カメラの横向きベクトル (上向きベクトルと前向きベクトルの外積

vec3というのは文字通り、3次元ベクトルです。

3次元なのでX軸、Y軸、Z軸の3つの値を持ちます。

アオキ
ベクトルは、矢印というよりただの数字の組み合わせと思った方が使いやすいと思います。

参考記事

カメラの横向きベクトルは、
上向きベクトルと前向きベクトルの『外積(がいせき)』で求まるそうで、

アオキ
『外積』・・ってなんだったっけ・・

と思いつつも、走りながら後でリサーチする事にします。

『レイマーチング』入門〜レイの定義 構造体

続いて、光源という意味の『レイ(Ray)』の設定。

コードはこちら。

//3. Rayの定義 (構造体)
struct Ray{
    vec3 pos; //Rayの現在の座標
    vec3 dir; //Rayの進行方向
};

structなので『構造体』でつくっています。

構造体は、名前は難しそうですが、要は変数の組み合わせです。

今回は 『レイの位置』『レイの向き』をそれぞれ『3次元ベクトル』で定義しています。

要は、
『レイの位置』と『レイの向き』それぞれ、

X, Y, Z の3つの値を持つという事になります。

Sponsored link

『レイマーチング』入門〜レイの設定

先ほど作成した『レイ』の構造体を実体化しつつ、

『レイの位置』と『レイの向き』の値を設定します。

// 4. Rayの設定
Ray ray; //ここはインスタンスか
ray.pos = camera_pos; //Rayの初期位置
ray.dir = normalize(pos.x * camera_side + pos.y * camera_up + camera_dir); // Rayの進行方向はカメラの姿勢から求めることができる

X・・レイのX軸 × カメラの横向き
Y・・レイのY軸 × カメラの上向き
Z・・カメラの前向き

としているようです。

アオキ
なぜにX、Y、Zとも足し算するんだろう(内積(ないせき?)

と思いつつ、とりあえず次へ。

『レイマーチング』入門〜レイの衝突判定

『レイマーチング(Ray Marching)』は、
『距離関数』で『オブジェクト(物体)』までの距離を測定しながら前に進み、
『オブジェクト(物体)』との距離がほぼゼロになったら描画するという仕組みになっています。

コードはこちら。

// 5. Rayの判定
float t = 0.0, d;
for (int i = 0; i < 64; i++ ){ //何回でもok 十分な数
    d = sphere_d(ray.pos); //距離関数から現在の距離を求める
    if (d < 0.001) {  //計算できた距離が十分に0に近かったら
        break; //衝突したという判定
    } 
        t += d; //当たらなかったら
        ray.pos = camera_pos + t * ray.dir; //rayの座標更新 どれだけrayを進めるかというと最も近いオブジェクトまでの距離(突き抜け防止
    }

まず t (時間)をゼロにして、
『距離関数』でオブジェクト(物体)との『距離』を求めて、

『距離』が限りなくゼロに近づいたら衝突したという判定にして、

そうでなければ『レイ』を前に進めています。

アオキ
こちらもまずはこんなもんかで先に進みます。
Sponsored link

『レイマーチング』入門〜レイが物体に衝突したら

最後に、『レイ』が当たったら、白に色を変えます。

    //6. あたったら色を変える
    if (d < 0.001) {
        gl_FragColor = vec4(1);
    } else {
        gl_FragColor = vec4(0);
    }

gl_FragColorは色つけの組み込み関数です。

vec4として、RGBA 4つの値を持つことができます。

RGBAだと普通 0〜255の範囲になりますが、

GLSLは0 〜 1 の範囲設定になるので、

『正規化』などの手順が必要になります。

アオキ
『正規化』の解説もいずれ・・

今回のコードをまとめるとこうなります。

#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

// 1. 球の距離関数
float sphere_d(vec3 pos){
    return length(pos) - 2.0; // 原点にある位置ベクトルから半径を引くと算出できる
}

//3. Rayの定義 (構造体)
struct Ray{
    vec3 pos; //Rayの現在の座標
    vec3 dir; //Rayの進行方向
};

    
void main( void ) {
    
    vec2 pos = ( gl_FragCoord.xy * 2.0 - resolution) / max(resolution.x, resolution.y); //現在の画素位置を0.0-1.0に正規化
    vec2 mouse_pos = (mouse - 0.5) * 2.0;
    mouse_pos.y *= resolution.y / resolution.x;
    
    //2. 始点の定義 (カメラの姿勢が定まる
    vec3 camera_pos = vec3(0.0, 0.0, -4.0); //カメラの位置
    vec3 camera_up = vec3(0.0, 1.0, 0.0);  //カメラの上向きベクトル
    vec3 camera_dir = vec3(0.0, 0.0, 1.0); //カメラの前向きベクトル
    vec3 camera_side = cross(camera_up, camera_dir); //カメラの横向きベクトル (上向きベクトルと前向きベクトルの外積

    // 4. Rayの設定
    Ray ray; //ここはインスタンスか
    ray.pos = camera_pos; //Rayの初期位置
    ray.dir = normalize(pos.x * camera_side + pos.y * camera_up + camera_dir); // Rayの進行方向はカメラの姿勢から求めることができる

    // 5. Rayの判定
    float t = 0.0, d;
    for (int i = 0; i < 64; i++ ){ //何回でもok 十分な数
        d = sphere_d(ray.pos); //距離関数から現在の距離を求める
        if (d < 0.001) {  //計算できた距離が十分に0に近かったら
            break; //衝突したという判定
        } 
        t += d; //当たらなかったら
        ray.pos = camera_pos + t * ray.dir; //rayの座標更新 どれだけrayを進めるかというと最も近いオブジェクトまでの距離(突き抜け防止
    }

    //6. あたったら色を変える
    if (d < 0.001) {
        gl_FragColor = vec4(1);
    } else {
        gl_FragColor = vec4(0);
    }
    
    
    
}

GLSL Sandboxに貼り付けて、白い円が表示されたらOKです。

GLSL Sandbox

アオキ
こんな感じで表示されたらOK。

『レイマーチング』入門 その1 まとめ

『レイマーチング(Ray Marching)』の手法自体が独特なこともあり、

まだまだ細かいところまで調べきれていないのですが、

アオキ
とりあえず動けばOK、後で調べる=3

のスタンスで、ガリガリ書いていこうかなと思います。

『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. 生成AI

    Dify講座をリリースしました【非エンジニア向け】
  2. バックエンド

    【Laravel第4弾】Vue.js3(CompositionAPI+Scrip…
  3. オンライン教材

    【React】初心者向け講座をリリースしました【MUI】【Udemy】
  4. オンライン教材

    【AWS】【初心者向け】インフラの基礎からわかる講座をリリースしました【Udem…
  5. 生成AI

    2024/5/14 OpenAI発表 まとめ
PAGE TOP
Ads Blocker Image Powered by Code Help Pro

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

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

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

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

Powered By
Best Wordpress Adblock Detecting Plugin | CHP Adblock