4次元スペースレーサー

Titlepic



最近、3次元シーンの簡単なレイトレーサーを作成しました。 JavaScriptで書かれており、それほど高速ではありませんでした。 興味のために、Cでレイトレーサーを作成し、4次元レンダリングモードにしました。このモードでは、4次元シーンをフラットスクリーンに投影できます。 カットの下には、いくつかのビデオ、いくつかの写真、レイトレーサーコードがあります。







4次元シーンを描画するために別のプログラムを作成する理由は何ですか? 通常のレイトレーサーを使用して4Dシーンをスリップし、面白い画像を取得できますが、この画像は画面上のシーン全体の投影ではありません。 問題は、シーンに4つの次元があり、画面が2つしかないことです。レイトレーサーが画面から光線を発射すると、3次元の部分空間のみをカバーし、4次元のシーンの3次元セクションのみが画面に表示されます。 簡単なアナロジー:3次元のシーンを1次元の線に投影してみてください。



2次元の視覚を持つ3次元の観察者は、4次元のシーン全体を見ることができないことがわかります。せいぜい、彼は小さな部分しか見ることができません。 3次元の視覚を持つ4次元のシーンを見る方が便利であると仮定することは論理的です:ある4次元の観察者が何らかのオブジェクトを見て、3次元の投影が網膜の3次元の類似物に形成されます。 私のプログラムはこの3D投影を評価します。 言い換えると、私のレイトレーサーは、4次元の観察者が3次元の視覚で見るものを描写しています。



3次元ビジョンの特徴





目の前にある紙の円を見ていると想像してください。この場合、円が表示されます。 この円をテーブルに置くと、楕円が表示されます。 この円を遠くから見ると、小さく見えます。 同様に3次元ビジョンの場合、4次元のボールは3次元楕円体として観察者に表示されます。 以下にいくつかの例を示します。 最初に、4つの同一の相互に垂直なシリンダーが回転します。 次に、4次元の立方体のフレームが回転します。









Cube4d



反射に移りましょう。 反射面のあるボール(クリスマスツリーのおもちゃなど)を見ると、反射は球の表面に描かれているように見えます。 また、3次元ビジョンの場合:4次元のボールを見ると、反射が表面にあるかのように描かれます。 4次元のボールの表面のみが3次元になったため、ボールの3次元投影を見ると、反射は表面ではなく内側になります。 ラスタートレーサーがビームを発し、ボールの3D投影と最も近い交差点を見つけると、黒い円が表示されます-3D投影の表面は黒になります(これは、フレネルの公式による)。 次のようになります。



ReflectionFirstHit



3次元ビジョンの場合、これは問題ではありません。彼にとっては、この3次元ボール全体が見え、内部ポイントと表面のポイントが見えるからです。しかし、この効果を何らかの方法でフラットスクリーンに伝える必要があります。レイトレーサーの追加モードを作成しました。3次元オブジェクトが煙のようであると考えた場合、ビームはそれらを通過し、徐々にエネルギーを失います。 次のようになります。



画像







同じことが影にも当てはまります。影は表面に落ちるのではなく、3次元の投影内に落ちます。 3次元のボールの内部(4次元のボールの投影)に、このキューブがボールに影を落とすと、4次元の立方体の投影の形で暗くなった領域があることがわかります。 この効果をフラットスクリーンで伝える方法はわかりませんでした。



最適化





4次元のシーンを評価することは、3次元よりも困難です。4Dの場合、平坦ではなく、3次元領域の色を見つける必要があります。 レイトレーサーを「額」と書くと、その速度は非常に遅くなります。 1000×1000の画像のレンダリング時間を数秒に短縮できる簡単な最適化がいくつかあります。



このような写真を見るときに最初に目を引くのは、たくさんの黒いピクセルです。 レイトレーサーの光線が少なくとも1つのオブジェクトに当たる領域を描くと、次のようになります。



地図



約70%が黒いピクセルであり、白い領域が接続されている(4次元シーンが接続されているため接続されている)ことがわかります。 ピクセルの色を順不同で計算できますが、1つの白いピクセルを推測して塗りつぶします。 これにより、白いピクセルと、白い領域の1ピクセルの境界を表すいくつかの黒いピクセルのみをトレースできます。



