LoginSignup
27
19

More than 5 years have passed since last update.

レイマーチング-modで複製した物体に乱数のパラメータを与える-

Last updated at Posted at 2017-10-22

はじめに

今回レイマーチングで作りたいのはこういうやつ
 2017-10-22 12.08.54.png
ランダムな高さを持った直方体を複製してやるぞ〜といった感じです
コードはGLSLです

作り方

まず思いついた方法が,物体をmod()を使って複製してやる
-> 個々の物体の高さに座標を引数とした乱数を設定してやる

みたいな感じで作ろうと思いました,いけそう

やってみた

    float boxDistFunc(vec3 p,vec3 b,vec3 c){
        return length(max(abs(p-c)-b,0.0));
    }
    float floorDistFunc(vec3 p){
        vec3 q=p;
        q.xz=mod(p.xz,1.0)-0.5;
        return boxDistFunc(q,vec3(0.4,0.4,0.4),vec3(0.0,0.0,0.0));
    }
    float distFunc(vec3 p){
        return floorDistFunc(p);
    }

まずこれが単純に物体を複製した状態

 2017-10-21 1.44.26.png
要はmodをレイの先端の座標に噛ませてやることでxz座標に関して-0.5~0.5までが延々繰り返されるっていう感じですね,なので原点に置いた一片が0.4*2=0.8の立方体がいっぱい出てる感じです

でこの中で最終的に使ってる距離関数がfloorDistFuncで,その中で呼び出してるboxDistFuncの第二引数が立方体の一片になるので,ここを弄ればいけるだろうと

    float random(vec2 p){
        return fract(sin(dot(p.xy,vec2(12.9898,78.233)))*43758.5453123)*2.0-1.0;
    }
    float boxDistFunc(vec3 p,vec3 b,vec3 c){
        return length(max(abs(p-c)-b,0.0));
    }
    float floorDistFunc(vec3 p){
        vec3 q=p;
        q.xz=mod(p.xz,1.0)-0.5;
        return boxDistFunc(q,vec3(0.4,abs(random(floor(p.xz))),0.4),vec3(0.0,0.0,0.0));
    }
    float distFunc(vec3 p){
        return floorDistFunc(p);
    }

 2017-10-21 1.45.45.png

あれれ〜〜〜おかしいぞ〜〜〜〜〜??

ぐちゃぐちゃやないか,原型とどめてない
ということでこれを解決してみましたっていうお話です

原因

要はレイが貫通しちゃってる状態なんですねあれは
当たるべき場所で当たってなくて,そのまま突き進んじゃうのであんな感じになっちゃうわけです

でその原因なんですが,図にしてみるとわかりやすかったです

普通になんの乱数も与えず複製した場合

 2017-10-22 12.56.19.png

こういう感じでレイが進んでいます
ここで気をつけなければいけないのは,modを使って物体を複製しているのですが,あくまでmodはレイの先端座標に使っているということです
物体自体を予めいっぱい作っているわけではないので,レイの先端座標を進める際に現在レイが位置している格子中の物体以外の影響を受けていません

問題の場合

 2017-10-22 12.56.29.png

こういうことが起きちゃうってことですね

解決策

上の様な場合はレイを距離関数から返された値そのまま進めるのではなく,次の格子に突入するまでだけ進めるっていう方法をとりました
 2017-10-22 12.56.38.png

以下コードです

        float distance=0.0;
        float rLen=0.0;
        vec3 rPos=origin;
        vec3 color=vec3(0.1);
        for(int i=0;i<100;i++){
            distance=distFunc(rPos);
            if(abs(distance)<0.01){
                if(distance==floorDistFunc(rPos)){
                    color=vec3(0.3,0.3,0.7);
                  }
                 break;
            }

            float t1=(1.0-fract(rPos.z))/ray.z;
            vec3 d1=rPos+t1*ray;
            float t2=(1.0-fract(rPos.x))/ray.x;
            vec3 d2=rPos+t2*ray;
            float t3=(-fract(rPos.x))/ray.x;
            vec3 d3=rPos+t3*ray;
            float t4=(-fract(rPos.z))/ray.z;
            vec3 d4=rPos+t4*ray;
            if(ray.z>0.0 && d1.x>=floor(rPos.x) && d1.x<=floor(rPos.x)+1.0 && abs(distance)>=length(t1*ray)){
                rLen+=length(t1*ray)+0.01;
            }else if(ray.x>0.0 && d2.z>=floor(rPos.z) && d2.z<=floor(rPos.z)+1.0 && abs(distance)>=length(t2*ray)){
                rLen+=length(t2*ray)+0.01;
            }else if(ray.x<0.0 && d3.z>=floor(rPos.z) && d3.z<=floor(rPos.z)+1.0 && abs(distance)>=length(t3*ray)){
                rLen+=length(t3*ray)+0.01;
            }else if(ray.z<0.0 && d4.x>=floor(rPos.x) && d4.x<=floor(rPos.x)+1.0 && abs(distance)>=length(t4*ray)){
                rLen+=length(t4*ray)+0.01;
            }else{
                rLen+=distance;
            }
            rPos=origin+rLen*ray;
        }

追記
コメント欄にありますが,gaziya5さんがもっとスッキリした書き方にまとめてくださっています
詳しくはコメント欄を見ましょう!

まとめ

物体をmodを使って複製した後に個々の高さを乱数で設定してみました
なんかゴリ押し感強くてもっといい方法とかいくらでもありそうですが初心者なりに色々考えたので記事にしてみました
もっとこうしたほうがいいぞ!ってご意見あればお気軽にお願いします

今回のコードの全貌はこちらにあります
https://github.com/ukeyshima/randomHeight

27
19
5

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
27
19