Ray Marching Part 2 : DE演算とCSG


レイMarchingについての私の前のポストでは、レイMarchingが何であるか、そして、あなたがGLSLでそれの基本的な実現をする方法について話しました.まだ読んでいない場合は、このコードを再利用するので、少なくともこれを実行してください.


この部分では、我々はより多くの距離推定器、これらの距離推定量を操作するいくつかの操作を追加し、より複雑なシーンにDESを結合する方法を学びます.
それ以上のADOなしで、始めましょう!
どのように図形を組み合わせることを学ぶことによって簡単に起動しましょう.ご存知かもしれませんが、3つの基本的なブール演算があります.

これらを利用するには、複数のオブジェクトを追加する方法が必要です.このためには、複数のDEを使用できるようにするシーンDEを作成することができます.最初に関数を作成します.
// IMPORTANT: In Shadertoy this MUST be put after both the DEs and the operators. idk if it's the same for normal OpenHL
float sceneDE(vec3 pos) {
    return sphereDE(pos, vec3(0,0,0), 1.0);
}
そして、この行をmarch() 関数(異なる変数名を使用したかもしれません):
float _distance = sphereDE(current_pos, vec3(0.0), 1.0);
そして、それを使用するように変更sceneDE() :
float _distance = sceneDE(current_pos);
Boolean関数を作成する準備が整いました.
組合は最も簡単ですので、始めましょう.新しい関数を作成します.opUnion :
// a and b are interchangeable
float opUnion(float a, float b) {
    return min(a,b);
}
よく見ると、この機能は基本的にはmin() . 我々がこの機能を定義している唯一の理由はコードがより理解できるようにすることです.
今我々はそれを追加することによってそれを試してみることができますsceneDE() !
float sceneDE(vec3 pos) {
    return opUnion(
        sphereDE(pos, vec3(0,1,1), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}
あなたが正しくそれをした場合は、右側のお互いの隣に2つの球を参照してくださいする必要があります!
次は差分演算子を加えてみましょう.今回は私たちはmax() 機能
// a and b are NOT interchangeable
float opDiff(float a, float b) {
    return max(-a, b);
}
調整sceneDE() 差分演算子を使用するには、次の手順に従います
float sceneDE(vec3 pos) {
    return opDiff(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}
最後に、交差点演算子を追加できます.ユニオンのように信じられないほど簡単です
// a and b are interchangeable
float opIntersect(float a, float b) {
    return max(a,b);
}
使用します.
float sceneDE(vec3 pos) {
    return opIntersect(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        sphereDE(pos, vec3(0,0,0), 1.0)
    );
}
今、私たちは3つの基本的な論理演算子を持っています!Here's a shader showcasing all three of them.
これまで我々は、我々の場面をつくるために、球以外何も使いませんでした.私は、我々がスパイスものにもう一つのデをもたらした時間についてであると思います.あなたが見るならばthis page (RayMarchingのためのリファレンスへの私の試み)球の後の次のデは箱のためのDEです.しかし、箱のためのもう一つのものも、オプションの丸い端であります.柔軟性のために、私たちはそれを使います.
// Original from here: https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
float roundBoxDE( vec3 p, vec3 b, float r) {
    vec3 q = abs(p) - b;
    return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;
}
これは翻訳が組み込まれていないので、翻訳操作を行います.
vec3 opTranslate(vec3 pos, vec3 moves) {
    return pos - moves;
}
ああ!これで、シーンdeでこれらをすべて使用できます.
float sceneDE(vec3 pos) {
    float u = opUnion(
        sphereDE(pos, vec3(-2.5,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(-2.5, -1.0, -1.5)), vec3(0.75,0.75,0.75), 0.0)
    );
    float d = opDiff(
        sphereDE(pos, vec3(0,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(0.0, 0.0, 0.0)), vec3(1.0,1.0,1.0), 0.0)
    );
    float i = opIntersect(
        sphereDE(pos, vec3(2.5,-1,-0.5), 1.0),
        roundBoxDE(opTranslate(pos, vec3(3.0, -0.0, 0.7)), vec3(1.0,1.0,1.0), 0.0)
    );
    return min(u,min(d,i));
}
Here's what it should look like!
再び、私の指は非常に疲れていると私は私がする必要がある他のものを持っているので、私はここでそれを残すつもりです.