2番目の最適化は、ボールと円柱の図が凸であるという事実から得られます。 これは、そのような図の任意の2点について、それらを結ぶ線分も完全に図の内側にあることを意味します。 点Aがオブジェクトの内側にあり、点Bが外側にあるときに、光線が凸面のオブジェクトを横切る場合、側面Bからの光線の残りはオブジェクトと交差しません。



さらにいくつかの例





ここで、立方体は中心の周りを回転します。 キューブボールは接触しませんが、3次元投影では交差できます。







このビデオでは、立方体は静止しており、4次元の観測者が立方体の中を飛びます。 大きく見えるその3次元の立方体は観測者に近く、小さいものはさらに遠くにあります。







以下は、軸1-2と3-4の平面での古典的な回転です。 この回転は、2つのギブンズ行列の積によって定義されます。







レイトレーサーの仕組み





コードはANSI C 99で記述されていますここからダウンロードできます。 ICC + WindowsおよびGCC + Ubuntuでテストしました。



このプログラムは、シーンの説明が入力されたテキストファイルを受け取ります。



scene = { objects = -- list of objects in the scene { group -- group of objects can have an assigned affine transform { axiscyl1, axiscyl2, axiscyl3, axiscyl4 } }, lights = -- list of lights { light{{0.2, 0.1, 0.4, 0.7}, 1}, light{{7, 8, 9, 10}, 1}, } } axiscylr = 0.1 -- cylinder radius axiscyl1 = cylinder { {-2, 0, 0, 0}, {2, 0, 0, 0}, axiscylr, material = {color = {1, 0, 0}} } axiscyl2 = cylinder { {0, -2, 0, 0}, {0, 2, 0, 0}, axiscylr, material = {color = {0, 1, 0}} } axiscyl3 = cylinder { {0, 0, -2, 0}, {0, 0, 2, 0}, axiscylr, material = {color = {0, 0, 1}} } axiscyl4 = cylinder { {0, 0, 0, -2}, {0, 0, 0, 2}, axiscylr, material = {color = {1, 1, 0}} }
      
      







次に、この説明を解析し、内部表現でシーンを作成します。 スペースの次元に応じて、シーンをレンダリングし、上記の例の4次元画像または通常の3次元画像を受け取ります。 4次元レイトレーサーを3次元に変換するには、vector.hファイルでvec_dimパラメーターを4から3に変更する必要がありますが、コンパイラーのコマンドラインパラメーターでも設定できます。 GCCでのコンパイル:



cd /home/ username /rt/

gcc -lm -O3 *.c -o rt









テスト実行:



/home/ username /rt/rt cube4d.scene cube4d.bmp









vec_dim = 3でレイトレーサーをコンパイルすると、cube3d.sceneシーンの通常のキューブが生成されます。



ビデオはどのように作られましたか





これを行うために、フレームごとに回転行列を計算して参照シーンに追加するスクリプトをLuaで作成しました。



 axes = { {0.933, 0.358, 0, 0}, -- axis 1 {-0.358, 0.933, 0, 0}, -- axis 2 {0, 0, 0.933, 0.358}, -- axis 3 {0, 0, -0.358, 0.933} -- axis 4 } scene = { objects = { group { axes = axes, axiscyl1, axiscyl2, axiscyl3, axiscyl4 } }, }
      
      







グループオブジェクトには、オブジェクトのリストに加えて、軸と原点の2つのアフィン変換パラメーターがあります。 軸を変更すると、グループ内のすべてのオブジェクトを回転できます。



次に、スクリプトはコンパイルされたレイトレーサーを呼び出しました。 すべてのフレームがレンダリングされると、スクリプトはmencoderを呼び出し、個々の写真からビデオを収集しました。 ビデオは、オートリピートをかけられるような方法で作成されました。 ビデオの終わりは始まりと一致します。 スクリプトは次のように実行されます。



luajit animate.lua









そして最後に、 このアーカイブには 4つのaviファイル1000×1000があります。 それらはすべて周期的です-自動リピートに置くと、通常のアニメーションが得られます。



All Articles