レイトレを始めたいのでお勉強。 1.レイのむき

前回レイの定義をしましたが、あのレイはz軸正方向を向くレイでしかなく、つまりはカメラの向きがz軸正方向に限られるということになってしまいます。

 

そこで、レイを回転することで任意の方向を向くカメラを実現したいと思います。回転手法には様々ありますが、今回はロドリゲスの回転公式による回転で実現したいと思います。

 

ロドリゲスの回転公式は、クオータニオンによって導かれるある軸周りの回転を、複素数計算部分をうまく整理することで実行列計算のみで実現する回転公式です。

 

https://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%89%E3%83%AA%E3%82%B2%E3%82%B9%E3%81%AE%E5%9B%9E%E8%BB%A2%E5%85%AC%E5%BC%8F

 

これによってレイの向きを回転させ、カメラの向きを再現します。

レイトレを始めたいのでお勉強。 1.レイの定義

 レイトレを始めたいのでまずはレイの定義をしたいと思います。

レイトレはいろんな手法があるみたいで、それによってレイの定義も様々あるのかもしれませんが、最も基本的なレイを考えたいと思います。

 

レイの定義には様々あると思いますが、まずは最もプリミティブな表現を考えます。

カメラの座標を(0,0,0)として、ある点(a,b,c)を通るような光を考えます。このときのレイの方向は(a,b,c)-(0,0,0)でそのまま(a,b,c)になります。

 

f:id:nilgiri-sgt:20190420134916p:plain

 

もしz= cの位置に,面xyに平行にスクリーンを置いたとすれば、このときのレイはスクリーン上のa,bを通ってくれるわけです。

 

このスクリーンとカメラの距離によって視野角があとから決められます。なので、このようなレイの定義をすると、スクリーン上の点(x,y)を描画するのに使うレイは

 

ray = normalize vec3 (screen.x,scree.y,D)

 

となります。このときDの値は任意に与えることができて、これによって視野角が変わってきます。

 

 

これに対して視野角を予め決めてやる方法もあります。このときは視野角を決めることによってカメラとスクリーンの位置が定まります。視野角を2θとしましょう(半分の角度を使うと計算が楽なので)。すると、スクリーンの幅に対してカメラの位置が決まります。

 

f:id:nilgiri-sgt:20190420140645p:plain

スクリーンの幅がr sin(θ)に対して、r cos(θ)だけ後ろにカメラをおけば視野角2θでスクリーンを写すことができるというわけです。長方形スクリーンのときは横の長さを基準にするのが普通な気がします。

 

さて、この位置にカメラを置いたとしてスクリーンの任意の位置(a,b)を通るようなレイの定義は、スクリーンの座標が -1 から 1 を取りうるとすれば、

 

r sin(θ) = 1

であるため、r = 1/sin(θ)

ゆえに、カメラの座標はスクリーンが(0,0,0)を中心にすると考えると、

 

(0,0,-cos(θ)/sin(θ))

 

ここでカメラ位置からスクリーンの任意の位置(a,b,0)へのベクトルは引き算して

 

(a,b,cos(θ)/sin(θ))

 

形を整えて規格化すれば

 

normalize( vec3( a*sin(θ),b*sin(θ),cos(θ) ) )

 

になります。次回はカメラの向いている向きによってレイの方向を変えることを考えてみたいと思います。

 

ABC 119 C Synthetic Kadomatsu

合成したりなんだりで規定の値を得る問題。
今回は本数がたったの八本だったので全列挙を考える。C問くらいまでは全列挙できるのも多いのでまずは全列挙を疑うべきですね。
全列挙の方法にはbit全列挙を選択。使わない、Aに使う、Bに使う、Cに使うの4状態がそれぞれについて考えられるので、2bit×N桁を用意してそれについて全列挙です。
下位桁を3と&を取ることで、どこに使うかという状態を取得しています。また、接合回数も考える必要があるので、これを記録する配列を確保。
このとき{-1,-1,-1}という配列を用意して、それぞれをA,B,Cに使った本数とすると0以上のとき10*それぞれの値で接続コストが求められるのでこの実装です。

尚、1本も使わない0の状態から伸ばしては行けないというのを見落としていたので、その処理を後からぶちこんでいてちょっと汚いです。


int main(void){
    int N,A,B,C;
    scanf("%d %d %d %d",&N,&A,&B,&C);
    vector<int> l;
    for (int i =0; i < N; ++i){
        int temp;
        scanf("%d",&temp);
        l.push_back(temp);
    }

    long long ans = 100000000000000000000;

    for (int i = 0; i < pow(4,N); ++i){
        vector<int> temp(3,0);
        vector<int> joint(3,-1);
        int copy = i*1;
        for (int j = 0;j<N;++j){
            int s=0;

            s += copy&3;
            copy = copy >> 2;
            if (s==0){
                continue;
            }else{
                temp[s-1]+=l[j];
                joint[s-1]+=1;
            }
        }
        if (temp[0]==0||temp[1]==0||temp[2]==0){
            continue;
        }
            int cost =0;
            cost += abs(A-temp[0]);
            cost += abs(B-temp[1]);
            cost += abs(C-temp[2]);

            for (int k = 0; k <3; ++k){
                if (joint[k] > 0){
                    cost += joint[k]*10;
                }
            }
            if (cost < ans){
                ans = cost;
            }

    }
    cout << ans << endl;

};