光線行進パート1:光線追跡の容認できないいとこ


光線追跡


我々はすべて242479152、ここでは、各ピクセルの光線を撮影し、再帰的にそれをバウンスし、色のピクセルを使用して空想の数学を使用してください.あなたがすべてのピクセルのためにこのプロセスを繰り返すならば、あなたは才能のあるアーティストによって作られた場合、実際の生活からほとんど区別できないように見えることができるシーンの素敵なレンダリングを得ることができます.
ray tracing
残念なことに、光線追跡は若干の欠点を持っています.つのフレームはレンダリングするために時間を取ることができます.そして、それは彼らの創造主が最もレンダリングされる非常に強力なコンピュータを持っているので、アニメ映画のためにすばらしいかもしれません、しかし、彼らが通常彼ら自身に巨大なレンダルファームを持っていない時から、それは愛好家のための全く迷惑です.
しかし、別のです.

レイマーチング


レイマーチングを入力します:光線追跡の容認されないいとこ.
レイマーチングはレイトレースに非常に似ていますが、それはそれがリアルタイムのグラフィックスのデモやゲームのための興味深いオプションを作るいくつかの興味深いquirksを持っています.
まず、レイマーチングはラスタ化やレイトレーシングの代替ではないことに注意してください.
ああ!始めましょう.

動作方法


レイのマーチングは、私が以前に述べたように、レイトレースによく似ています.違いは光線が彼らのベクトルに沿って光線を行進して、それから光線を行進するまでどれくらい遠くまで決定するか、または、それがオブジェクトと交差しているならば、距離方程式を使用するということです.それから、我々はそれを交替した位置のような行進機能からものを返すことができます.

実装方法


あなたがそれがどのように動くかを知っている今、実際に光線マーチャーを作りましょう.GLSLを使用するので、OpenGLを設定するか、 のようなものを使う必要があります.あなたが沿って続くように感じないならば、ここにShadertoyです
まず第一に、遮光物の上部にいくつかのものが必要です.
#version 420
// you can change #version if you want to
// the resolution, set to the window's dimensions.
uniform vec2 resolution;
// uncomment if you are going to implement a movement system
//uniform vec3 camPos;
最も簡単な部分、距離推定器から始めましょう.具体的には、球体のde :
float sphereDE(vec3 pos, vec3 spherePos, float size) {
    return length(pos - spherePos) - size;
}
これは超簡単でかなり自己説明的であるので、私は本当にそれを説明しません、しかし、他のDESがこれより複雑であると心に留めておいてください.あなたは球のような感じていない場合は他の図形のcode on Shadertoyよりもあなたのためです.
今、我々は実際の行進を行うマーチング機能を書くことができます!
vec3 march(vec3 origin, vec3 direction) {
    float rayDist = 0.0;
    const int NUM_STEPS = 32; // doesn't matter much right now
    const float MIN_DIST = 0.001; // threshold for intersection
    const float MAX_DIST = 1000.0; // oops we went into space

    for(int i = 0; i < NUM_STEPS; i++) {
        vec3 current_pos = origin + rayDist*direction;

        // Use our distance estimator to find the distance
        float _distance = sphereDE(current_pos, vec3(0.0), 1.0);

        if(_distance < MIN_DIST) {
            // We hit an object! This just adds a subtle shading effect.
            return vec3(rayDist/float(NUM_STEPS)*4.0);
        }

        if(rayDist > MAX_DIST) {
            // We have gone too far
            break;
        }

        // Add the marched distance to total
        rayDist += _distance;
    }
    // The ray didn't hit anything so return a color (black, for now)
    return vec3(0.0);
}
今、我々は主な機能を除いてRayMarchに必要なすべてを持っています.
書きましょう
void main( out vec4 fragColor, in vec2 fragCoord ) {
    // normalized coordinates, resolution should be the window/screens pixel dimensions.
    vec2 uv = fragCoord / resolution.xy * 2.0 - 1.0;
    uv = uv / vec2(0.6, 1.0);

    // camPos can be a uniform if you want to move around
    vec3 camPos = vec3(0.0, 0.0, -3.0);
    vec3 rayDir = vec3(uv, 1.0);

    // march!
    vec3 shaded_color = march(camPos, rayDir);

    // set the color!
    fragColor = vec4(shaded_color, 1.0);
}
そして、我々はされます!一度これらをまとめると、微妙にエッジに向かって軽くなる円を見ることができるはずです.

ここで大きなリストです 改善


我々がちょうど作ったものが涼しくて、すべてであった間、それはそれほど刺激的でありません.それは単調で鈍いです、そして、球以外のそれにそれほど多くありません.
私たちはコールドのために構造体を作ります.それから、あらゆる種類の有用な値を返すことができます.
struct Ray {float distance; vec3 endPos; float minDist; bool hit;};
だから私の最後のバージョンです.
const int NUM_STEPS = 32; // doesn't matter much right now
const float MIN_DIST = 0.001; // threshold for intersection
const float MAX_DIST = 1000.0; // oops we went into space

struct Ray {float totalDist; float minDist; vec3 endPos; bool hit;};

// The distance estimator for a sphere
float sphereDE(vec3 pos, vec3 spherePos, float size) {
    return length(pos - spherePos) - size;
}

Ray march(vec3 origin, vec3 direction) {
    float rayDist = 0.0;
    float minDist = MAX_DIST;

    for(int i = 0; i < NUM_STEPS; i++) {
        vec3 current_pos = origin + rayDist * direction;

        // Use our distance estimator to find the distance
        float _distance = sphereDE(current_pos, vec3(0.0), 1.0);

        minDist = _distance < minDist ? _distance : minDist;

        if(_distance < MIN_DIST) {
            // We hit an object!
            return Ray(rayDist, minDist, current_pos, true);
        }

        if(rayDist > MAX_DIST) {
            // We have gone too far
            break;
        }

        // Add the marched distance to total
        rayDist += _distance;
    }
    return Ray(MAX_DIST, minDist, origin + rayDist * direction, false);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord / iResolution.xy * 2.0 - 1.0;

    // scale the ra
    uv = uv / vec2(0.6, 1.0);

    vec3 camPos = vec3(0.0, 0.0, -3.0);
    vec3 rayDir = vec3(uv, 1.0);

    Ray marched = march(camPos, rayDir);

    vec3 color = marched.hit ? 
        vec3(marched.totalDist/pow(float(NUM_STEPS), 0.8)*4.0) : // shading
        vec3(0.0) + vec3(pow(clamp(-1.0 * marched.minDist + 1.0, 0.0, 1.0), 4.0) / 2.0); // glow

    fragColor = vec4(color,1.0);
}

無限の他の追加の色のようにすることができます、CSG(の間のブール演算)、またはより多くの図形を再生するには.しかし、私の指は本当に疲れているので、ここで止まるつもりです.
私も非常に彼のゲームは、レイマーチングとかなりフラクタルで作られた見てお勧めします.