LoginSignup
14

More than 5 years have passed since last update.

自分用のレイマーチングチートシートを作ってみた。

Last updated at Posted at 2017-01-16

初心者ながらいきなりレイマーチングは難しい…

レイマーチングをするにあたって、いきなり書こうとすると、何を書けばいいかわからないので、以前受けた、GLSLスクール2016 のサンプルコードから、自分用のチートシートを作ってみました。

というか

頭では、分かっていても体がついてこない…
ということで、とにかく基本に公式的なものを自分で作ってみました。

というか…

サンプルコードとほぼ変わらないですが…

  • 図形の距離関数を書く
  • 法線を定義
  • カメラワークを定義
  • レイが進む処理
  • レイとオブジェクトの衝突処理を書く

の流れだけを書き出してみました。

/*
*******************************************************************************
レイマーチングチートシート
*******************************************************************************
*/

/* 精度修飾子の宣言 */
precision mediump float;

/* WebGLで受け渡された変数 */
// 解像度 (512.0, 512.0)
uniform vec2  resolution;
// mouse (-1.0 ~ 1.0)
uniform vec2  mouse;
// time (1second == 1.0)
uniform float time;
// previous scene texture
uniform sampler2D prevScene;


/* 距離関数の定義 */
float dGraphic01(vec3 p){
    // ここに図形の距離関数を書く
    return length(p) - 0.5;
}
float dGraphic02(vec3 p){
    // ここに図形の距離関数を書く
    return length(p) - 0.5;
}
// 二つの図形を合成するの距離関数
float distanceHub(vec3 p){
    // 二つの図形の描く距離関数を書く
    return min(dGraphic01(p), dGraphic02(p));
}

/* シェーディング */
// 法線の生成
vec3 genNormal(vec3 p){
    float d = 0.001;
    return normalize(vec3(
        distanceHub(p + vec3(  d, 0.0, 0.0)) - distanceHub(p + vec3( -d, 0.0, 0.0)),
        distanceHub(p + vec3(0.0,   d, 0.0)) - distanceHub(p + vec3(0.0,  -d, 0.0)),
        distanceHub(p + vec3(0.0, 0.0,   d)) - distanceHub(p + vec3(0.0, 0.0,  -d))
    ));
}
// シェーディング(色など)
vec3 doColor(vec3 p){
    float e = 0.001;
    // レイとオブジェクトの距離を確認
    if (dGraphic01(p)<e){
        // 法線を算出
        vec3 normal = genNormal(p);
        // ライトベクトルの定義(マウスの影響を受けるように)
        vec3 light  = normalize(vec3(1.0, 1.0, 1.0));
        // ライトベクトルとの内積を取る
        float diff  = max(dot(normal, light), 0.1);
        return vec3(diff, diff, diff);
        // スペキュラーを定義する
        // float spec = pow(diff*diff, 15.0);
        // return vec3(diff+spec, diff+spec, diff+spec);
    }
    // 衝突しなかった場合はそのまま黒
    return vec3(0.0);
}

/* カメラのワーク */
void main(){
    // スクリーンスペースを考慮して座標を正規化
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);

    /* カメラを定義 */
    // カメラの位置
    vec3 cPos         = vec3(0.0,  0.0,  3.0);
    // カメラの向き(視線)
    vec3 cDir         = vec3(0.0,  0.0, -1.0);
    // カメラの上方向
    vec3 cUp          = vec3(0.0,  1.0,  0.0);
    // 外積を使って横方向を算出
    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 = distanceHub(rPos);
        rLen += dist;
        rPos = cPos + ray * rLen;
    }

    // レイとオブジェクトの距離を確認
    vec3 color = doColor(rPos);
    gl_FragColor = vec4(color, 1.0);
}

ほぼコピペですが…

gazou.PNG

これをもとに明日から、レイマーチングの記事を書こうと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14