学生の頃、レイトレーシングのプログラムを組んで、 F1マシンらしき造形の極短いアニメーションを作ったことがありました。
当時の手持ちの環境は98互換機EPSON-286VS。 C言語で書いてTrubo C++でコンパイルして走らせてみたものの、 1枚の絵を描画するのに果てしなく時間がかかる代物。
そこで学校で所属してた熱工学研究室の機材に目をつけて、空いてる時に少々拝借 ;-p)
と言ってもホストPC環境はPC9801RXだったかな? 貧乏研究室だったのでその98に神戸製鋼のトランスピューターボードを挿して、 ボード側で数値計算のプログラムを走らせ、98はI/Oだけを使ってました。
(当時、隣の流体力学の研究室では、Sunのワークステーションがゴロゴロとあって何とうらやましかったことか)
トランスピュータボード付属の「パラレルCコンパイラ」で通るようにプログラムを修正して、 一晩こっそり走らせると視点をグリグリ動かしたアングルで大量の画像ファイルの出来上がり。
画像ファイルをMOディスクに落として後輩のはまちゃんに渡すと、 X68000でパラパラアニメ表示して学園祭で展示してくれました。
そんな懐かしい思い出に浸りつつ、どんなプログラムだったかぼちぼちと思い出してPythonで書いてみます。
今回OpenCVを使いますが、画像ファイルと動画を扱う箇所のimg.pyだけで限定的に使うようにしてます。
あと、一旦ガーっと作ってからバラしてまとめ直して、 さらに一度単純な機能の段階に戻して、再度肉付けして機能を増やしたりして作っていきます。
なので後の段階のために、一見不要な処理が伏線のように出てくるかも知れませんが、あしからず。
レイトレーシングの前にアングルの確認とかしたいので、 プレビュー用にワイヤーフレーム表示から入ってみます。
以前にワイヤーフレームは ワイヤーフレームのプログラム で色々とやってみました。
その反省を踏まえて、ごちゃごちゃし過ぎないように、 一部をPythonに持ってきて、簡単な表示だけから試します。
$ tar xzf rt_v1.tgz $ cd rt $ ls -l -rw-r--r-- 1 kondoh staff 1936 3 16 20:38 ax.py -rwxr-xr-x 1 kondoh staff 1269 3 16 21:06 cg.py -rw-r--r-- 1 kondoh staff 765 3 16 20:38 cylx.py -rw-r--r-- 1 kondoh staff 710 3 16 20:38 fcx.py -rwxr-xr-x 1 kondoh staff 2889 3 16 20:38 img.py -rw-r--r-- 1 kondoh staff 891 3 16 20:38 line.py -rw-r--r-- 1 kondoh staff 685 3 16 20:38 lstx.py -rw-r--r-- 1 kondoh staff 1777 3 16 20:38 mt.py -rw-r--r-- 1 kondoh staff 3351 3 16 20:38 ut.py -rw-r--r-- 1 kondoh staff 1448 3 16 20:38 v.py -rw-r--r-- 1 kondoh staff 1500 3 16 20:38 vecs.py -rwxr-xr-x 1 kondoh staff 2597 3 16 20:38 way.py -rw-r--r-- 1 kondoh staff 2385 3 16 20:50 wf.py $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/wf : $ ls -l out/ | head total 20000 -rw-r--r-- 1 kondoh staff 583325 3 16 21:32 wf.mp4 -rw-r--r-- 1 kondoh staff 32257 3 16 21:31 wf00000.jpg -rw-r--r-- 1 kondoh staff 32474 3 16 21:31 wf00001.jpg -rw-r--r-- 1 kondoh staff 32999 3 16 21:31 wf00002.jpg -rw-r--r-- 1 kondoh staff 32937 3 16 21:31 wf00003.jpg -rw-r--r-- 1 kondoh staff 32903 3 16 21:31 wf00004.jpg -rw-r--r-- 1 kondoh staff 32445 3 16 21:31 wf00005.jpg -rw-r--r-- 1 kondoh staff 30759 3 16 21:31 wf00006.jpg -rw-r--r-- 1 kondoh staff 32098 3 16 21:31 wf00007.jpg
一応、平面と球のつもりです。
ut.py ユーティリティ関数とか mt.py 数学よりな関数とか v.py 3次元ベクトルの処理 line.py 直線 vecs.py 3x3行列関連 ax.py アフィン変換 cylx.py 円筒の変換 fcx.py フォーカスと平面の変換 lstx.py ax cylx fcx の変換を連結、合成して扱う変換 img.py 画像ファイル動画ファイル way.py 視点移動など、時間とともに変化する量や位置を扱う wf.py ワイヤーフレーム描画処理の本体 cg.py データの定義と描画して動画に落とす処理
自己流のクロージャと空クラスの使い方については、 パックマンもどき2017秋 の クロージャと空クラス を参照してください。
レイトレーシングの1発目。 視点から物体までをトレースして、視線と物体の交点を求めます。 物体と交差していれば単純にその物体の色でベタ塗りしてみます。
$ cat v2.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/beta1 div=16 fps=2 $ ls -lt out/ | head total 208 -rw-r--r-- 1 kondoh staff 21681 3 17 19:35 beta1.mp4 -rw-r--r-- 1 kondoh staff 1155 3 17 19:35 beta100019.jpg -rw-r--r-- 1 kondoh staff 1207 3 17 19:35 beta100017.jpg -rw-r--r-- 1 kondoh staff 1164 3 17 19:35 beta100018.jpg -rw-r--r-- 1 kondoh staff 1143 3 17 19:35 beta100015.jpg -rw-r--r-- 1 kondoh staff 1174 3 17 19:35 beta100016.jpg -rw-r--r-- 1 kondoh staff 1314 3 17 19:35 beta100013.jpg -rw-r--r-- 1 kondoh staff 1228 3 17 19:35 beta100014.jpg -rw-r--r-- 1 kondoh staff 1394 3 17 19:35 beta100011.jpg
まずは、解像度を1/16、フレームレート1/15でお試し。
処理するピクセル数は本来の 1/(16*16*15) = 1/3840
それでは意を決してフルサイズでトライ。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/beta2 : wh : 290716/307200(94.6%) : rest 4.82s : 2018/03/18 03:04:20 wh : 294482/307200(95.8%) : rest 3.71s : 2018/03/18 03:04:19 wh : 298262/307200(97.0%) : rest 2.6s : 2018/03/18 03:04:19 wh : 302059/307200(98.3%) : rest 1.49s : 2018/03/18 03:04:19 wh : 305822/307200(99.5%) : rest 0.4s : 2018/03/18 03:04:19 wh : 307200/307200(100.0%) : fin 1m 29.38s frm : 300/300(100.0%) : fin 7h 27m 13.67s $ $ ls -lt out | head total 10584 -rw-r--r-- 1 kondoh staff 153570 3 18 03:04 beta2.mp4 -rw-r--r-- 1 kondoh staff 15780 3 18 03:04 beta200299.jpg -rw-r--r-- 1 kondoh staff 15763 3 18 03:02 beta200298.jpg -rw-r--r-- 1 kondoh staff 15247 3 18 03:01 beta200297.jpg -rw-r--r-- 1 kondoh staff 14890 3 18 02:59 beta200296.jpg -rw-r--r-- 1 kondoh staff 14265 3 18 02:58 beta200295.jpg -rw-r--r-- 1 kondoh staff 13989 3 18 02:56 beta200294.jpg -rw-r--r-- 1 kondoh staff 14135 3 18 02:55 beta200293.jpg -rw-r--r-- 1 kondoh staff 14031 3 18 02:53 beta200292.jpg
7時間半かかってました。
部品のソースコードのメモに追加しておきます。
cross.py 物体と直線の交点を求める処理 rt.py レイトレーシング描画処理の本体
パッチファイルのメモも追加。
v2.patch メモ
レイトレーシングの2発目。 物体の表面で拡散する光の強さを計算して、球体に陰影をつけてみます。 これまでのベタな塗りは周囲光あるいは自発光として扱います。
真上からの照明を1つ用意して、物体表面の法線と照明の入射角で拡散光の強さを決めてます。
v3.patch メモ
$ cat v3.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/diff1 div=16 fps=2
まずは粗い設定で確認。 光が当たる北半球だけ、ほんのり陰影がでました。
では、覚悟を決めてレンダリング開始。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/diff2 : wh : 277377/307200(90.2%) : rest 9.67s : 2018/03/18 19:27:02 wh : 280708/307200(91.3%) : rest 8.58s : 2018/03/18 19:27:02 wh : 284141/307200(92.4%) : rest 7.46s : 2018/03/18 19:27:02 wh : 287539/307200(93.5%) : rest 6.36s : 2018/03/18 19:27:02 wh : 290947/307200(94.7%) : rest 5.25s : 2018/03/18 19:27:02 wh : 294340/307200(95.8%) : rest 4.15s : 2018/03/18 19:27:02 wh : 297750/307200(96.9%) : rest 3.04s : 2018/03/18 19:27:01 wh : 301166/307200(98.0%) : rest 1.94s : 2018/03/18 19:27:01 wh : 304536/307200(99.1%) : rest 0.85s : 2018/03/18 19:27:01 wh : 307200/307200(100.0%) : fin 1m 38.8s frm : 300/300(100.0%) : fin 8h 17m 55.27s
8時間超えました。
レイトレーシングの3発目。 物体の表面で反射する光を計算してみます。
物体表面の交点を新たな視点として、再帰的にトレースして色を求め、 物体の反射率を係数としてかけて反射光を算出します。
再帰の処理が終わらない場合があるので、 反射率を掛け算していって、大元の呼び出しへの影響が小さくなった時点で、 再帰を終わらせるようにしています。
物体表面を新たな視点としてトレースする時、 起点の交点そのものは次の交点の候補から外す処理を追加しています。
v4.patch メモ
$ cat v4.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/reflect1 div=16 fps=2
球体の根元に四角の色が写り込むようになりました。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/reflectc2 : wh : 296056/307200(96.3%) : rest 6.17s : 2018/03/19 10:47:01 wh : 298242/307200(97.0%) : rest 4.95s : 2018/03/19 10:47:01 wh : 300420/307200(97.7%) : rest 3.74s : 2018/03/19 10:47:00 wh : 302607/307200(98.5%) : rest 2.53s : 2018/03/19 10:47:00 wh : 304786/307200(99.2%) : rest 1.33s : 2018/03/19 10:47:00 wh : 306958/307200(99.9%) : rest 0.13s : 2018/03/19 10:47:00 wh : 307200/307200(100.0%) : fin 2m 49.17s frm : 300/300(100.0%) : fin 13h 43m 27.77s
13時間半超え。 四角の平面にも青い球体が写り込んでます。 再帰は時間がかかりますね。
レイトレーシングの4発目。 物体の表面で屈折する光を計算してみます。
反射光の場合とほぼ同様な処理になりますが、 物体表面の交点を新たな視点として、 トレースする向きが物体の内部側へと向かいます。 いわゆるスネルの法則で屈折率を算出するために、 物体の密度の情報を追加してます。
v5.patch メモ
$ cat v5.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/reflact1 div=16 fps=2
なんだか画像が汚い感じになりましたが、 少し球体が透けて屈折して見えてる様子?
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/reflact2 : wh : 298508/307200(97.1%) : rest 12.53s : 2018/03/21 06:32:38 wh : 300056/307200(97.6%) : rest 10.27s : 2018/03/21 06:32:37 wh : 301597/307200(98.1%) : rest 8.03s : 2018/03/21 06:32:35 wh : 303131/307200(98.6%) : rest 5.81s : 2018/03/21 06:32:34 wh : 304676/307200(99.1%) : rest 3.59s : 2018/03/21 06:32:33 wh : 306214/307200(99.6%) : rest 1.4s : 2018/03/21 06:32:32 wh : 307200/307200(100.0%) : fin 7m 16.08s frm : 300/300(100.0%) : fin 38h 33m 5.59s
38時間半強! とにかく長時間かかりました。 球体の中にある平面部分が屈折して上に見えてるのでしょうか?
物体の表面に画像を投影してみます。
v6.patch メモ
$ cat v6.patch | ( cd rt ; patch -p1 ) $ cd rt $ wget http://kondoh.html.xdomain.jp/copen-090419.jpg $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/map1 div=16 fps=2
とりあえず時間がかからないように、 デフォルトの設定で反射と屈折は0、周囲光と拡散光だけにしてます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/map2 : wh : 293339/307200(95.4%) : rest 7.04s : 2018/03/21 19:18:31 wh : 295575/307200(96.2%) : rest 5.9s : 2018/03/21 19:18:31 wh : 297801/307200(96.9%) : rest 4.76s : 2018/03/21 19:18:31 wh : 300021/307200(97.6%) : rest 3.63s : 2018/03/21 19:18:31 wh : 302169/307200(98.3%) : rest 2.54s : 2018/03/21 19:18:31 wh : 303879/307200(98.9%) : rest 1.68s : 2018/03/21 19:18:31 wh : 306090/307200(99.6%) : rest 0.56s : 2018/03/21 19:18:31 wh : 307200/307200(100.0%) : fin 2m 35.63s frm : 300/300(100.0%) : fin 11h 2m 56.42s
11時間でした。
拡散光のときの
frm : 300/300(100.0%) : fin 8h 17m 55.27s
に比べて、map_col()の処理分の時間が増えてるはずですね。
画像が貼れるなら同じくらいの負荷で動画も貼れるだろう、 という事で試してみます。
ワイヤーフレームのプログラム で作った動画でも貼ってみます。
どうせワイヤーフレームの動画なので、 周囲光(自発光)のみにして、拡散光もなしのベタ塗り設定にしてみます。
v7.patch メモ
$ cat v7.patch | ( cd rt ; patch -p1 ) $ cd rt $ wget http://kondoh.html.xdomain.jp/wf/img/g43.gif $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/vmap1 div=16 fps=2
うーむ。粗いお試しだと意味不明ですな。
./cg.py eyep=[0,0,0],200,10 sec=10 name=out/vmap2 : wh : 301281/307200(98.0%) : rest 3.63s : 2018/03/22 12:15:16 wh : 303089/307200(98.6%) : rest 2.52s : 2018/03/22 12:15:15 wh : 304980/307200(99.2%) : rest 1.36s : 2018/03/22 12:15:15 wh : 306814/307200(99.8%) : rest 0.23s : 2018/03/22 12:15:15 wh : 307200/307200(100.0%) : fin 3m 8.27s frm : 300/300(100.0%) : fin 13h 44m 46.54s
13時間45分。 なんか思ってたんと違うー。 自発光のみにしたものの、そこそこ時間かかってました。
+ maps = [ + { 'fn': 'g43.gif', 'fn_r': 'g43.gif', 't2m': [ ax.zoom_all(8) ] }, + { 'fn': 'g43.gif', 't2m': [ ax.zoom_all(8), ax.zoom_z(-1) ] }, + ]
ここで8倍にしたのが、ちょっと拡大しすぎだったかも。
もう少しまともっぽい動画でためしてみます。
v8.patch メモ
球体の方は貼り付けなしで、青く薄く自発光、拡散光なし、反射光なし。 屈折だけは密度2でがっちりと。 透明のビー玉の感じを狙ってみました。
$ cat v8.patch | ( cd rt ; patch -p1 ) $ cd rt $ wget http://kondoh2.html.xdomain.jp/rt/IMG_3999_3.mov $ wget http://kondoh2.html.xdomain.jp/rt/IMG_3999_4.mov $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/vmap3 : wh : 299613/307200(97.5%) : rest 4.53s : 2018/03/23 06:02:07 wh : 301843/307200(98.2%) : rest 3.19s : 2018/03/23 06:02:06 wh : 304062/307200(98.9%) : rest 1.86s : 2018/03/23 06:02:06 wh : 306291/307200(99.7%) : rest 0.54s : 2018/03/23 06:02:06 wh : 307200/307200(100.0%) : fin 3m 2.46s frm : 300/300(100.0%) : fin 15h 48m 45.39s
16時間弱。 屈折はちゃんとかかってるようですね。
屈折光 のときに38時間半もかかってたのは、 屈折と反射のコラボが原因と推察します。
視線からのトレースで球体表面で屈折して内部に向かった後、 球体内部で反射しまくって、減衰するまで処理してるからなのかと。
反射を0にしたので、 動画を貼ってもそこまでは時間はかかりませんでした。
ということで、物体の法線ベクトルの裏側の面はデフォルトでは反射しない事にします。 'reflect_backside'を明示的にあえてTrueに設定した時だけ、裏面も反射を有効にします。
至近距離から強めの点光源を当てて、拡散光の変化が出やすくしてみました。
あと拡散光の処理のバグ修正も少々。
v9.patch メモ
$ cat v9.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/vmap4 : wh : 301054/307200(97.9%) : rest 6.82s : 2018/03/24 13:02:22 wh : 302503/307200(98.4%) : rest 5.20s : 2018/03/24 13:02:22 wh : 303998/307200(98.9%) : rest 3.54s : 2018/03/24 13:02:21 wh : 305486/307200(99.4%) : rest 1.89s : 2018/03/24 13:02:20 wh : 306992/307200(99.9%) : rest 0.22s : 2018/03/24 13:02:20 wh : 307200/307200(100.0%) : fin 5m 38.39s frm : 300/300(100.0%) : fin 24h 43m 13.72s
24時間。まぁ37時間よりは短縮です。
時間はかかっても反射と半透明のコラボは美しいですね。
平面と球だけというのも何なので、立方体を追加してみます。
v10.patch メモ
まずはワイヤーフレームで確認してみます。
$ cat v10.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/wf_cube wf
続いて粗い設定で。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/cube1 div=16 fps=2
なんとなく立方体が見えてる風味。良さそうなのでレンダリング開始。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/cube2 : wh : 306305/307200(99.7%) : rest 2.70s : 2018/03/27 09:28:18 wh : 306711/307200(99.8%) : rest 1.47s : 2018/03/27 09:28:18 wh : 306993/307200(99.9%) : rest 0.62s : 2018/03/27 09:28:18 wh : 307200/307200(100.0%) : fin 15m 27.14s frm : 300/300(100.0%) : fin 68h 23m 0.11s
68時間半とは3日弱!!!
球をサイコロに置き換えると、サイコロは6つの四角に展開されるので、 処理時間がずいぶんと増えました。
立方体に続いて色々追加してみます。
cg.py の data, lights の定義は、dat.py に切り出してみました。
$ cat v11.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/objs_wf wf : frm : 285/300(95.0%) : rest 4.58s : 2018/03/27 09:48:37 frm : 289/300(96.3%) : rest 3.36s : 2018/03/27 09:48:37 frm : 293/300(97.6%) : rest 2.14s : 2018/03/27 09:48:38 frm : 297/300(99.0%) : rest 0.91s : 2018/03/27 09:48:38 frm : 300/300(100.0%) : fin 1m 31.98s
10秒のワイヤーフレーム動画作成に1分半。 これまでワイヤーフレームはリアルタイムで表示できていたのに、 嫌な予感。
1/16の解像度で処理ピクセル数を1/256にして、 5秒の時刻の1コマだけ描画してみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/objs1 div=16 n=1 init_sec=5 : wh : 928/1200(77.3%) : rest 4.49s : 2018/03/27 09:50:45 wh : 1012/1200(84.3%) : rest 3.03s : 2018/03/27 09:50:45 wh : 1110/1200(92.5%) : rest 1.40s : 2018/03/27 09:50:44 wh : 1200/1200(100.0%) : fin 17.99s
18秒
解像度を元に戻して1コマ描画したとすると
18*(16*16)/(60*60) = 1.28 (h)
お試しするには長すぎなので、 解像度を1/4に落として1コマ描画したとすると
18*(16*16)/(4*4)/60 = 4.8 (m)
試してみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/objs2 div=4 n=1 init_sec=5 : wh : 18825/19200(98.0%) : rest 5.45s : 2018/03/27 10:00:54 wh : 18984/19200(98.8%) : rest 3.12s : 2018/03/27 10:00:53 wh : 19146/19200(99.7%) : rest 0.77s : 2018/03/27 10:00:52 wh : 19200/19200(100.0%) : fin 4m 36.09s
この結果から試算しなおして
1コマ ( 4*60+36 )*(4*4)/(60*60) = 1.22666 (h) 30fpsで10秒分だと300コマ ( 4*60+36 )*(4*4)/(60*60) * 300 = 367.999 (h) ( 4*60+36 )*(4*4)/(60*60) * 300 / 24 = 15.333 (d)
15日以上かかるとの予想!
とりあえず、フレームレートを fps=1 にしての 10 sec
( 4*60+36 )*(4*4)/(60*60) * 10 = 12.2666 (h)
これで試してみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/objs3 fps=1 : wh : 306885/307200(99.8%) : rest 4.73s : 2018/03/27 20:33:46 wh : 306976/307200(99.9%) : rest 3.36s : 2018/03/27 20:33:46 wh : 307067/307200(99.9%) : rest 1.99s : 2018/03/27 20:33:45 wh : 307135/307200(99.9%) : rest 0.97s : 2018/03/27 20:33:45 wh : 307200/307200(100.0%) : fin 1h 16m 52.02s frm : 10/10(100.0%) : fin 10h 26m 54.04s
予想よりちょっとましで、10時間半。
角錐のあたり、何かバグってますね。
角錐のたぐいはワイヤーフレームでは、 三角に展開されてそれらしく表示されてましたが、 レイトレーシングしてみると表示が乱れてました。
まず、dat.py を変更してコマンドライン引数の指定で、 角錐のデータに切り替えれるようにしておいて、 色々と追いかけてみました。
ローカル座標系とグローバル座標系の関係は dataの辞書のキー'l2g'に設定されてます。 ワイヤーフレームでは'l2g'をローカルからグローバルへの方向に変換して使用します。 レイトレーシングでは視線の直線を'l2g'を使って、グローバルからローカルへと逆変換して使用します。
ここで、逆変換の方向の処理にバグがありました。
diff -urN rt_v11/vecs.py rt_v12/vecs.py --- rt_v11/vecs.py 2018-03-16 20:38:43.000000000 +0900 +++ rt_v12/vecs.py 2018-03-28 22:25:34.000000000 +0900 @@ -12,10 +12,15 @@ e.typ = 'vecs' e.v3 = v3 l2g = lambda v_: v.lst_add( map( lambda (a, e): v.op1('*', a, e), zip(v3, v_) ) ) - g2l = lambda v_: map( lambda a: v.dot_product_len(v_, a), v3 ) + g2l = lambda v: e.rev().tr('l2g', v) e.tr = lambda d, v: { 'l2g': l2g, 'g2l': g2l }.get(d, l2g)(v) - e.rev = lambda : new( mt.v3_rev(v3) ) + e.rev_vs = None + def rev(): + if not e.rev_vs: + e.rev_vs = new( mt.v3_rev(v3) ) + return e.rev_vs + e.rev = rev e.zoom = lambda zm3: new( map( lambda (v_, zm): v.op1('*', v_, zm), zip(v3, zm3) ) ) e.zoom_all = lambda zm: e.zoom( [zm,zm,zm] )
修正前の処理では、座標系のベクトルが同じ大きさで直行してる前提でなければ、正しく動作しなかったようです。 とりあえず、逆行列を使う方向で修正してみると、それらしい表示になりました。
v12.patch メモ
$ cat v12.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid_wf wf : frm : 282/300(94.0%) : rest 1.11s : 2018/03/28 22:56:27 frm : 299/300(99.6%) : rest 0.06s : 2018/03/28 22:56:27 frm : 300/300(100.0%) : fin 18.63s
まずは1コマだけで。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid1 init_sec=5 n=1 : wh : 304044/307200(98.9%) : rest 6.96s : 2018/03/28 23:09:43 wh : 305019/307200(99.2%) : rest 4.80s : 2018/03/28 23:09:42 wh : 306130/307200(99.6%) : rest 2.35s : 2018/03/28 23:09:40 wh : 307200/307200(100.0%) : fin 11m 13.93s
1コマ11分14秒ということは
(11*60+14)*300/60/60/24 = 2.34 (d)
単純計算で丸2日以上はかかりますね。 高速化を検討すべきでしょうか。 解像度半分でピクセル数1/4。半日(12時間)強で手をうってみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid2 div=2 : wh : 75347/76800(98.1%) : rest 2.89s : 2018/03/29 12:19:29 wh : 75933/76800(98.8%) : rest 1.72s : 2018/03/29 12:19:29 wh : 76524/76800(99.6%) : rest 0.54s : 2018/03/29 12:19:29 wh : 76800/76800(100.0%) : fin 2m 32.64s frm : 300/300(100.0%) : fin 13h 2m 52.90s
できるだけnumpyを使うようにしてみます。 [x,y,z]な要素3のリストの扱いがほとんどなので、さほどな気もしますが...
$ cat v13.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid3 init_sec=5 n=1 : wh : 305726/307200(99.5%) : rest 2.81s : 2018/04/01 12:10:05 wh : 307177/307200(99.9%) : rest 0.04s : 2018/04/01 12:10:03 wh : 307200/307200(100.0%) : fin 9m 44.53s
ぱっと見、同じ画像が生成できてる様子? というか、モアベターになってないかい?
v12のとき wh : 307200/307200(100.0%) : fin 11m 13.93s だったので (9*60+44.53) / (11*60+13.93 ) * 100 = 86.73 100 - 86.73 = 13.27
速度的には13.27パーセントの向上です。
交点を求める処理で、結局最後に使われないかもしれない計算は、 なるべくセコく先延ばしするようにしてみました。
$ cat v14.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid4 init_sec=5 n=1 : wh : 304901/307200(99.2%) : rest 3.77s : 2018/04/01 20:53:33 wh : 306183/307200(99.6%) : rest 1.66s : 2018/04/01 20:53:32 wh : 307200/307200(100.0%) : fin 8m 22.68s
v13のとき wh : 307200/307200(100.0%) : fin 9m 44.53s だったので (8*60+22.68) / (9*60+44.53) * 100 = 85.99 100 - 85.99 = 14.01
14.01パーセントの向上です。
やってしまったか。
さらなる高速化のため numba とやらを試そうかと思ったのが運のつき。
Macでの情報を検索してみると
llvmのインストールbrew install homebrew/versions/llvm38 export LLVM_CONFIG=/usr/local/Cellar/llvm38/3.8.1/bin/llvm-config-3.8 llvmlite のインストールpip3 install llvmlite numbaのインストールpip3 install numba
ふむ。
$ brew install homebrew/versions/llvm38 : To avoid broken installations, as soon as possible please run: brew upgrade Or, if you're OK with a less reliable fix: brew upgrade python Error: homebrew/versions was deprecated. This tap is now empty as all its formulae were migrated.
!? とりあえず...
$ brew upgrade :
!?
$ python Python 3.6.5 (default, Mar 30 2018, 06:41:49) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
Python 3 になっとる。
ここまで Python 2 のままで Python 3 には手を出してなかったのに〜!
まぁ、あきらめます。いい機会と思って Python 3 で動くようにしてみます。
numba は後回し。
v15.patch メモ
$ cat v15.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid5 init_sec=5 n=1 : wh : 305693/307200(99.5%) : rest 3.13s : 2018/04/03 10:16:01 wh : 306936/307200(99.9%) : rest 0.54s : 2018/04/03 10:15:59 wh : 307200/307200(100.0%) : fin 10m 38.03s
v14のとき wh : 307200/307200(100.0%) : fin 8m 22.68s だったので (10*60+38.03) / (8*60+22.68) * 100 = 126.92 100 - 126.92 = -26.92
26.92パーセントの低下です。
ちびちび速度アップしてきたのに、 map, filter への安易な対策が足を引っ張ってしまったかも (T_T)
ワイヤーフレームの描画をさせてみるとエラー発生。
python3対応を施したものの、 角錐の平面系の絵が1枚描ける事しか確認してませんでしたね。
できるだけ対処して、時間のかからない設定でざっと確認してみます。
v16.patch メモ
$ cat v16.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out/ball_wf wf : frm : 278/300(92.7%) : rest 1.82s : 2018/04/04 17:17:49 frm : 291/300(97.0%) : rest 0.74s : 2018/04/04 17:17:49 frm : 300/300(100.0%) : fin 24.77s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out/ball div=8 fps=15 : wh : 3199/4800(66.6%) : rest 1.50s : 2018/04/04 17:28:21 wh : 4242/4800(88.4%) : rest 0.52s : 2018/04/04 17:28:21 wh : 4800/4800(100.0%) : fin 4.31s frm : 150/150(100.0%) : fin 9m 32.98s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out/ball_1 n=1 init_sec=5 : wh : 298537/307200(97.2%) : rest 6.64s : 2018/04/04 17:40:54 wh : 304452/307200(99.1%) : rest 2.07s : 2018/04/04 17:40:50 wh : 307200/307200(100.0%) : fin 3m 50.63s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=cube name=out/cube_wf wf : frm : 279/300(93.0%) : rest 1.69s : 2018/04/04 17:43:08 frm : 293/300(97.7%) : rest 0.56s : 2018/04/04 17:43:08 frm : 300/300(100.0%) : fin 24.19s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=cube name=out/cube div=8 fps=15 : wh : 4270/4800(89.0%) : rest 1.11s : 2018/04/04 18:06:52 wh : 4761/4800(99.2%) : rest 0.08s : 2018/04/04 18:06:52 wh : 4800/4800(100.0%) : fin 10.10s frm : 150/150(100.0%) : fin 22m 55.25s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=cube name=out/cube_1 n=1 init_sec=5 : wh : 305653/307200(99.5%) : rest 3.23s : 2018/04/04 18:18:36 wh : 306345/307200(99.7%) : rest 1.78s : 2018/04/04 18:18:35 wh : 307200/307200(100.0%) : fin 10m 40.80s frm : 1/1(100.0%) : fin 10m 48.61s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out/objs_wf wf : frm : 295/300(98.3%) : rest 2.35s : 2018/04/04 18:27:33 frm : 297/300(99.0%) : rest 1.41s : 2018/04/04 18:27:33 frm : 300/300(100.0%) : fin 2m 21.61s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out/objs div=8 fps=1 : wh : 4590/4800(95.6%) : rest 2.16s : 2018/04/04 18:36:47 wh : 4698/4800(97.9%) : rest 1.04s : 2018/04/04 18:36:47 wh : 4800/4800(100.0%) : fin 49.20s frm : 10/10(100.0%) : fin 6m 52.90s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out/objs_1 n=1 init_sec=5 div=2 : wh : 76449/76800(99.5%) : rest 4.40s : 2018/04/04 19:10:47 wh : 76720/76800(99.9%) : rest 1.00s : 2018/04/04 19:10:45 wh : 76800/76800(100.0%) : fin 16m 1.01s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid_wf wf : frm : 273/300(91.0%) : rest 2.38s : 2018/04/04 19:12:18 frm : 288/300(96.0%) : rest 1.04s : 2018/04/04 19:12:18 frm : 300/300(100.0%) : fin 26.01s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid div=8 fps=15 : wh : 3429/4800(71.4%) : rest 2.40s : 2018/04/04 19:34:14 wh : 4154/4800(86.5%) : rest 1.09s : 2018/04/04 19:34:13 wh : 4800/4800(100.0%) : fin 7.86s frm : 150/150(100.0%) : fin 20m 44.41s
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=poly_n_pyramid name=out/pn_pyramid_1 n=1 init_sec=5 : wh : 304953/307200(99.3%) : rest 6.95s : 2018/04/04 20:31:36 wh : 306216/307200(99.7%) : rest 3.03s : 2018/04/04 20:31:34 wh : 307200/307200(100.0%) : fin 15m 45.51s
python3 対応以降、アングルが微妙に変わってます。
way.py def liss_get(key): (p, r, t) = p_r_t(key) p = mt.arr(p) ps = p - r pe = p + r t3 = (t, t*4/3, t*5/3) return liss(ps, pe, t3)
ここの割り算が、対応前は整数の割り算扱いでした。 対応前と同じにするには '/' --> '//' ですが、実は対応前が間違い。 tの値はfloatを想定していましたが、intの値ばかり指定して試してました。
なので対応後のアングルの方が正解のはずです。
あと、全体的に気泡のようなツブツブが目立つのは気のせい?
気泡問題は以前反射光のところで
物体表面を新たな視点としてトレースする時、 起点の交点そのものは次の交点の候補から外す処理を追加しています。
だったはずですが...
ref_rate の値を100万分の1固定から、引数の指定で変更できるようにして試してみます。 とりあえず指定がなかったときのデフォルト値は1000分の1ということで。
v17.patch diff -urN rt_v16/rt.py rt_v17/rt.py --- rt_v16/rt.py 2018-04-03 09:46:11.000000000 +0900 +++ rt_v17/rt.py 2018-04-04 21:33:33.000000000 +0900 @@ -36,6 +36,8 @@ col = np.sum(cols, axis=0) if cols else def_col return ut.map_lst( lambda v: min(v, 255), col ) +ref_rate = ut.arg_f('ref_rate', 0.001) + def get_col(data, lights, l_g, video, nest_rate=1.0, ref_len=None): if nest_rate < 0.01: return [] @@ -46,7 +48,6 @@ return [] if ref_len: - ref_rate = 0.000001 lst = ut.filter_lst( lambda crs: crs.get('t') > ref_len * ref_rate, lst ) if not lst: return []
この「候補から外す処理」の内容は
rt.py def get_col(data, lights, l_g, video, nest_rate=1.0, ref_len=None): 最後の引数ref_lenで「参考にする長さ」を指定 最初の視点からのトレース時は、デフォルト値でNone(指定なし) : if ref_len: lst = ut.filter_lst( lambda crs: crs.get('t') > ref_len * ref_rate, lst ) if not lst: return [] もしref_lenの指定があれば、ここでふるいにかけてます lstは複数の物体の交点情報のリスト crs.get('t')は視点から交点までの距離のようなもの それが「参考にする長さ」の100万分の1より小さい、 つまり視点に十分近い位置ならば、除外します crs = min( lst, key=lambda crs: crs.get('t') ) 除外処理済みのリストから、一番視点に近い交点をcrsに : crst = crs.get('t') その交点crsの視点との距離のようなものをcrstに def reflect_col(): : col = get_col( data, lights, ref_l, video, nest_rate * reflect, crst ) return col * reflect if col != [] else [] col_ = reflect_col() : 反射の再帰処理で、交点crsを新たな視点としてトレースするときは 「参考にする長さ」ref_len として、前回の視点と交点の距離のような値crstを指定します 屈折の場合もまた同様にref_lenを指定
試してみます。まずref_rateが1000分の1の場合
$ cat v17.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out_v17/ball_1 n=1 init_sec=5 : wh : 307200/307200(100.0%) : fin 3m 55.30s
気泡、北半球は消えてる感じです。
次に、これまで通りref_rateが100万分の1の場合
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out_v17/ball_2 n=1 init_sec=5 ref_rate=0.000001 : wh : 307200/307200(100.0%) : fin 3m 45.27s
気泡、目立ちますね。 反射光対応の最初から100万分の1としてたはずなのですが。
極端に、ref_rateを10分の1にしてみた場合
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball name=out_v17/ball_3 n=1 init_sec=5 ref_rate=0.1 : wh : 307200/307200(100.0%) : fin 3m 5.07s
まぁそうですね。極端にすると逆に問題ありになりますね。 以降ref_rateはデフォルトの1000分の1という事で。
以前の試算で15日以上かかる予想のデータを、このバージョンで荒削り設定で試してみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v17/objs div=2 fps=4 : wh : 76569/76800(99.7%) : rest 2.30s : 2018/04/05 06:53:42 wh : 76698/76800(99.9%) : rest 1.01s : 2018/04/05 06:53:42 wh : 76800/76800(100.0%) : fin 12m 46.20s frm : 40/40(100.0%) : fin 6h 50m 3.11s
それでも多少、気泡が気になりますね。
解像度1/2でピクセル数1/4 フレームレート4/30 よって本来のピクセル処理量の1/30 それで7時間弱かかったので ( ((6*60+50)*60+3.11) * 30 ) / (60*60*24) = 8.54 約8日半 あら、15日以上の予想より速いですね。 以前の予想のときは $ ./cg.py eyep=[0,0,0],200,10 sec=10 name=out/objs2 div=4 n=1 init_sec=5 : wh : 19200/19200(100.0%) : fin 4m 36.09s 解像度1/4の絵を1枚で4分36.09秒 ピクセル数は本来の1/(4*4*300)なので (4*60+36.09) * (4*4*300) / (60*60*24) = 15.33 まぁ10秒間のうち時刻5秒のときの絵1枚の時間だったので、 たまたま処理が重くなるアングルで、試算していたのかもしれません
それでも一週間以上はかかる予想です。(T_T)
Python3 対応以降のソースを全体的に見直して、高速化してみました。
まずバージョン17から
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v17/objs_32 div=32 : wh : 300/300(100.0%) : fin 3.09s frm : 300/300(100.0%) : fin 12m 51.35s
そしてバージョン18
$ cd .. $ cat v18.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v18/objs_32 div=32 : frm : 299/300(99.7%) : total 7m 35.62s : rest 1.51s : 2018/04/08 00:26:20 wh : 0/300(0.0%) : not start yet wh : 184/300(61.3%) : total 1.63s : rest 0.63s : 2018/04/08 00:26:20 wh : 300/300(100.0%) : fin 1.77s frm : 300/300(100.0%) : fin 7m 35.91s
(7*60+35.91) / (12*60+51.35) * 100 = 59.10 100 - 59.10 = 40.90
40.90パーセントの向上です。v^_^)
ということは、解像度を4倍あげてフレームレート2fpsにおとすと、
4*4*(2/30)=16/15=1.066
だいたい同じくらいの時間で仕上がるはず。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v18/objs_8_2_ div=8 fps=2 : wh : 4732/4800(98.6%) : total 32.64s : rest 0.46s : 2018/04/08 00:53:13 wh : 4800/4800(100.0%) : fin 32.60s frm : 20/20(100.0%) : fin 8m 14.18s
ですね。
さらに解像度を2倍でフレームレート30fpsの予想時間は
((8*60+14.18)*2*2*(30/2)) / (60*60) = 8.23
8.23時間。試してみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v18/objs_4 div=4 : wh : 19196/19200(100.0%) : total 1m 55.49s : rest 0.02s : 2018/04/08 08:58:21 wh : 19200/19200(100.0%) : fin 1m 55.53s frm : 300/300(100.0%) : fin 7h 56m 30.00s
やっぱり気泡が気になります。 多少速度を犠牲にしても良しとして、根本的に対策しておきます。
再帰して交点を求めるときに、 前回の交点となった物体の情報を覚えておいて、 交点算出時に除外する方針で何とかしてみます。
あと、多角形(poly_n)の交点を求める処理を入れてましたが、、、 多角形は複数の三角形に展開して使うので、不要でした orz
まず前のバージョンの結果を確認
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v18/objs_1_2 n=1 init_sec=5 div=2 : wh : 76009/76800(99.0%) : total 7m 50.93s : rest 4.85s : 2018/04/12 20:50:10 wh : 76469/76800(99.6%) : total 7m 49.10s : rest 2.02s : 2018/04/12 20:50:08 wh : 76800/76800(100.0%) : fin 7m 47.81s
では対策したバージョンで
$ cd .. $ cat v19.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v19/objs_1_2 n=1 init_sec=5 div=2 : wh : 75908/76800(98.8%) : total 7m 42.15s : rest 5.36s : 2018/04/12 21:00:15 wh : 76373/76800(99.4%) : total 7m 40.34s : rest 2.55s : 2018/04/12 21:00:13 wh : 76800/76800(100.0%) : fin 7m 38.74s
円柱の曲面や、円柱と平面の交差するあたりで改善が顕著です。 処理時間はほぼ同等。逆に短縮されたくらいですね v^_^)
視線の直線と物体との交点を求める処理を、別プロセスに切り出して処理させてみます。
さらに次のステップでは、切り出した別プロセスのプログラムをC言語で実装しなおしてみて、高速化を試してみます。 (numbaのお試しは、さらに先延ばし...)
とまぁ、この段階ではわざわざ別のserverプロセスに分けても、serverで同じcross.pyの処理を呼び出してるので、 遅くなるだけです。
serverで返した交点の答をあんちょこファイルに落としているのがミソで、次回同様に use_srv 指定で起動した場合にserverの動作は
あんちょこファイルを作ったときと同じ設定にしなければ意味ないのですが、 これは、1つの処理時間の基準になります。
同様のserverをがんばってC言語で実装したとしても、 このあんちょこカンニング版の処理時間が上限で、 これ以上短くなる事はまず無いでしょう。
なので、あんちょこを使っても遅ければ、プロセス間通信のオーバーヘッドが大きいので、 素直に従来通り処理した方が、まだ「まし」という事になります。
まずは、従来の処理の場合から。 use_srv 指定の有無による分岐が1つ追加で入ってるので、影響が大きくないか一応確認しておきます。
$ cat v20.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v20/objs_1_2 n=1 init_sec=5 div=2 : wh : 76242/76800(99.3%) : total 7m 50.43s : rest 3.41s : 2018/04/12 21:42:35 wh : 76664/76800(99.8%) : total 7m 48.84s : rest 0.83s : 2018/04/12 21:42:34 wh : 76800/76800(100.0%) : fin 7m 48.33s
ふむ。従来通りの処理時間っすね。
では、別serverプロセスを起動する方式で、あんちょこファイルも作ってみます。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v20/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76049/76800(99.0%) : total 9m 12.58s : rest 5.40s : 2018/04/12 23:11:19 wh : 76446/76800(99.5%) : total 9m 10.71s : rest 2.53s : 2018/04/12 23:11:17 wh : 76800/76800(100.0%) : fin 9m 9.07s $ ls -l xdat -rw-r--r-- 1 kondoh staff 2636160 4 12 23:58 xdat
同様の画像ができてます。 そして、あんちょこファイル 2.5Mバイト程度。
別プロセスに分けることで 100 * ( (9*60+9.07) / (7*60+48.33) - 1 ) = 17.23 パーセント低下
続いて、あんちょこファイルでカンニング方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v20/objs_1_2_s2 n=1 init_sec=5 div=2 use_srv : wh : 67446/76800(87.8%) : total 2m 3.53s : rest 15.04s : 2018/04/13 00:02:20 wh : 71625/76800(93.3%) : total 1m 57.40s : rest 7.91s : 2018/04/13 00:02:14 wh : 76800/76800(100.0%) : fin 1m 50.29s
無事、同様の画像ができてます。
ほとんどプロセス間通信のオーバーヘッドだけの状態で 100 * ( 1 - ( 1*60+50.29) / (7*60+48.33) ) = 76.45 パーセント向上
これならserverの処理をC言語でトライしてみる価値がありそうですね。 76.45パーセントのどこまで近づけれるものなのか。
ちなみに、生成した画像ファイルはみな同様に見えますが、、、
$ cd out_v20 $ ls -l *.jpg total 192 -rw-r--r-- 1 kondoh staff 32282 4 12 21:43 objs_1_2.jpg -rw-r--r-- 1 kondoh staff 32282 4 13 00:00 objs_1_2_s.jpg -rw-r--r-- 1 kondoh staff 32282 4 13 00:02 objs_1_2_s2.jpg $ cmp objs_1_2.jpg objs_1_2_s.jpg $ $ cmp objs_1_2_s.jpg objs_1_2_s2.jpg $ $ cd ..
無事、一致しておりました。
ということで、がんばってC言語で書いてみました。
起動オプション usr_srv を指定した上で、さらに srv_c を指定すると C言語で実装した方のサーバプログラムを起動します。
$ cat v21.patch | ( cd rt ; patch -p1 ) $ cd rt $ make gcc -Wall -c -o sock.o sock.c gcc -Wall -c -o cross.o cross.c gcc -Wall -c -o ax.o ax.c gcc -Wall -c -o vecs.o vecs.c gcc -Wall -c -o line.o line.c gcc -Wall -c -o v.o v.c gcc -Wall -c -o mt.o mt.c gcc -o sock sock.o cross.o ax.o vecs.o line.o v.o mt.o $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v21/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 68851/76800(89.6%) : total 1m 0.56s : rest 6.26s : 2018/04/14 11:47:18 wh : 74103/76800(96.5%) : total 57.30s : rest 2.01s : 2018/04/14 11:47:15 wh : 76800/76800(100.0%) : fin 55.70s $ ls -l out_v21/objs_1_2_sc.jpg -rw-r--r-- 1 kondoh staff 32344 4 14 11:48 out_v21/objs_1_2_sc.jpg $ ls -l out_v20/objs_1_2_s2.jpg -rw-r--r-- 1 kondoh staff 32282 4 13 00:02 out_v20/objs_1_2_s2.jpg
画像ファイルのサイズが微妙に違ってますが、まぁ..同様に見えます。
気になる処理時間は、55.70秒 !!!
v20あんちょこカンニング版の時間にどれだけ迫れるものかと思ってたら、 さらに半分近くにまで短縮 !?
他の設定でも試してみます。フルの解像度で1枚だけの場合
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v21/objs_1_sc n=1 init_sec=5 use_srv srv_c port=23482 : wh : 299637/307200(97.5%) : total 3m 41.78s : rest 5.46s : 2018/04/14 09:09:08 wh : 306265/307200(99.7%) : total 3m 37.98s : rest 0.66s : 2018/04/14 09:09:05 wh : 307200/307200(100.0%) : fin 3m 37.46s
3分半。ということは
10秒分の300枚の単純な予想では ( 3*60+37.46 ) * 300 / 60 / 60 = 18.12 時間
色んなアングルがあるので、もうちょっと違う設定でじっくりと
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v21/objs_2_15_sc div=2 fps=15 use_srv srv_c port=23484 : wh : 76664/76800(99.8%) : total 1m 0.14s : rest 0.10s : 2018/04/14 11:21:29 wh : 76800/76800(100.0%) : fin 1m 0.12s frm : 150/150(100.0%) : fin 2h 7m 12.09s
解像度1/2でフレームレート15/30倍なので、フルで試したとすると ( (((2*60)+7)*60+12.09) * 2*2*2 ) / 60 / 60 = 16.96
予想では17時間。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v21/objs_full_sc use_srv srv_c : wh : 306431/307200(99.7%) : total 3m 58.73s : rest 0.59s : 2018/04/15 05:15:55 wh : 307200/307200(100.0%) : fin 3m 58.63s frm : 300/300(100.0%) : fin 16h 50m 54.21s
確かに17時間で終了です。
2週間以上かかる予想だった頃や、 立方体と平面だけで3日もかかってた頃に比べると、 速くなりました〜 v^_^)
そこそこ処理が速くなったところで、 変わり映えしない絵の脱却を図るべく、 データを追加してみます。
巨大な球の赤道に沿って円でしきった物体を用意。 その北半球部分に、ちいさな球と立方体を配置。 巨大な球のドーム屋根の内側と下側の円に動画を投影しつつ、 下側の円の表面では天井の絵をある程度反射。
$ cat v22.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball_world name=out_v22/bw2_wf wf
解像度半分、フレームレートも半分で、フルの1/8で。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball_world name=out_v22/bw2_2_15 use_srv srv_c div=2 fps=15 : wh : 76221/76800(99.2%) : total 1m 24.69s : rest 0.63s : 2018/04/15 21:44:58 wh : 76800/76800(100.0%) : fin 1m 24.62s frm : 150/150(100.0%) : fin 3h 11m 18.29s
では、8倍で24時間。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball_world name=out_v22/bw2_full use_srv srv_c : wh : 306434/307200(99.8%) : total 5m 42.07s : rest 0.85s : 2018/04/16 23:41:50 wh : 307200/307200(100.0%) : fin 5m 41.87s frm : 300/300(100.0%) : fin 25h 48m 38.76s
26時間弱でした。
先の追加データがいい感じなので、 もうちょっと違うバージョンを試そうと、 画像の円柱マッピング方式のデータを追加してみました。
普通の長方形の画像を円柱に巻きつけたとき、、、 例えば縦横比4:3の画像を隙間なく巻きつけるならば
h = 2*pi*r *3/4 = 4.71 * r
高さは円柱半径の5倍弱。ちょっと細すぎで使い勝手が悪いかも。
高さと半径の割合をいい感じにとると、円周方向の長さが足りず。
足りない分は、繰り返しパターンで埋める事にすればいいか。 画像や動画を繰り返し展開する機能を追加する事にします。
v23.patch メモ
ところで、レイトレーシングの画像を検索してみると、 判で押したように「チェスボードの上に透明の球」な画像が出てきます。
ここはひとつ、画像の繰り返し展開を試しつつも、 伝統に従ったデータを追加して試してみます。
$ cat v23.patch | ( cd rt ; patch -p1 ) $ cd rt $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=copen_rep name=out_v23/copen_rep use_srv srv_c : wh : 306415/307200(99.7%) : total 2m 59.52s : rest 0.45s : 2018/04/17 11:53:31 wh : 307200/307200(100.0%) : fin 2m 59.47s frm : 300/300(100.0%) : fin 12h 8m 4.87s
せっかくout_v23/copen_rep.mp4 が出来たのですが...
-rw-r--r-- 1 kondoh staff 3741956 4 17 11:53 copen_rep.mp4
3Mバイトを超えてしまい、 サイトのファイル1つ3Mバイトまでの制限にひっかかりました。
$ ./img.py out_v23/tmp/copen_rep out_v23/copen_rep cmd=v2i $ ls out_v23/tmp/ | head copen_rep00000.jpg copen_rep00001.jpg copen_rep00002.jpg copen_rep00003.jpg copen_rep00004.jpg copen_rep00005.jpg copen_rep00006.jpg copen_rep00007.jpg copen_rep00008.jpg copen_rep00009.jpg $ ls out_v23/tmp/ | tail copen_rep00290.jpg copen_rep00291.jpg copen_rep00292.jpg copen_rep00293.jpg copen_rep00294.jpg copen_rep00295.jpg copen_rep00296.jpg copen_rep00297.jpg copen_rep00298.jpg copen_rep00299.jpg $ mkdir out_v23/tmp/hide $ mv out_v23/tmp/copen_rep002* out_v23/tmp/hide/ ここで img.py の imgs_to_video() で python3 対応もれ : lst = ut.cmd_exec(cmd).decode().strip().split('\n') #lst = ut.cmd_exec(cmd).strip().split('\n') : 次回のpatchに含めておきます。 $ ./img.py out_v23/tmp/copen_rep out_v23/copen_rep2 $ ls -l out_v23/copen_rep2.mp4 -rw-r--r-- 1 kondoh staff 1474209 4 17 21:15 out_v23/copen_rep2.mp4 ちょっと削りすぎた $ mv out_v23/tmp/hide/copen_rep002[01234]* out_v23/tmp/ $ ./img.py out_v23/tmp/copen_rep out_v23/copen_rep2 $ ls -l out_v23/copen_rep2.mp4 -rw-r--r-- 1 kondoh staff 2444200 4 17 21:41 out_v23/copen_rep2.mp4 まだいける $ mv out_v23/tmp/hide/copen_rep002[567]* out_v23/tmp/ $ ./img.py out_v23/tmp/copen_rep out_v23/copen_rep2 $ ls -l out_v23/copen_rep2.mp4 -rw-r--r-- 1 kondoh staff 3019992 4 17 21:43 out_v23/copen_rep2.mp4 超えてしまった $ mv out_v23/tmp/copen_rep0027* out_v23/tmp/hide/ $ ./img.py out_v23/tmp/copen_rep out_v23/copen_rep2 $ ls -l out_v23/copen_rep2.mp4 -rw-r--r-- 1 kondoh staff 2827547 4 17 21:44 out_v23/copen_rep2.mp4 OK
なんだか、定番の「チェスボードの上に透明の球」とは違って、不気味な凄み。
そして、円柱マッピングなバージョンのお試し。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=ball_world2 name=out_v23/bw2 use_srv srv_c : wh : 306229/307200(99.7%) : total 4m 58.12s : rest 0.94s : 2018/04/18 13:04:59 wh : 307200/307200(100.0%) : fin 4m 58.00s frm : 300/300(100.0%) : fin 24h 58m 25.62s
25時間でした。 えらいもんで、外側のドームへ円柱マッピングすると、中にある球も円柱な感じに見えますね。
視線と物体の交点を求める処理を別サーバプロセスに切り出し、C言語で実装してみました。
もうちょっと先の分の処理まで。交点の法線を求めるところまで、サーバ側のC言語で面倒みさせてみます。
そして、円柱マッピングのところにあったバグも、ひっそりと改修。
まず従来方式
$ cat v24.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make gcc -Wall -c -o sock.o sock.c gcc -Wall -c -o cross.o cross.c gcc -Wall -c -o lstx.o lstx.c gcc -Wall -c -o ax.o ax.c gcc -Wall -c -o cylx.o cylx.c gcc -Wall -c -o fcx.o fcx.c gcc -Wall -c -o vecs.o vecs.c gcc -Wall -c -o line.o line.c gcc -Wall -c -o v.o v.c gcc -Wall -c -o mt.o mt.c gcc -o sock sock.o cross.o lstx.o ax.o cylx.o fcx.o vecs.o line.o v.o mt.o -lm $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v24/objs_1_2 n=1 init_sec=5 div=2 : wh : 76609/76800(99.8%) : total 7m 45.16s : rest 1.15s : 2018/04/18 21:27:07 wh : 76800/76800(100.0%) : fin 7m 44.42s
サーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v24/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76579/76800(99.7%) : total 9m 39.30s : rest 1.66s : 2018/04/18 21:54:10 wh : 76800/76800(100.0%) : fin 9m 38.24s
別プロセスのところをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v24/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 72244/76800(94.1%) : total 56.58s : rest 3.35s : 2018/04/18 21:57:43 wh : 76800/76800(100.0%) : fin 54.07s
別プロセスに切り出しのときの結果は
従来方式 wh : 76800/76800(100.0%) : fin 7m 48.33s サーバプロセスに分離版 wh : 76800/76800(100.0%) : fin 9m 9.07s サーバプロセスであんちょこファイルカンニング版 wh : 76800/76800(100.0%) : fin 1m 50.29s
wh : 76800/76800(100.0%) : fin 55.70s
まー、ほとんど以前の結果と変わらない感じですね。
法線を求める処理は、 交点を求めるときのように物体の数だけ処理するわけじゃなく、 交点の1つの物体についてだけなので、そんなところですかね。
$ ls -l out_v24/*.jpg -rw-r--r-- 1 kondoh staff 29772 4 18 21:27 out_v24/objs_1_2.jpg -rw-r--r-- 1 kondoh staff 29772 4 18 21:54 out_v24/objs_1_2_s.jpg -rw-r--r-- 1 kondoh staff 29775 4 18 21:57 out_v24/objs_1_2_sc.jpg
円柱マッピングのデータで、ぐいっと接近した視点移動。 球や立方体の中に視点が入ったらどんな感じになるか試してみます。
$ ./cg.py eyep=[0,0,0],30,5 sec=10 data_name=ball_world2 name=out_v24/bw2_2_near div=2 use_srv srv_c : wh : 76800/76800(100.0%) : fin 1m 55.91s frm : 300/300(100.0%) : fin 11h 28m 25.60s $ls -l out_v24/bw2_2_near.mp4 -rw-r--r-- 1 kondoh staff 1849766 4 19 20:48 out_v24/bw2_2_near.mp4
11時間半。解像度半分で本来の1/4のピクセル数。フルなら44時間の予想。 接近すると、なかなか重いですね。
ちょっとぶん回し過ぎでよくわからんですね。 フレームレートを落としてみます。
$ ./img.py out_v24/bw2_2_near out_v24/bw2_2_near_fps10 fps=10 zm=2
むー。いまいち中に入ってる感がよく分かりませんね。
拡散光の強さを算出する処理のところまで、別プロセスにやらせてみます。
データの拡散の係数や、複数の光源の情報を渡さねばならなりません。 可変長なデータのやりとりが出てきて、結構な変更量となりました。
今回は遠目の視点で試してみます。
$ cat v25.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make gcc -Wall -c -o sock.o sock.c gcc -Wall -c -o rt.o rt.c gcc -Wall -c -o cross.o cross.c gcc -Wall -c -o lstx.o lstx.c gcc -Wall -c -o ax.o ax.c gcc -Wall -c -o cylx.o cylx.c gcc -Wall -c -o fcx.o fcx.c gcc -Wall -c -o vecs.o vecs.c gcc -Wall -c -o line.o line.c gcc -Wall -c -o v.o v.c gcc -Wall -c -o mt.o mt.c gcc -o sock sock.o rt.o cross.o lstx.o ax.o cylx.o fcx.o vecs.o line.o v.o mt.o -lm $ ./cg.py eyep=[0,0,0],400,10 sec=10 data_name=ball_world2 name=out_v25/bw2_long_wf wf
$ ./cg.py eyep=[0,0,0],400,10 sec=10 data_name=ball_world2 name=out_v25/bw2_long div=2 use_srv srv_c : wh : 75775/76800(98.7%) : total 50.69s : rest 0.67s : 2018/04/20 06:02:32 wh : 76800/76800(100.0%) : fin 50.66s frm : 300/300(100.0%) : fin 3h 53m 0.30s
そして、いつものデータで速度比較。
まず従来方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v25/objs_1_2 n=1 init_sec=5 div=2 : wh : 76764/76800(100.0%) : total 7m 51.10s : rest 0.22s : 2018/04/20 09:17:53 wh : 76800/76800(100.0%) : fin 7m 50.96s 以前の v24 wh : 76800/76800(100.0%) : fin 7m 44.42s v23 wh : 76800/76800(100.0%) : fin 7m 48.33s
サーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v25/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76693/76800(99.9%) : total 9m 35.41s : rest 0.80s : 2018/04/20 09:29:17 wh : 76800/76800(100.0%) : fin 9m 34.91s 以前の v24 wh : 76800/76800(100.0%) : fin 9m 38.24s v23 wh : 76800/76800(100.0%) : fin 9m 9.07s
別プロセスのところをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v25/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 72244/76800(94.1%) : total 56.39s : rest 3.34s : 2018/04/20 09:32:56 wh : 76800/76800(100.0%) : fin 53.95s 以前の v24 wh : 76800/76800(100.0%) : fin 54.07s v23 wh : 76800/76800(100.0%) : fin 1m 50.29s
まぁ、さほど変わらずですね。
平面マッピング版の方でも、視点接近コースをゆっくり目で走らせてみます。
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v25/bw_near_2 div=2 use_srv srv_c : wh : 76463/76800(99.6%) : total 2m 2.65s : rest 0.53s : 2018/04/20 19:47:13 wh : 76800/76800(100.0%) : fin 2m 2.54s frm : 300/300(100.0%) : fin 9h 53m 50.62s
約10時間でした。
黒っぽい球にメーター表示。 むかーし小学校の頃見た、 松本零士大先生の「ダイバーゼロ」に、 確かこんな球体が出てきた覚えがあります。
画像ファイルや動画ファイルのピクセルデータを取得する処理を、 別プロセスのサーバに切り出してみます。
まぁこんな事をしたら、普通、動作は遅くなるはずです。
これは明日のための布石です。
ややこしいので、従来の交点を求めたりするサーバは、 rt server (レイトレサーバ) とでも呼んで区別するようにします。
$ cat v26.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make
いつものデータで速度比較。
まず従来方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2 n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 7m 31.17s 以前の v25 wh : 76800/76800(100.0%) : fin 7m 50.96s v24 wh : 76800/76800(100.0%) : fin 7m 44.42s v23 wh : 76800/76800(100.0%) : fin 7m 48.33s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2_is n=1 init_sec=5 div=2 use_img_srv : wh : 76800/76800(100.0%) : fin 8m 12.84s
( (8*60+12.84) / (7*60+31.17) - 1 ) * 100 = 9.23 パーセント低下
サーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76800/76800(100.0%) : fin 9m 22.96s 以前の v25 wh : 76800/76800(100.0%) : fin 9m 34.91s v24 wh : 76800/76800(100.0%) : fin 9m 38.24s v23 wh : 76800/76800(100.0%) : fin 9m 9.07s $ rm xdat
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2_s_is n=1 init_sec=5 div=2 use_srv use_img_srv : wh : 76800/76800(100.0%) : fin 9m 54.44s $ rm xdat
( (9*60+54.44) / (9*60+22.96) - 1 ) * 100 = 5.59 パーセント低下
別プロセスのところをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 76800/76800(100.0%) : fin 53.40s 以前の v25 wh : 76800/76800(100.0%) : fin 53.95s v24 wh : 76800/76800(100.0%) : fin 54.07s v23 wh : 76800/76800(100.0%) : fin 1m 50.29s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v26/objs_1_2_sc_is n=1 init_sec=5 div=2 use_srv srv_c use_img_srv : wh : 76800/76800(100.0%) : fin 1m 6.02s
( (1*60+6.02) / 53.40 - 1 ) * 100 = 23.63 パーセント低下
まぁそうですね。 画像のピクセルデータ取得処理に比べて、 他の箇所が速いほど低下は大きくなります。
では、v25の接近パターンの続きを...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v26/bw_near_2 div=2 use_srv srv_c use_img_srv init_sec=10 : wh : 75840/76800(98.8%) : total 3m 3.55s : rest 2.29s : 2018/04/21 13:43:12 wh : 76444/76800(99.5%) : total 3m 3.10s : rest 0.84s : 2018/04/21 13:43:12 wh : 76800/76800(100.0%) : fin 3m 2.88s frm : 81/300(27.0%) : total 14h 36m 51.49s : rest 10h 40m 6.39s : 2018/04/22 00:23:18 wh : 0/76800(0.0%) : not start yet Traceback (most recent call last): File "./img_sock.py", line 158, inf() File "./img_sock.py", line 137, in col col = img.col(*lst) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 139, in col return videos.col(fn, sec, x, y, def_col, rep) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 102, in col return img_sec(fn, sec)[y, x] TypeError: 'NoneType' object is not subscriptable Traceback (most recent call last): File "./cg.py", line 304, in f(data, lights, eye2g, wh2eye, sc_sz, video) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 149, in draw col = get_col(data, lights, l_g, sec) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 132, in get_col col_ = reflact_col() File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 129, in reflact_col col = get_col( data, lights, ref_l, sec, nest_rate * reflact, d ) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 132, in get_col col_ = reflact_col() File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 129, in reflact_col col = get_col( data, lights, ref_l, sec, nest_rate * reflact, d ) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 87, in get_col col = map_col( crs, rev, sec ) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 43, in map_col cols = ut.filter_lst( lambda col: col != [], cols ) File "/Users/kondoh/rt_wk/rt_v26/ut.py", line 14, in filter_lst = lambda f, lst: list( filter( f, lst ) ) File "/Users/kondoh/rt_wk/rt_v26/rt.py", line 40, in f return col_func( fn, sec, int(x), int(y), [], m.get('rep') ) File "/Users/kondoh/rt_wk/rt_v26/img_sock.py", line 79, in col (col_, s) = bin.unpack_col(s) File "/Users/kondoh/rt_wk/rt_v26/bin.py", line 27, in unpack_col ( col[i], s ) = unpack_i4(s) File "/Users/kondoh/rt_wk/rt_v26/bin.py", line 17, in unpack_i4 = lambda s: ( struct.unpack_from('=i', s)[0], s[4:] ) struct.error: unpack_from requires a buffer of at least 4 bytes
!?
先のエラーを追いかけます。
$ ls -lt out_v26/bw_near_2* | head -rw-r--r--@ 1 kondoh staff 416097 4 21 13:43 out_v26/bw_near_2.mp4 -rw-r--r-- 1 kondoh staff 28439 4 21 13:43 out_v26/bw_near_200080.jpg -rw-r--r-- 1 kondoh staff 28495 4 21 13:40 out_v26/bw_near_200079.jpg -rw-r--r-- 1 kondoh staff 28084 4 21 13:37 out_v26/bw_near_200078.jpg -rw-r--r-- 1 kondoh staff 27962 4 21 13:34 out_v26/bw_near_200077.jpg -rw-r--r-- 1 kondoh staff 27857 4 21 13:31 out_v26/bw_near_200076.jpg -rw-r--r-- 1 kondoh staff 27951 4 21 13:28 out_v26/bw_near_200075.jpg -rw-r--r-- 1 kondoh staff 27738 4 21 13:25 out_v26/bw_near_200074.jpg -rw-r--r-- 1 kondoh staff 27942 4 21 13:22 out_v26/bw_near_200073.jpg -rw-r--r-- 1 kondoh staff 27636 4 21 13:19 out_v26/bw_near_200072.jpg 0,1,2,... ときて 81の処理のどこかで起きてるようなので... 10 * 81 / 300 = 2.7 これで再現するだろうか $ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v26/dbg div=2 use_srv srv_c use_img_srv init_sec=12.7 OpenCV: FFMPEG: tag 0x34363248/'H264' is not supported with codec id 28 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x31637661/'avc1' frm : 0/300(0.0%) : not start yet wh : 0/76800(0.0%) : not start yet Traceback (most recent call last): File "./img_sock.py", line 158, inf() File "./img_sock.py", line 137, in col col = img.col(*lst) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 139, in col return videos.col(fn, sec, x, y, def_col, rep) File "/Users/kondoh/rt_wk/rt_v26/img.py", line 102, in col return img_sec(fn, sec)[y, x] TypeError: 'NoneType' object is not subscriptable 再現する
追いかけてみるとどうも
v26.patch diff -urN rt_v25/img.py rt_v26/img.py : - video = [] - while vc.isOpened(): - (ret, img) = vc.read() - if not ret: - break - video.append(img) - n = len(video) : + kd = { 'i': 1, 'w': 3, 'h': 4, 'fps': 5, 'n': 7 } + get_prop = lambda k: vc.get( kd.get(k) ) + set_prop = lambda k, v: vc.set( kd.get(k), v ) + fix_type = lambda k, v: int(v) if k != 'fps' else v + + dic = dict( map( lambda k: ( k, fix_type( k, get_prop(k) ) ), kd.keys() ) ) + + fps = dic.get('fps') + n = dic.get('n') :
ここで以前は動画ファイルに含まれるフレームの数nを、 最後までreadしみて決定してましたが、、、
今回のv26では、vc.get(7)で返る結果を使うように変更してました。
さらに、以前は最初に全フレームをreadして保持してましたが、 さすがにメモリを使い過ぎる気がして、 必要なときに vc.set(1, xxx) でseekしてreadするよう変更してました。
どうも、取得したフレーム数 n の範囲内でも、 read に失敗する現象が出てるようです。 (IMG_3999_3.mov の 171 フレームの read で失敗してます)
というか、以前は最初にまとめてreadして、 失敗した段階でそこまでのフレーム数を、動画ファイルのフレームと思っていた。
というか、というか、今回 vc.get(7) で取得するようにした値は、 動画ファイルに含まれるフレーム数として正しい値じゃなかった!?
動画ファイルを画像ファイルに展開してみて、 どこかでエラーがでるか試してみます。 $ ./img.py Usage: ./img.py img_name video_name fps=zm= cmd= fps is int value (default 30) zm is float value (default 1.0) cmd is v2i, i2v or play (default i2v) $ ./img.py out_v26/for_dbg_3 IMG_3999_3.mov cmd=v2i Traceback (most recent call last): File "./img.py", line 263, in video_to_imgs(img_name, video_name) File "./img.py", line 233, in video_to_imgs cv2.imwrite(fn, imgs[i] ) TypeError: 'map' object is not subscriptable bash-3.2$ って、これは違うエラー python3 対応もれ... とりあえず img.py : def read_video(fn): : #dic['imgs'] = lambda : map( img_idx, range(n) ) # func dic['imgs'] = lambda : ut.map_lst( img_idx, range(n) ) # func で修正して 次のパッチに入れるとして $ ./img.py out_v26/for_dbg_3 IMG_3999_3.mov cmd=v2i エラーはでませんな... ls -l out_v26/for_dbg_3* -rw-r--r-- 1 kondoh staff 79995 4 22 07:58 out_v26/for_dbg_300000.jpg -rw-r--r-- 1 kondoh staff 78942 4 22 07:58 out_v26/for_dbg_300001.jpg -rw-r--r-- 1 kondoh staff 78168 4 22 07:58 out_v26/for_dbg_300002.jpg : -rw-r--r-- 1 kondoh staff 66253 4 22 07:58 out_v26/for_dbg_300168.jpg -rw-r--r-- 1 kondoh staff 64499 4 22 07:58 out_v26/for_dbg_300169.jpg -rw-r--r-- 1 kondoh staff 67107 4 22 07:58 out_v26/for_dbg_300170.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300171.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300172.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300173.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300174.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300175.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300176.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300177.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300178.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300179.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300180.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300181.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300182.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300183.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300184.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300185.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300186.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300187.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300188.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300189.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300190.jpg -rw-r--r-- 1 kondoh staff 0 4 22 07:58 out_v26/for_dbg_300191.jpg ほれー! 171フレーム以降が 0 バイトになってる
さてどうしたものか
$ python Python 3.6.5 (default, Mar 30 2018, 06:41:49) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import cv2 >>> vc = cv2.VideoCapture('IMG_3999_3.mov') >>> vc.get(7) 192.0 >>> list(map( vc.get, range(8) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0] >>> list(map( vc.get, range(9) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0] >>> list(map( vc.get, range(10) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0, 0.0] >>> list(map( vc.get, range(11) )) [0.0, 0.0, 0.0016666666666666668, 640.0, 360.0, 28.64246643460965, 828601953.0, 192.0, 0.0, 0.0, 0.0]
確かに192を返してて、他に171を返すようなプロパティは無さそうですね...
全部メモリに保持するのは避けるとして、 時間はかかりますが、最初に空読みしてread可能なフレーム数だけ調べる対応にしてみますかな。
img.py : def read_video(fn): vc = cv2.VideoCapture(fn) kd = { 'i': 1, 'w': 3, 'h': 4, 'fps': 5, 'n': 7 } get_prop = lambda k: vc.get( kd.get(k) ) set_prop = lambda k, v: vc.set( kd.get(k), v ) fix_type = lambda k, v: int(v) if k != 'fps' else v dic = dict( map( lambda k: ( k, fix_type( k, get_prop(k) ) ), kd.keys() ) ) fps = dic.get('fps') n = dic.get('n') # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) : if 'img' not in dic: ( ret, dic['img'] ) = vc.read() if not ret: sys.stderr.write( 'err i/n={}/{}\n'.format( dic.get('i'), dic.get('n') ) ) return dic.get('img')
これならどうか? 解像度を落としてエラーチェック。
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 : wh : 300/300(100.0%) : fin 0.80s frm : 65/300(21.7%) : total 4m 8.20s : rest 3m 14.42s : 2018/04/22 09:52:53 wh : 0/300(0.0%) : not start yet wh : 300/300(100.0%) : fin 0.80s wh : 0/300(0.0%) : not start yet err i/n=171/178 Traceback (most recent call last): File "./img_sock.py", line 158, inf() File "./img_sock.py", line 137, in col col = img.col(*lst) File "/Users/kondoh/rt_wk/rt_v27/img.py", line 149, in col return videos.col(fn, sec, x, y, def_col, rep) File "/Users/kondoh/rt_wk/rt_v27/img.py", line 112, in col return img_sec(fn, sec)[y, x] TypeError: 'NoneType' object is not subscriptable Traceback (most recent call last):
vc.get(7)のプロパティは192が返って、 最初にまとめてread()すると177まで成功するので178フレーム分あると思ってたら、 seekしてやり読み直してると171のreadでエラー!?。
n = dic.get('n') # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0)
seekで先頭に戻してもう一度最初からreadしてみると...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 : err i/n=171/178 :
n=178表示は1回しか出ないので、2回目の171もreadできてる様子?
# get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break for i in [171, 170, 172]: set_prop('i', i) (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
さらに171にseekしてread、170にseekしてread、172にseekしてreadを試すと...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 171 ret=False 170 ret=True 172 ret=False :
連続してreadすると177までOKで、seekしてreadするときは170まではOKとかなのだろうか?
: for i in [171, 170, 172]: set_prop('i', i) (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 170) for i in range(3): i += 170 (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
170read成功のあと、seekなしで連続でreadしてみると...
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 171 ret=False 170 ret=True 172 ret=False 170 ret=True 171 ret=False 172 ret=False
いちどerrが出てしまうと、もうだめとか?
# get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break set_prop('i', 0) for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i sys.stderr.write( 'n={}\n'.format(n) ) break #for i in [171, 170, 172]: # set_prop('i', i) # (ret, _) = vc.read() # sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 170) for i in range(3): i += 170 (ret, _) = vc.read() sys.stderr.write( '{} ret={}\n'.format(i, ret) ) set_prop('i', 0)
いかに?
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 n=178 170 ret=True 171 ret=False 172 ret=False
seek 0のあとは178までread OKで、 seek 170すると171でNG ? 確認
$ python >>> import cv2 >>> vc = cv2.VideoCapture('IMG_3999_3.mov') >>> vc.set(1, 170) True >>> vc.read() (True, array([[[ 10, 15, 15], [ 10, 15, 15], [ 10, 15, 15], ..., [ 21, 24, 29], : >>> vc.get(1) 171.0 >>> (ret,_) = vc.read() >>> ret False >>> vc.set(1, 0) True >>> vc.get(1) 0.0 >>> for i in range(169): ... (ret, _) = vc.read() ... >>> (ret, _) = vc.read() >>> ret True >>> (ret, _) = vc.read() >>> ret True >>> (ret, _) = vc.read() >>> ret True >>> vc.get(1) 172.0
確かに、0から連続してreadしてる分には171もread OK
さてどうしたものか。
最初連続readで上限を取得しておいて、 つかってて途中でエラーでたら、 seek 0で先頭からreadしてなんとかするとか。
def err_recover(): if vc.isOpened(): vc.open(fn) if 'img' in dic: dic.pop('img') if get_prop('i') != 0: set_prop('i', 0) # get_prop(7) is doubt for i in range(n): (ret, _) = vc.read() if not ret or len(_) == 0: dic['n'] = n = i break err_recover() def img_idx(i): i %= n # loop if 'img' in dic and dic.get('i') != i: dic.pop('img') if dic.get('i')+1 != i: set_prop('i', i) dic['i'] = i if 'img' not in dic: ( ret, dic['img'] ) = vc.read() if not ret: err_recover() for j in range(i+1): ( ret, dic['img'] ) = vc.read() if not ret: sys.stderr.write( 'err {} {}/{}\n'.format( fn, j, dic.get('n') ) ) dic['i'] = i return dic.get('img') dic['img_idx'] = img_idx
これでトライ
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_32 div=32 use_srv srv_c use_img_srv init_sec=10 : wh : 300/300(100.0%) : fin 0.67s frm : 300/300(100.0%) : fin 3m 38.28s
一応エラーではとまらなくなりました。
パッチを作っておいて。
それでは、前回のリベンジ。
$ ./cg.py eyep=[0,0,0],50,20 sec=10 data_name=ball_world name=out_v27/bw_near_2 div=2 use_srv srv_c use_img_srv init_sec=10 : wh : 76530/76800(99.6%) : total 2m 44.76s : rest 0.57s : 2018/04/23 04:08:46 wh : 76800/76800(100.0%) : fin 2m 44.74s frm : 300/300(100.0%) : fin 14h 22m 30.00s
とりあえずエラーでとまらずに10秒の動画を生成できました。 14時間半。画像サーバに切り出す前は確か11時間半。
では、いつものデータで速度比較。
まず従来方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2 n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 7m 45.41s 以前の v26 wh : 76800/76800(100.0%) : fin 7m 31.17s v25 wh : 76800/76800(100.0%) : fin 7m 50.96s v24 wh : 76800/76800(100.0%) : fin 7m 44.42s v23 wh : 76800/76800(100.0%) : fin 7m 48.33s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_is n=1 init_sec=5 div=2 use_img_srv : wh : 76800/76800(100.0%) : fin 8m 19.96s 以前の v26 wh : 76800/76800(100.0%) : fin 8m 12.84s
レイトレ用のサーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76800/76800(100.0%) : fin 9m 18.49s 以前の v26 wh : 76800/76800(100.0%) : fin 9m 22.96s v25 wh : 76800/76800(100.0%) : fin 9m 34.91s v24 wh : 76800/76800(100.0%) : fin 9m 38.24s v23 wh : 76800/76800(100.0%) : fin 9m 9.07s $ rm xdat
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_s_is n=1 init_sec=5 div=2 use_srv use_img_srv : wh : 76800/76800(100.0%) : fin 9m 53.40s 以前の v26 wh : 76800/76800(100.0%) : fin 9m 54.44s $ rm xdat
レイトレ用のサーバプロセスをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 76800/76800(100.0%) : fin 53.66s 以前の v26 wh : 76800/76800(100.0%) : fin 53.40s v25 wh : 76800/76800(100.0%) : fin 53.95s v24 wh : 76800/76800(100.0%) : fin 54.07s v23 wh : 76800/76800(100.0%) : fin 1m 50.29s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v27/objs_1_2_sc_is n=1 init_sec=5 div=2 use_srv srv_c use_img_srv : wh : 76800/76800(100.0%) : fin 1m 8.39s 以前の v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
まぁ、変わらず。
rt_sock.py と img_sock.py が同じようなコードなので、sock.py として括り出してまとめてみました。
あと、あんちょこファイルのsave, loadは、もう役目を終えたようなので廃止しておきます。
$ cat v28.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make
まず、いつものデータで速度比較。
まず従来方式
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2 n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 7m 42.09s 以前の v27 wh : 76800/76800(100.0%) : fin 7m 45.41s v26 wh : 76800/76800(100.0%) : fin 7m 31.17s v25 wh : 76800/76800(100.0%) : fin 7m 50.96s v24 wh : 76800/76800(100.0%) : fin 7m 44.42s v23 wh : 76800/76800(100.0%) : fin 7m 48.33s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2_is n=1 init_sec=5 div=2 use_img_srv : wh : 76800/76800(100.0%) : fin 8m 5.03s 以前の v27 wh : 76800/76800(100.0%) : fin 8m 19.96s v26 wh : 76800/76800(100.0%) : fin 8m 12.84s
サーバプロセス分離版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2_s n=1 init_sec=5 div=2 use_srv : wh : 76800/76800(100.0%) : fin 9m 34.23s 以前の v27 wh : 76800/76800(100.0%) : fin 9m 18.49s v26 wh : 76800/76800(100.0%) : fin 9m 22.96s v25 wh : 76800/76800(100.0%) : fin 9m 34.91s v24 wh : 76800/76800(100.0%) : fin 9m 38.24s v23 wh : 76800/76800(100.0%) : fin 9m 9.07s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2_s_is n=1 init_sec=5 div=2 use_srv use_img_srv : wh : 76800/76800(100.0%) : fin 10m 9.66s 以前の v27 wh : 76800/76800(100.0%) : fin 9m 53.40s v26 wh : 76800/76800(100.0%) : fin 9m 54.44s
別プロセスのところをC言語で実装版
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2_sc n=1 init_sec=5 div=2 use_srv srv_c : wh : 76800/76800(100.0%) : fin 1m 3.32s 以前の v27 wh : 76800/76800(100.0%) : fin 53.66s v26 wh : 76800/76800(100.0%) : fin 53.40s v25 wh : 76800/76800(100.0%) : fin 53.95s v24 wh : 76800/76800(100.0%) : fin 54.07s v23 wh : 76800/76800(100.0%) : fin 1m 50.29s
イメージ用のサーバプロセスを使う場合は
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v28/objs_1_2_sc_is n=1 init_sec=5 div=2 use_srv srv_c use_img_srv : wh : 76800/76800(100.0%) : fin 1m 18.06s 以前の v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
肝心の「別プロセスのところをC言語で実装版」で、大きく低下してるのがまずいですね。 サーバからの結果を受け取ってからの処理に手を入れてる影響かもしれません。 1度listにしてからdictにしてるので、もうちょっと良く考えるべしですね。
v25で生成した動画と、その続きとしてv27で生成した動画をつないでおきます。
$ ./img.py tmp/a1 out_v25/bw_near_2.mp4 cmd=v2i $ ./img.py tmp/a2 out_v27/bw_near_2.mp4 cmd=v2i $ ./img.py tmp/a out_v28/bw_near_2.mp4 $ ls -l out_v28/bw_near_2.mp4 -rw-r--r-- 1 kondoh staff 2437277 4 24 01:20 out_v28/bw_near_2.mp4 セーフ。まだ3Mバイトを超えてません。
コードの整理をどんどん進めてるうちに、結構手が入ってしまいました。
まず「値」サーバなるものを追加しました。
これはファイルパスの文字列を整数値で扱いたいために考えたサーバで、 パス文字列をサーバの中のリストに登録追加していって、 サーバに登録済みの文字列を渡すとリスト中のインデックスの整数が返り、 整数を渡すと対応する文字列が返る。
というような動作をするものでした。
まず、この登録文字列に対して「インデックス以外の整数でも返せるようにしたいなぁ」 というところから、プロパティの値を別に持たせるようにしようと。
ならば、値は整数だけじゃなく他の値も返してくれたら便利では?
プロパティの型情報も保持させなきゃ。
サーバとの通信で値を流すなら、ちゃんとシリアライズできねば。
可変長のリストもプロパティの値として扱いたいなぁ。
どうせなら辞書の形式も。
どんどん妄想が膨らんでしまい、bin.py pks.py sock.py val.py の辺りに落ち着きました。
あと、画像、動画を参照するサーバもかなり手を入れました。 結局動画の読み込みは、1つのフレームの画像を辞書で保持してメモリ使いまくり方式に。 そして呼び出して使う側もサーバを使う前提固定に。
$ cat v29.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make
色々と整理したところで、 とりあえず交点を求める処理のサーバだけC言語版を実装して、 とりあえず処理速度の測定。
別プロセスのところをC言語で実装版でイメージ用のサーバプロセスを使う場合
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v29/objs_1_2_sc n=1 init_sec=5 div=2 use_srv : wh : 76800/76800(100.0%) : fin 1m 44.72s 以前の v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
一方、処理速度はじわじわ低下する一方。
サーバ群は起動しっぱなしなので、落としたい場合はとりあえずkillコマンドで。
$ ps ax | grep ' boot$' 20739 ?? Ss 0:04.73 /usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python ./val.py boot 20750 ?? Ss 0:18.00 /usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python ./img.py boot 20765 ?? SNs 0:15.19 ./cross boot $ ps ax | grep ' boot$' | cut -d ' ' -f1 20739 20750 20765 $ ps ax | grep ' boot$' | cut -d ' ' -f1 | xargs kill $ ps ax | grep ' boot$' $
rt.pyの主要部分のコードを徐々にrt.cに移して試してますが... 1つの壁は「get_col()の再帰」です。
このあたりでpython側とC側を行ったり来たりしていては、 結局もたもたして速度が上がりませぬ。
という事でget_col()ごとゴッソリとrt.cへ持って行ってみました。
$ cat v30.patch | ( cd rt ; patch -p1 ) $ cd rt $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v30/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 38.39s 以前の v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
大幅に短縮! よしよし v^_^)
そして起動しっぱなしのサーバを落とすには、
$ ps ax | grep ' boot$' | cut -d ' ' -f1 | xargs kill
そのうち、もうちょっと簡単な方法を用意せねば...
例のデータでも試してみます。 まずは荒い解像度で。
$ ./cg.py eyep=[100,0,0],100,5 sec=10 data_name=ball_world name=out_v30/bw_tst div=32 : frm : 300/300(100.0%) : fin 1m 39.28s
解像度フルでの予想時間は
( (60+39.28) *32*32 ) /60/60 = 28.23 時間
div=2の設定ならば
( (60+39.28) *16*16 ) /60/60 = 7.05 時間
ここらで手を打ってみましょう。
$ ./cg.py eyep=[100,0,0],100,5 sec=10 data_name=ball_world name=out_v30/bw_2 div=2 : wh : 76800/76800(100.0%) : fin 1m 5.33s frm : 300/300(100.0%) : fin 5h 22m 17.99s
予想より若干短く5時間半弱。
視点移動の中心をちょっとずらしたので、5秒あたりで真上からのアングルになった瞬間、 カメラの姿勢がロール方向に180度回転。 一瞬で球と立方体の位置関係が入れ替わって見えてます。
おうちに転がってるネットブックな非力マシン ASUS Eee PC 901。
このマシンでもレイトレーシングの計算のお手伝いをさせてみようかと。
久しぶりに起動。
$ uname -a Linux kondoh-901 3.13.0-66-generic #108-Ubuntu SMP Wed Oct 7 15:21:40 UTC 2015 i686 i686 i686 GNU/Linux $ cat /etc/issue Ubuntu 14.04.3 LTS \n \l $ dmesg | grep 'CPU.*Intel' [ 0.082673] smpboot: CPU0: Intel(R) Atom(TM) CPU N270 @ 1.60GHz (fam: 06, model: 1c, stepping: 02) $ ps ax | grep sshd | grep -v grep $
とりあえず sshd をば
$ sudo apt-get update $ sudo apt-get install openssh-server $ ps ax | grep sshd | grep -v grep 5932 ? Ss 0:00 /usr/sbin/sshd -D $ $ ifconfig -a : wlan0 Link encap:イーサネット ハードウェアアドレス 00:15:af:e7:01:99 inetアドレス:192.168.1.9 ブロードキャスト:192.168.1.255 マスク:255.255.255.0 :
では、Macからlogin
$ ssh 192.168.1.9 The authenticity of host '192.168.1.9 (192.168.1.9)' can't be established. ECDSA key fingerprint is SHA256:OH5rwJOAh88nkIFuP9r8jdvYOgIZ9ewRBGS5qioQjp4. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.1.9' (ECDSA) to the list of known hosts. kondoh@192.168.1.9's password: [パスワード入力] Welcome to Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-66-generic i686) * Documentation: https://help.ubuntu.com/ : $
pythonは?
$ which python /usr/bin/python $ python Python 2.7.6 (default, Jun 22 2015, 18:00:18) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> ^D $
numpy はインストールした覚えがないのでとりあえず入れておきます。
$ sudo apt-get install python-numpy $ python : >>> import numpy >>> >>> ^D $ $ exit
Mac側に戻って今回のパッチ。
$ cat v31.patch | ( cd rt ; patch -p1 ) $ mkdir ttt $ tar cf - rt | tar xf - -C ttt $ mv ttt/rt rt_v31 $ rmdir ttt $ cd rt_v31 $ make clean $ make
今回は都合でディレクトリ名は rt/ じゃなくて rt_v31/ にしてます。
そして、ちょっとやばそうなツールを作ってみました。 まぁ自分のマシンで勝手に試すだけなので...
$ ./cmd_send.py host=192.168.1.9 cmd="tar cf - cmd.py | ssh -R55511:localhost:55511 -R55512:localhost:55512 \ -L55520:localhost:55510 -L55523:localhost:55513 -L55524:localhost:55514 \ -L55525:localhost:55515 -L55526:localhost:55516 -L55527:localhost:55517 \ -L55528:localhost:55518 -L55529:localhost:55519 192.168.1.9 "cd /tmp ; tar xf - ; ./cmd.py port=55510"" kondoh@192.168.1.9's password: [ パスワード入力 ]
sshでMacから192.168.1.9のネットブックに接続しますが、 -R と -L オプションでポートフォワーディングの設定をしてます。
Macのポート55511, 55512 をネットブックに見せつつ、 ネットブックのポート 55510, 55513, 55514 ... 55519 を、 Macの55520, 55523, 55524 ... 55529 として、 +10したポートで見えるようにしてます。
Macで起動するsshの標準入力に cmd.py をtarでアーカイブしたデータをながしつつ、
tar cf - cmd.py | ssh ...
ssh でログインした先のネットブック上では、 /tmp に移動して、そこに標準入力から cmd.py のアーカイブデータを展開。 展開したての cmd.py をオプション port=55510 を指定して実行します。
... cd /tmp/ ; tar xf - ; ./cmd.py port=55510
cmd_send.py コマンドは起動したままにして、sshの接続を保っておきます。 これでネットブックへのバックドアの仕込み完了。 ネットブックのポート55510でコマンドを受け付ける口をあけてます。 このポートはsshの経路を通して、Mac側のポート55520として見えてます。
Mac側から $ echo hostname | nc localhost 55520 kondoh-901 $ $ echo pwd | nc localhost 55520 /tmp $
つづいて、Macからソースコードを送りつけてビルドします。
$ make clean $ ./src_send.py path=../rt_v31 d=.. n=rt_v31 rmt_cmd=echo "nc localhost -l 55519 | tar xf -" | nc localhost 55520 lcl_cmd=tar cf - -C .. rt_v31 | nc localhost 55529 wait cmd=echo "cd rt_v31 ; make clean ; make" | nc localhost 55520 $ $ echo ls | nc localhost 55520 cmd.py config-err-cLU0tn rt_v31 $ $ make
やってる事は
ここで使うポートの決め事を少々
srvs.py に記録してる : base_port = 55500 :
55500 からの 100ポート分を予約です。
10の位の値は 1: 起動してるサーバが使用 2: ネットブック側で起動してるサーバをMac側から見えるポート 下1桁の割り振りは 0: コマンド実行用 1: 値サーバ val.py 2: 画像サーバ img.py 3: レイトレサーバ rt 4: 交点を求める用のサーバ cross (今回使わず) : 9: ファイルコピー時にデータを流す用
Mac側で実行してる、値サーバ 55511 と 画像サーバ 55512 は、 ネットブック側でも ssh のポートフォワーディングで、 同じ 55511, 55512 として見えてます。
srvs.py の infs = [ ... ] で設定している 'srv.rt-2' がネットブック側で実行するレイトレサーバの設定になります。
base_port = 55500 infs = [ ( 'srv.val', { 'port': base_port + 11, 'cmd': './val.py boot', 'pid': -1 } ), ( 'srv.img', { 'port': base_port + 12, 'cmd': './img.py boot', 'pid': -1 } ), ( 'srv.rt', { 'port': base_port + 13, 'cmd': './rt boot', 'pid': -1 } ), ( 'srv.cross', { 'port': base_port + 14, 'cmd': './cross boot', 'pid': -1 } ), ( 'srv.rt-2', { 'port': base_port + 23, 'cmd': 'echo "cd rt_v31 ; ./rt boot" | nc localhost {}'.format(base_port + 20), 'pid': -1 } ), ]
'srv.rt-2' を起動するためのコマンド文字列が、 "cd rt_v31 ; ./rt boot" という文字列を、ポート55520 にncで送り込むコマンドになってます。
これでネットブックの55513ポートを使うレイトレサーバrtがネットブックで起動しますが、 ssh の設定でMac側の55523ポートとして見えることになります。
仕込みが完了したところでお試し実行。
Mac側から $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v31/objs_1_2_sc n=1 init_sec=5 div=2 : conn srv.val 55511 ... err [Errno 61] Connection refused boot ./val.py boot conn srv.val 55511 ... ok boot ./img.py boot conn srv.val 55511 ... ok conn srv.img 55512 ... ok OpenCV: FFMPEG: tag 0x34363248/'H264' is not supported with codec id 28 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x31637661/'avc1' frm : 0/1(0.0%) : not start yet wh : 0/76800(0.0%) : not start yet boot ./rt boot boot echo "cd rt_v31 ; ./rt boot" | nc localhost 55520 conn srv.rt 55513 ... conn srv.rt-2 55523 ... ok ok wh : 2/76800(0.0%) : total 10h 58m 28.06s : rest 10h 58m 27.03s : 2018/05/07 03:31:42 wh : 4925/76800(6.4%) : total 31.63s : rest 29.60s : 2018/05/06 16:33:45 wh : 9829/76800(12.8%) : total 23.66s : rest 20.63s : 2018/05/06 16:33:37 : wh : 74467/76800(97.0%) : total 41.29s : rest 1.25s : 2018/05/06 16:33:55 wh : 76800/76800(100.0%) : fin 40.50s
conn srv.val 55511 ... err
については、まず値サーバに接続を試してみて失敗すれば、起動を試みるようにしてるので想定通りです。
以前の v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
なんと、ネットブックに手伝ってもらった方が足を引っ張られてる感じでしょうか。
rt.py の
: def func(cli): while True: lock.acquire() run = cnt.up(show) (ix, iy) = cnt.cur() #print('{} {} {}'.format(cli.name, ix, iy)) lock.release() if not run: break :
コメントアウトしてるprint()を有効にしてみると
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v31/objs_1_2_sc n=1 init_sec=5 div=2 > log1 $ head log1 conn srv.val 55511 ... ok conn srv.img 55512 ... ok frm : 0/1(0.0%) : not start yet wh : 0/76800(0.0%) : not start yet srv.rt 0 0 srv.rt-2 1 0 conn srv.rt 55513 ... conn srv.rt-2 55523 ... ok ok srv.rt 2 0 srv.rt 3 0 $ $ grep '^srv.rt-2 ' log1 | head srv.rt-2 1 0 srv.rt-2 11 1 srv.rt-2 173 1 srv.rt-2 58 2 srv.rt-2 243 2 srv.rt-2 112 3 srv.rt-2 319 3 srv.rt-2 173 4 srv.rt-2 47 5 srv.rt-2 249 5 $ grep '^srv.rt ' log1 | wc -l 76332 $ grep '^srv.rt-2 ' log1 | wc -l 470 320*240 = 76800 なので 470/76800*100 = 0.61 ネットブックは0.61パーセントしか力になってませんでしたか...
起動したままのサーバを落としておきます。
Mac側から $ ps ax | grep boot | grep -v grep 33484 ?? Ss 0:08.91 /usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python ./val.py boot 33491 ?? Ss 0:29.44 /usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python ./img.py boot 33498 ?? SNs 0:16.92 ./rt boot 33499 ?? SNs 0:00.01 /bin/sh -c echo "cd rt_v31 ; ./rt boot" | nc localhost 55520 $ ./srvs.py kill_all conn srv.val 55511 ... ok kill srv.img pid=33491 kill srv.rt pid=33498 kill srv.rt-2 pid=33499 kill srv.val pid=33484 $ ps ax | grep boot | grep -v grep $ $ echo "ps ax | grep boot | grep -v grep" | nc localhost 55520 12862 ? S 0:00 /bin/sh -c cd rt_v31 ; ./rt boot 12863 ? S 0:01 ./rt boot $ ./kill_str.py 'rt boot' ps ax | grep 'rt boot' | grep -v grep | sed 's/^ *//' | cut -d ' ' -f1 | xargs kill $ ./kill_str.py 'rt boot' | nc localhost 55520 $ echo "ps ax | grep boot | grep -v grep" | nc localhost 55520 $
1つのMacの中で複数のレイトレサーバを起動して試してみます。
$ mv rt_v31 rt_v32 $ cat v32.patch | ( cd rt_v32 ; patch -p1 ) $ cd rt_v32 $ make clean $ make
rt.py の names の箇所
: names = [ 'srv.rt', 'srv.rt-14', 'srv.rt-15', 'srv.rt-16', 'srv.rt-17', 'srv.rt-18' ] names = names[:2] :
この箇所で起動するレイトレサーバの数を調整します。
まずサーバ1つの設定に書き換えて
: names = names[:1] :
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v32/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 39.83s
以前の v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
サーバ数を2に戻して
: names = names[:2] :
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v32/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 26.84s
サーバ数を3,4,5,6で順次試すと
names = names[:3] wh : 76800/76800(100.0%) : fin 28.43s names = names[:4] wh : 76800/76800(100.0%) : fin 28.81s names = names[:5] wh : 76800/76800(100.0%) : fin 29.13s names = names[:6] wh : 76800/76800(100.0%) : fin 29.35s
サーバ2つが最速でじわじわ劣化していきますね。 いづれにせよ1つの処理プロセスだけでは、コアを使い切れてなかったのは確かなようです。
サーバ2つの最速設定に戻して、 時間のかかっていた以前のデータで描画を試してみます。
names = names[:2] $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v32/objs_tst fps=1 : wh : 307200/307200(100.0%) : fin 2m 9.34s frm : 10/10(100.0%) : fin 19m 35.11s
fps=30での予想時間は ( 19*60+35.11 ) * 30 / 60/60 = 9.79時間
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v32/objs : wh : 305132/307200(99.3%) : total 2m 14.94s : rest 0.90s : 2018/05/07 08:15:45 wh : 307200/307200(100.0%) : fin 2m 14.93s frm : 300/300(100.0%) : fin 10h 2m 5.22s
$ ./cg.py eyep=[0,0,0],50,10 sec=10 data_name=objs name=out_v32/objs_near : wh : 307200/307200(100.0%) : fin 2m 4.99s frm : 300/300(100.0%) : fin 10h 27m 29.13s $ ./srvs.py kill_all
ちとアングルが近過ぎた。
ワイヤーフレーム表示を永らく試してなかったら、まともに動かなくなってました。 修正しておきます。
ball_world2のデータを試そうとすると、マシンによってはmalloc()しすぎのエラーで落ちてました。
この現象の原因は、円柱マッピングのデータを受け取るC言語側の構造体が、 マシンによってはパディングが入り、後続のデータ解釈にズレが出るためでした。 修正しておきます。
サーバを終了してから数分待たずに同じアドレスでbindしようとすると
OSError: [Errno 48] Address already in use
が出てしまうのがアレなので、setsockopt で SO_REUSEADDR を設定するようにしてみました。
あと、src_send.py からの nc と tar によるファイルコピーで、 サイズが大きいと落ちる現象が出てしまうのですが、、、 原因が突き止められてません(>_<)
$ mv rt_v32 rt_v33 $ cat v33.patch | ( cd rt_v33 ; patch -p1 ) $ cd rt_v33 $ make clean $ make
$ ./cg.py eyep=[100,0,0],100,5 sec=10 data_name=ball_world2 name=out_v33/bw2_wf wf : frm : 300/300(100.0%) : fin 42.18s
$ ./cg.py eyep=[100,0,0],100,5 sec=10 data_name=ball_world2 name=out_v33/bw2 : wh : 307200/307200(100.0%) : fin 3m 14.75s frm : 300/300(100.0%) : fin 14h 43m 10.50s $ ./srvs.py kill_all
-rw-r--r-- 1 kondoh staff 3394859 5 8 20:41 bw2.mp4
おっと3Mバイト制限!
動画ファイルをほどいて、 適当に3Mになるまで末尾を削る機能を img.py に追加しておきます。(パッチは次回に含めます)
まず、前回で未解決だった問題。
あと、src_send.py からの nc と tar によるファイルコピーで、 サイズが大きいと落ちる現象が出てしまうのですが、、、 原因が突き止められてません(>_<)
判りました。
色々試してみると、 sshでリモートマシンに手動でログインして、手動でcmd.pyを起動した場合では何の問題も出ず。 cmd_send.py で cmd.py をリモートマシンに送りつけて起動すると、問題が出ます。 怪しい。
cmd_send.py の
rmt_cmd = 'cd /tmp ; tar xf - ; ./cmd.py port={}'.format( get_port(lcl_base, cmd) ) cmd = 'tar cf - cmd.py | ssh {} {} {} "{}"'.format(opt_exp, opt_fwd, rmt_host, rmt_cmd)
ここ!
ここで、リモートマシン側で ./cmd.py を起動するときの標準入力が、 sshを経由して、接続元のローカルマシンで流し込んだ 「tarデータの終端」が見えてる状態になってました。
cmd.pyから起動する全てのコマンドの標準入力は、この状態を受け継いでました。 ファイルコピー用のデータを受け取るncコマンドも例外やおまへん。 ncは標準入力から読み込み、接続先のソケットに送信しようとしますが、 標準入力では「データの終端」EOFが見えてるので、終了してしまう。
さてどうしたものか。 発想を切り替えて、ファイルコピー時はローカルマシン側でncをサーバに、 リモートマシン側でncをクライアントにして対応してみました。
ローカルマシン側でncサーバをたてて、誰かが繋ぎにきたらtarデータを送りつけます。
リモートマシン側ではssh経由でncクライアントを起動して、ローカルマシンに繋ぎにいきます。 繋がるとtarデータが流れてくるので、tarコマンドで受けて展開します。
これでsshの標準入力にtarデータを流さずともよろしかろうと。
あと明日への布石のため、動画を書き込む処理を画像サーバに含めてしまいました。
こうしておけば、複数のレイトレサーバが個別にピクセルを処理した後、 おのおのが画像サーバに結果を渡せるようになるはずです。 レイトレサーバに一度に複数のピクセルを処理させるための変更が、楽になりそうです。
$ mv rt_v33 rt_v34 $ cat v34.patch | ( cd rt_v34 ; patch -p1 ) $ cd rt_v34 $ make clean $ make
では、速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v34/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 38.47s
以前の v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
速度的には後退。 まぁそうなりますよね。 明日への布石という事で。
視点移動の高さ方向を抑制してみてobjsのデータを眺めてみます。
$ ./cg.py eyep=[0,0,12],[100,100,10],10 sec=10 data_name=objs name=out_v34/objs_tst div=4 fps=1 : wh : 18860/19200(98.2%) : total 14.25s : rest 0.25s : 2018/05/09 01:29:10 wh : 19200/19200(100.0%) : fin 14.27s frm : 10/10(100.0%) : fin 2m 10.59s
( 2*60+10.59 ) * 4 * 4 * 30 / 60 / 60 = 17.41 時間の予想
$ ./cg.py eyep=[0,0,12],[100,100,10],10 sec=10 data_name=objs name=out_v34/objs : wh : 307200/307200(100.0%) : fin 3m 41.64s frm : 300/300(100.0%) : fin 17h 46m 26.78s
ほぼ予想時間通りでした。
ベンチマークでさんざんしがんだデータでも、視点を変えてみるとまた違った味わいがありますね。
レイトレサーバに一度に複数のピクセルを処理させるための変更をしてみました。
また、画像サーバ側も一度に複数のピクセルを書き込めるように変更しております。
rt.py : names = names[:2] : rates = map( lambda name: 0.2 / len(names), names ) :
1つのrtサーバが一度に処理するピクセル数は、 1枚の画面のピクセル数の20パーセントを、rtサーバ数で割った数にしてみました。
同じくらいの処理能力のrtサーバならば、 1つのrtサーバあたり5回まわれば、画面が1つ描画されます。
$ mv rt_v34 rt_v35 $ cat v35.patch | ( cd rt_v35 ; patch -p1 ) $ cd rt_v35 $ make clean $ make
では、速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v35/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 16.16s
以前の v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
最速出ました v^_^)
(1 - 16.16/26.84) * 100 = 39.79
過去の最速から約40パーセント短縮です。
今回は裏面も見えるようにズラしてみます。 まず荒削り設定で。
$ ./cg.py eyep=[0,0,-5],[100,100,10],10 sec=10 data_name=objs name=out_v35/objs_tst div=4 fps=10 : wh : 19200/19200(100.0%) : fin 4.67s frm : 100/100(100.0%) : fin 8m 42.26s
(8*60+42.26) *4*4*3 /60/60 = 6.96 時間の予想
このデータ、初期の頃では10秒の動画を作るのに、15日くらいかかる予想が出てたはずです。 荒削りで10分未満、フルでも7時間の予想。本当だろうか?
$ ./cg.py eyep=[0,0,-5],[100,100,10],10 sec=10 data_name=objs name=out_v35/objs : wh : 307200/307200(100.0%) : fin 1m 19.09s frm : 300/300(100.0%) : fin 8h 7m 5.64s
8時間でした。
-rw-r--r-- 1 kondoh staff 2722444 5 9 19:45 out_v34/objs.mp4 -rw-r--r-- 1 kondoh staff 1889074 5 10 07:11 out_v35/objs.mp4
3M制限もOK。 同じ10秒の動画でも、フレームごとの単純さとフレーム間の変化の具合で、ファイルサイズはバラバラです。
さらに、続きの10秒を。
$ ./cg.py eyep=[0,0,-5],[100,100,10],10 sec=10 data_name=objs name=out_v35/objs_s10 init_sec=10 : wh : 307200/307200(100.0%) : fin 55.07s frm : 300/300(100.0%) : fin 7h 17m 34.75s $ ./srvs.py all_kill
-rw-r--r-- 1 kondoh staff 1711910 5 11 03:44 out_v35/objs_s10.mp4
繋ぎ合わせてみます。
$ (cd out_v35 ; ls objs_s10*.jpg | sed -e 's/objs_s10\(.*\)/mv objs_s10\1 objs1\1/' | sh) $ ls out_v35 | head objs100001.jpg objs100002.jpg objs100003.jpg objs100004.jpg objs100005.jpg objs100006.jpg objs100007.jpg objs100008.jpg objs100009.jpg objs100010.jpg $ ./img.py out_v35/objs out_v35/objs.mp4 cmd=v2i $ ls -l out_v35/objs_sum.mp4 -rw-r--r-- 1 kondoh staff 3484415 5 11 04:08 out_v35/objs_sum.mp4 20秒だとさすがに3M超えました。 3M分のフレームまでにするツールの処理を、 バイナリサーチを使うように改良したので試しておきます。 $ ./img.py dmy out_v35/objs_sum.mp4 cmd=3M $ ls -l v.mp4 -rw-r--r-- 1 kondoh wheel 3144776 5 11 04:15 v.mp4 OK 3M以内。 $ cp v.mp4 out_v35/objs_sum_3m.mp4
同じ物体をコピーして繰り返し位置をズラして配置できるようにしてみました。
もともと立方体(cube)などのデータは、dat.py d_setup(d) 関数で、 6つの四角平面(square)に展開されます。
d_setup(d)の呼び出し元の dat.py setup()では、
data = sum( map( d_setup, data ), [] )
などとしており、これは data = [ d, d, d, ... ] から d を取り出して d_setup(d) を呼び出してます。 d_setup(d) では d に処理を施し、結果を [ d ]、 あるいは複数に展開した後の [ d, d, d ... ] を返します。
それら [ [ d, d, ... ], [ d, d, ... ] ... ] を sum( ..., [] ) で連結して、 [ d, d, ... ] にしてます。
この仕組みを使って、d に「繰り返しコピー展開」の属性'rxs'があると、 d_setup(d) の中で複数のデータに展開して返すようにしてみました。
お試しデータは
dat.py : rxs_test = [ { 'kind': 'ball', 'rtd': rtd, 'm2g': [ ax.zoom_all(10), ax.slide([-15*4,-15*3,-15*2]) ], 'rxs': [ ( 'm2g', 'append', 4, [ ax.slide_x(30) ] ), ( 'm2g', 'append', 3, [ ax.slide_y(30) ] ), ( 'm2g', 'append', 2, [ ax.slide_z(30) ] ), ] },{ 'kind': 'ball', 'rtd': { 'diff': 0.3 }, 'maps': [ { 'fn': 'IMG_3999_3.mov', 'fn_r': 'IMG_3999_4.mov', 'r': 0.3, 'rep': (1,1) } ], 'm2g': [ ax.zoom_all(r) ], } ] :
rxs はリストで複数の rx を格納します。
rx とは
(コピーするときの変換位置, そこへの挿入か追加の指定, コピー数, 繰り返し施す変換)
そもそも物体のデータの構造は次のようになってます。
{ kind: 球(中心原点で半径1)とか、立方体(中心原点で一辺が-1から+1)とか l2m: 変換のリスト。上記のローカル座標系を、マッピング座標系に変換するためのもの m2g: 変換のリスト。マッピング座標系をグローバル座標系に変換するためのもの l2g: ローカル座標系からグローバル座標系に変換するためのもの (なければ d_setup() でl2m と m2g を連結して作られる) : }
物体を配置するときの処理を概念的に説明すると、次のような感じです。
例えば半径1の球は、l2m で拡大、縮小、変形などの変換をした後、画像を照射するマッピングのステージにあげます。
そこで画像データを、平行光線のように照射したり、点光源からの光のように照射したり、 はたまた直線を軸とする光源から円柱状に照射したりして、対象の球に画像を照らして焼き付けます。
画像が焼き付けられた球は、さらにm2gで変換してグローバル座標のステージに配置されます。
で、で、繰り返しコピー展開 rx に戻って、 (コピーするときの変換位置, そこへの挿入か追加の指定 ... ) は、 どの変換の段階でコピーするのかを指定します。
そして、指定の処理位置でコピー数分のコピーをとると、 rx の最後の指定の「繰り返し施す変換」をかけます。
最初の1つめのコピーは、変換なしのオリジナル。 次のコピーは「繰り返し施す変換」を1回かけたもの、 さらに次のコピーは「繰り返し施す変換」を2回かけたもの、...という具合。
まぁ処理の概念的には上記の通りですが、 実際の処理は、指定の変換リスト(l2mやm2g)の先頭か末尾に、 「繰り返し施す変換」を追加していくだけです。
そのrxによるコピーで1つのデータが複数になり。 rxs のリストから次の rx を取り出して処理すると、そのデータ群がコピーされて複数のデータ群に。 などと、rxs のリストが空になるまでコピーが繰り返されます。
dat.py のパッチは短いコードですが、かなり深い内容です。
+ if 'rxs' in d: + rxs = d.get('rxs') + if not rxs: + d.pop('rxs') + return d_setup(d) + (targ_k, i_a, n, lx) = rxs.pop(0) + + targ = d.get(targ_k, []) + ds = [] + for i in range(n): + d_ = d.copy() + d_['rxs'] = rxs[:] # ! + d_[targ_k] = targ[:] + ds.append(d_) + targ = lx + targ if i_a == 'insert' else targ + lx + return sum( map( d_setup, ds ), [] ) + ### +
画像サーバの中に動画書き込みの機能を入れ込んでましたが、 サーバの中でコネクションスレッドごとのロックとかがあり、 微妙に待ちが生じるので、別のサーバに分離しました。
ソースコードはimg.pyの中に一緒に入ってますが、 別のsrv.vwtサーバとして./img.py boot_vwt で起動します。
また、レイトレサーバに複数のピクセル位置をリストで渡していましたが、、、 ピクセル位置は連続保証にしたので、 「先頭のx,y位置」と「続く個数」的な情報で渡し、 可変長を嫌って固定長にしました。
あと、 遅いマシンでもrtサーバを上げて手伝ってもらう時でも、 あまり足をひっぱらないよう、割り当てるピクセル数を動的に調整する仕組みを入れてみました。
計算が終わってサーバを落とすとき用に、skill.sh を追加しました。 リモートマシンにも手伝ってもらう場合は、 skill.sh の後半部分のコメントを外すなり、変更して使います。
pythonのロックのメソッドacquire(), release()がイマイチしっくりこないので、 ut.py にラッパを用意して lock(), unlock() にしてみました。
$ mv rt_v35 rt_v36 $ cat v36.patch | ( cd rt_v36 ; patch -p1 ) $ cd rt_v36 $ make clean $ make
ではまず、速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v36/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 15.13s $ ./skill.sh
以前の v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s (1-15.13/16.16)*100 = 6.37 パーセントの改善
ではお試しデータで、ワイヤーフレームから
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=rxs_test name=out_v36/rxs_test_wf wf : frm : 298/300(99.3%) : total 4m 30.31s : rest 1.80s : 2018/05/11 06:43:42 frm : 300/300(100.0%) : fin 4m 30.22s
-rw-r--r-- 1 kondoh staff 3588838 5 11 06:44 rxs_test_wf.mp4 3M超えてました。 $ ./img.py dmy out_v36/rxs_test_wf.mp4 cmd=3M $ cp v.mp4 out_v36/rxs_test_wf_3m.mp4
まぁ無事コピー展開できてる様子。 しかしワイヤーフレームでも10秒の動画生成に4分半、、、
荒削り設定で
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=rxs_test name=out_v36/rxs_test_es div=8 fps=10 : wh : 4800/4800(100.0%) : fin 1.89s frm : 100/100(100.0%) : fin 4m 39.54s
(4*60+39.54)*8*8*3/60/60 = 14.90 時間の予想
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=rxs_test name=out_v36/rxs_test : wh : 276167/307200(89.9%) : total 2m 22.12s : rest 14.35s : 2018/05/11 21:53:32 wh : 307200/307200(100.0%) : fin 2m 7.84s frm : 300/300(100.0%) : fin 14h 53m 45.76s ls -l out_v36/*.mp4 -rw-r--r-- 1 kondoh staff 12170547 5 11 21:53 out_v36/rxs_test.mp4 -rw-r--r-- 1 kondoh staff 1763037 5 11 06:58 out_v36/rxs_test_es.mp4 -rw-r--r-- 1 kondoh staff 3588838 5 11 06:43 out_v36/rxs_test_wf.mp4
予想時間通りではありますが、いやいや 12Mバイト! 3Mバイトに切り捨てるだけじゃなくて、3Mごとに分割するツールを作らねば。 (パッチは次回に含めます)
$ ./img.py dmy out_v36/rxs_test.mp4 cmd=div3M (n, fps)=(300, 30.0) : ./v.mp4 86/300 (n, fps)=(214, 30.0) : ./v.mp4 86/214 (n, fps)=(128, 30.0) ./v.mp4 86/128 $ ls -l out_v36/ total 61680 -rw-r--r-- 1 kondoh staff 12170547 5 11 22:08 rxs_test.mp4 -rw-r--r-- 1 kondoh staff 3145698 5 12 00:26 rxs_test_1.mp4 -rw-r--r-- 1 kondoh staff 3107714 5 12 00:27 rxs_test_2.mp4 -rw-r--r-- 1 kondoh staff 3113627 5 12 00:28 rxs_test_3.mp4 -rw-r--r-- 1 kondoh staff 2214859 5 12 00:28 rxs_test_4.mp4 :
しかし、同じVGA fps=30の3Mバイトの動画でも
このワイヤーフレームの二値の線画で8秒
色数も多いこれが18秒
これが2秒
そういうものなのだろうか。なんかどこかで間違ってたりしないだろうか?
繰り返しコピーができるようになったところで、 私が勝手に思い込んでいるレイトレーシングの伝統的なパターン 「チェスボードの上に透明の球」を再度試してみます。
$ mv rt_v36 rt_v37 $ cat v37.patch | ( cd rt_v37 ; patch -p1 ) $ cd rt_v37 $ make clean $ make
物体の繰り返しコピー配置 では、 コピーを作る位置についてごたくを並べてたのですが、 バグがあり意図した動作になってませんでした。
物体データをコピーしても、データが指してるマッピング情報が、皆同じものを指していました。 コピーした最後のデータに行ったマッピングの処理が、 全部のコピーしたデータに影響してしまっておりました。
パッチの
dat.py : d_ = d.copy() d_['rxs'] = rxs[:] # ! d_[targ_k] = targ[:] + d_['maps'] = ut.map_lst( lambda m: m.copy(), d.get('maps') ) # ! ds.append(d_) targ = lx + targ if i_a == 'insert' else targ + lx return sum( map( d_setup, ds ), [] ) :
この箇所で、マッピング情報もコピーするように修正しておきます。
毎回、フルサイズで走らせたときの予想時間を手で計算してましたが、 荒削り設定のときに最後に表示するようにしてみました。
生成した動画ファイルが3Mバイトを超えてた場合、 適当に分割する処理を追加していみました。
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v37/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 15.49s $ ./skill.sh
以前の v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
まぁ同程度。
ではパッチに追加した「伝統パターン」をば。
: +rxs_check = [ { + 'kind': 'square', + 'rtd': { 'diff': 0.8 }, + 'maps': [ { 'fn': 'IMG_3999_3.mov', 'fn_r': 'IMG_3999_4.mov', 't2m': [ ax.zoom_all(4) ] } ], + 'm2g': [ ax.slide([-8,-8,-2]) ], + 'rxs': [ + ( 'm2g', 'insert', 2, [ ax.slide([2,2,0]) ] ), + ( 'm2g', 'insert', 4, [ ax.slide_x(4) ] ), + ( 'm2g', 'insert', 4, [ ax.slide_y(4) ] ), + ] +},{ + 'kind': 'ball', + 'rtd': rtd, + 'm2g': [ ax.zoom_all(2) ], +} ] + +rxs_check2 = [ { + 'kind': 'square', + 'rtd': { 'diff': 0.8 }, + 'maps': [ { 'fn': 'IMG_3999_3.mov', 'fn_r': 'IMG_3999_4.mov', 't2m': [ ax.zoom_all(40) ] } ], + 'l2m': [ ax.slide([-8,-8,-2]) ], + 'rxs': [ + ( 'l2m', 'insert', 2, [ ax.slide([2,2,0]) ] ), + ( 'l2m', 'insert', 4, [ ax.slide_x(4) ] ), + ( 'l2m', 'insert', 4, [ ax.slide_y(4) ] ), + ] +},{ + 'kind': 'ball', + 'rtd': rtd, + 'm2g': [ ax.zoom_all(2) ], +} ]
rxs_check はコピーする位置が画像を焼き付けた後、 rxs_check2 はコピーする位置が画像を焼き付ける前になってます。
前者のデータで、まずは荒削り設定で
$ ./cg.py eyep=[0,0,0],[40,40,10],10 sec=10 data_name=rxs_check name=out_v37/rxs_check_tst fps=10 div=4 : wh : 14959/19200(77.9%) : total 1.33s : rest 0.29s : 2018/05/12 17:29:50 wh : 19200/19200(100.0%) : fin 1.31s frm : 100/100(100.0%) : fin 2m 20.23s estimated 1.87 hour at 640*480 30fps $ ls -lt out_v37/ | head -rw-r--r-- 1 kondoh staff 887006 5 12 17:29 rxs_check_tst.mp4 :
1.87時間の予想。いかに?
$ ./cg.py eyep=[0,0,0],[40,40,10],10 sec=10 data_name=rxs_check name=out_v37/rxs_check : wh : 278581/307200(90.7%) : total 29.79s : rest 2.77s : 2018/05/12 20:32:56 wh : 307200/307200(100.0%) : fin 27.08s frm : 300/300(100.0%) : fin 2h 33m 32.76s $ ./skill.sh $ ls -lt out_v37/ | head -rw-r--r-- 1 kondoh staff 2994817 5 12 21:31 rxs_check_1.mp4 -rw-r--r-- 1 kondoh staff 3165126 5 12 20:32 rxs_check.mp4 :
実際には2時間半でした。
生成した動画サイズが微妙に3Mを超えてたので、 自動的に3Mバイトに分割する処理が入りましたが、、、 展開してまとめなおしただけで、ファイルサイズが3M以内になったようです。
jpegで不可逆な圧縮をしてると、まぁそういう事もあるのかな。
続いて画像をマッピングする前にコピーする方式の場合。
$ ./cg.py eyep=[0,0,0],[40,40,10],10 sec=10 data_name=rxs_check2 name=out_v37/rxs_check2_tst fps=10 div=4 : wh : 15251/19200(79.4%) : total 1.31s : rest 0.27s : 2018/05/12 17:35:16 wh : 19200/19200(100.0%) : fin 1.32s frm : 100/100(100.0%) : fin 2m 23.70s estimated 1.92 hour at 640*480 30fps $ ls -lt out_v37/ | head -rw-r--r-- 1 kondoh staff 536321 5 12 17:35 rxs_check2_tst.mp4 :
$ ./cg.py eyep=[0,0,0],[40,40,10],10 sec=10 data_name=rxs_check2 name=out_v37/rxs_check2 : wh : 278271/307200(90.6%) : total 28.55s : rest 2.68s : 2018/05/13 00:13:13 wh : 307200/307200(100.0%) : fin 25.93s frm : 300/300(100.0%) : fin 2h 34m 43.47s $ ./skill.sh $ ls -lt out_v37/ | head -rw-r--r-- 1 kondoh staff 1404207 5 13 00:13 rxs_check2.mp4 :
こちらも予想時間を超えて2時間半程度でした。
ファイルサイズは1.5M弱。 こういう画像(?)だと、動画ファイルのサイズが小さくなるようです。
では、続きの10秒
$ ./cg.py eyep=[0,0,0],[40,40,10],10 sec=10 data_name=rxs_check2 name=out_v37/rxs_check2_2 init_sec=10 : wh : 270609/307200(88.1%) : total 17.28s : rest 2.05s : 2018/05/13 06:31:52 wh : 307200/307200(100.0%) : fin 15.30s frm : 300/300(100.0%) : fin 2h 28m 55.50s $ ./skill.sh $ ls -l out_v37/ | head -rw-r--r-- 1 kondoh staff 1182585 5 13 06:31 rxs_check2_2.mp4 :
合わせて20秒に
$ rm -rf /tmp/img_wk/ttt $ mkdir -p /tmp/img_wk/ttt $ ./img.py /tmp/img_wk/ttt/a0 out_v37/rxs_check2.mp4 cmd=v2i $ ./img.py /tmp/img_wk/ttt/a1 out_v37/rxs_check2_2.mp4 cmd=v2i $ ./img.py /tmp/img_wk/ttt/a out_v37/rxs_check2_sum.mp4 cmd=i2v $ ls -l out_v37/rxs_check2_sum.mp4 -rw-r--r-- 1 kondoh staff 2348114 5 13 09:37 out_v37/rxs_check2_sum.mp4
20秒でも余裕でファイルサイズ3Mバイト以内でした。
複数のrtサーバプロセスを起動して試してましたが、 1つのrtサーバでもスレッドセーフな作りにしておけば、 複数のスレッドから繋げて使えるはず。
などと思って試してみると、色々とスレッドセーフになってなくて いっぱい修正が入ってしまいました。
とくに「値サーバ」。 例えば、複数のスレッドが値サーバに他のサーバの起動状況の情報を取りにいって、 起動してなかったらそのスレッドがサーバを起動しようとします。
ここで、複数のスレッドがほぼ同時に、あるサーバが起動してないと判定してしまって、 同じサーバをほぼ同時に複数起動してしまうという問題が起こってしまいました。
そこで「値サーバ」の中に、ちょっとした不可分なロックのしくみを追加して、 srvs.py の boot() からのサーバ起動確認処理で、使うようにしてみました。
$ mv rt_v37 rt_v38 $ cat v38.patch | ( cd rt_v38 ; patch -p1 ) $ cd rt_v38 $ make clean $ make
では、いつもの速度確認。
まず以前の通りrtサーバは2つ起動して使う設定のままで。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v38/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 18.49s
以前の v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
うーむ。
rt.py #names = [ 'srv.rt' ] * 2 この行のコメントアウトを外して names = [ 'srv.rt' ] * 2 にします。
これで、1つのrtサーバに2つのスレッドでから繋いでみます。
$ ./skill.sh $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v38/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 15.44s
まぁあんまり変わらんですが、 この方式の方がちょっとだけの差で最速。
rt.py 例の箇所を #names = [ 'srv.rt' ] * 2 names = [ 'srv.rt', 'srv.rt', 'srv.rt-15', 'srv.rt-15' ]
2つのrtサーバに、それぞれ2つのスレッドをつないで、 合計4つのスレッドで走らせてみます。
$ ./skill.sh $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v38/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 15.09s
これもまぁ誤差範囲かもですが、一応最速。
rt.py #names = [ 'srv.rt' ] * 2 names = [ 'srv.rt' ] * 4 + [ 'srv.rt-15' ] * 4
8スレッドではいかに?
$ ./skill.sh $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v38/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 19.80s
まぁ2サーバ * 2スレッドで 4スレッドにしておきますかね。
rt.py names = [ 'srv.rt' ] * 2 + [ 'srv.rt-15' ] * 2
rtサーバの中にval.pyから取得したデータのキャッシュを持ったままになっていて、 違うデータの指定で cg.py を起動しても、前回取得したデータのまま処理が進む不具合がありました。
まぁデータを変更するたび ./skill.sh でサーバを落として何とかしてたわけですが、 さすがに面倒なので cg.py の起動時にrtサーバの中のデータのキャッシュをクリアできるようにしてみました。
では、伝統パターンで視点の動きをちょっと変えてみて試してみます。
$ ./cg.py eyep=[0,0,-20],[40,40,5],10 sec=20 data_name=rxs_check2 name=out_v38/rxs_check2_tst div=8 fps=15 : frm : 300/300(100.0%) : fin 3m 19.42s estimated 7.09 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,-20],[40,40,5],10 sec=20 data_name=rxs_check2 name=out_v38/rxs_check2 : wh : 267968/307200(87.2%) : total 23.57s : rest 3.01s : 2018/05/17 06:11:42 wh : 307200/307200(100.0%) : fin 21.47s frm : 600/600(100.0%) : fin 5h 32m 53.51s $ ls -lt out_v38/ | head -rw-r--r-- 1 kondoh staff 2836688 5 17 06:11 rxs_check2.mp4 : 3MバイトOK
既存のデータを指定して、変換をかけたり画像のマッピングを追加したりして、 配置できるようにしてみました。
$ mv rt_v38 rt_v39 $ cat v39.patch | ( cd rt_v39 ; patch -p1 ) $ cd rt_v39 $ make clean $ make
では、いつもの速度確認。
$ ./skill.sh $ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v39/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 15.37s
以前の v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
追加したデータを試してみます。
dat.py : export_test = [ { 'kind': 'export', 'export': 'copen', 'm2g': [ ax.zoom_all(0.5), ax.slide([-60,-60,0]) ], 'rxs': [ ( 'm2g', 'append', 3, [ ax.slide_x(60) ] ), ( 'm2g', 'append', 3, [ ax.slide_y(60) ] ), ] } ] :
以前のデータ'copen'とは
maps_copen = [ { 'fn': 'copen-090419.jpg', 't2m': [ ax.zoom_all(2) ] } ] copen = [ { 'kind': 'square', 'l2m': [], 'maps': maps_copen, 'm2g': [ ax.zoom_all(50) ], },{ 'kind': 'ball', 'def_col': [128,0,0], 'l2m': [ ax.zoom_all(20.0/50) ], 'maps': maps_copen, 'm2g': [ ax.zoom_all(50) ], } ]
四角の平面と球で、copenの画像を貼り付けたデータです。
exportの指定では、 この'copen'データを新たなlocal座標系のデータとして扱います。
取り込んだ'copen'データ全体に対してさらに、 'm2g'の位置の変換で0.5倍に縮小して、(-60,-60,0)の平行移動。
'rxs'の指定でさらに'm2g'の変換位置の後ろで分身させてます。 まず3つ分身させてx方向に60つづ平行移動。 そのセットに対して、さらに3つ分身させてy方向に60づつ平行移動。
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test name=out_v39/exp_tst div=4 fps=10 : wh : 12411/19200(64.6%) : total 3.17s : rest 1.12s : 2018/05/18 21:50:18 wh : 19200/19200(100.0%) : fin 2.29s frm : 100/100(100.0%) : fin 2m 29.03s estimated 1.99 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test name=out_v39/exp : wh : 289365/307200(94.2%) : total 37.80s : rest 2.19s : 2018/05/19 00:42:37 wh : 307200/307200(100.0%) : fin 35.65s frm : 300/300(100.0%) : fin 2h 13m 31.11s $ ls -lt out_v39/ | head -rw-r--r-- 1 kondoh staff 1376197 5 19 00:42 exp.mp4 :
画像のマッピングの追加も試しておきます。
dat.py : export_test2 = [ { 'kind': 'export', 'export': 'copen', 'm2g': [ ax.zoom_all(0.5), ax.slide([-60,-60,0]) ], 'rxs': [ ( 'm2g', 'append', 3, [ ax.slide_x(60) ] ), ( 'm2g', 'append', 3, [ ax.slide_y(60) ] ), ], 'maps': [ { 'fn': 'IMG_3999_3.mov', 'fn_r': 'IMG_3999_4.mov', 't2m': [ ax.zoom_all(100) ] } ], } ] :
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test2 name=out_v39/exp_tst2 div=4 fps=10 : wh : 19200/19200(100.0%) : fin 3.83s frm : 100/100(100.0%) : fin 4m 51.80s estimated 3.89 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test2 name=out_v39/exp2 : wh : 307200/307200(100.0%) : fin 1m 0.54s frm : 300/300(100.0%) : fin 4h 13m 11.92s $ ls -lt out_v39/ | head -rw-r--r-- 1 kondoh staff 1531099 5 20 20:26 exp2.mp4 :
dat.py : export_test3 = [ { 'kind': 'export', 'export': 'copen', 'l2m': [ ax.zoom_all(0.5), ax.slide([-60,-60,0]) ], 'rxs': [ ( 'l2m', 'append', 3, [ ax.slide_x(60) ] ), ( 'l2m', 'append', 3, [ ax.slide_y(60) ] ), ], 'maps': [ { 'fn': 'IMG_3999_3.mov', 'fn_r': 'IMG_3999_4.mov', 't2m': [ ax.zoom_all(500) ] } ], } ]
'rxs'による分身の位置を'l2m'の直後に移動して、 マッピングステージに上がる直前に変更してみます。
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test3 name=out_v39/exp_tst3 div=4 fps=10 : wh : 19200/19200(100.0%) : fin 3.71s frm : 100/100(100.0%) : fin 4m 54.74s estimated 3.93 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[200,200,20],10 sec=10 data_name=export_test3 name=out_v39/exp3 : wh : 307200/307200(100.0%) : fin 1m 3.22s frm : 300/300(100.0%) : fin 4h 18m 37.56s $ ls -lt out_v39/ | head -rw-r--r-- 1 kondoh staff 1131620 5 20 15:00 exp3.mp4 :
物体の繰り返しコピー配置 を、 立方体で試してみて不具合が発覚しました。
立方体を複数にコピーして配置しようとしたのですが、 1つの四角い平面しか分身してくれません。
立方体は6つの四角い平面に展開されて処理されるのですが、 そこで分身した全てのデータが、コピー元の同じ'rxs'データを指していたのが原因でした。
これまで試した球や単独の四角い平面では、複数の物体に展開される事が無かったので、 不具合が潜んだままでした。
他にも例えば円柱の場合、側面の筒と上下のフタの円に分身する時に同じ問題が出ます。
深いコピー用の関数を用意して、まとめて対処しておきます。
$ mv rt_v39 rt_v40 $ cat v40.patch | ( cd rt_v40 ; patch -p1 ) $ cd rt_v40 $ make clean $ make
最初のデータ展開箇所だけの問題で、速度には影響ないということで、 いつもの速度確認は省略。
とりあえず、展開で問題になった立方体を円形にコピー配置して確認しておきます。
$ ./cg.py eyep=[0,0,0],[200,200,40],10 sec=10 data_name=colosseum name=out_v40/col_t fps=2 div=4 : wh : 19200/19200(100.0%) : fin 6.32s frm : 20/20(100.0%) : fin 2m 24.46s estimated 9.63 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[200,200,40],10 sec=10 data_name=colosseum name=out_v40/col : wh : 307200/307200(100.0%) : fin 1m 29.51s frm : 300/300(100.0%) : fin 9h 10m 30.63s $ ls -lt out_v40/ | head -rw-r--r-- 1 kondoh staff 2283827 5 22 08:10 col.mp4 :
$ ./cg.py eyep=[0,0,0],[300,300,60],10 sec=10 data_name=colosseum2 name=out_v40/col2_t fps=5 div=16 wh : 1200/1200(100.0%) : fin 2.41s frm : 50/50(100.0%) : fin 2m 3.29s estimated 52.61 hour at 640*480 30fps
予想時間は52時間!
$ ./cg.py eyep=[0,0,0],[300,300,60],10 sec=10 data_name=colosseum2 name=out_v40/col2_one n=1 init_sec=10 show_sec=-1 : wh : 288756/307200(94.0%) : total 8m 56.84s : rest 32.23s : 2018/05/22 09:38:24 wh : 307200/307200(100.0%) : fin 8m 24.65s frm : 1/1(100.0%) : fin 9m 13.41s $ ls -lt out_v40/ | head -rw-r--r-- 1 kondoh staff 14244 5 22 09:38 col2_one.mp4 -rw-r--r-- 1 kondoh staff 100076 5 22 09:37 col2_one00001.jpg :
1コマ10分として 10*300/60 = 50時間
物体の数が多過ぎという事ですかね。div=2 で妥協して50/4=12.5時間で。
$ ./cg.py eyep=[0,0,0],[300,300,60],10 sec=10 data_name=colosseum2 name=out_v40/col2 div=2 : wh : 76800/76800(100.0%) : fin 2m 8.56s frm : 300/300(100.0%) : fin 11h 37m 39.34s estimated 46.51 hour at 640*480 30fps $ ls -lt out_v40/ | head -rw-r--r-- 1 kondoh staff 2506857 5 22 21:31 col2.mp4 :
データファイル dat.yaml を新規追加して、 dat.py に書いていた物体のデータを移しました。
デフォルトで dat.yaml をロードするようにしてますが、 cg.py起動時のコマンド引数で yaml=xxx.yaml 指定で変更出来ます。
$ mv rt_v40 rt_v41 $ cat v41.patch | ( cd rt_v41 ; patch -p1 ) $ cd rt_v41 $ make clean $ make
追加したデータファイル dat2.yaml を試してみます。
pillar: - kind: cube rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ ax.zoom_z(10) ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([2,2,1])', ax.slide_z(-11) ] rxs: - [ m2g, append, 2, [ ax.slide_z(22) ] ] big_ball: - kind: ball rtd: { diff: 0.3 } maps: - fn: IMG_3999_4.mov fn_r: IMG_3999_4.mov t2m: [ ax.zoom_all(2), ax.rot_x(90) ] - fn: IMG_3999_4.mov fn_r: IMG_3999_4.mov t2m: [ ax.zoom_all(2), ax.rot_x(90), ax.rot_z(180) ] m2g: [ ax.zoom_all(500) ] colosseum: - kind: export export: pillar m2g: [ ax.slide_x(20) ] rxs: - [ m2g, append, 16, [ ax.rot_z(360.0/16) ] ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([24,24,1])', ax.slide_z(-13) ] rxs: - [ m2g, append, 2, [ ax.slide_z(26) ] ] - kind: ball rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ ax.zoom_all(6) ] - kind: export export: big_ball # EOF
ワイヤーフレームも意外と時間もかかってファイルも大きくなるので、 フレームレート粗めで。
./cg.py eyep=[0,0,0],[300,300,100],10 sec=10 yaml=dat2.yaml data_name=colosseum name=out_v41/col_wf wf fps=5 : frm : 50/50(100.0%) : fin 2m 58.58s estimated 0.30 hour at 640*480 30fps
粗削りお試し。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=10 yaml=dat2.yaml data_name=colosseum name=out_v41/col_tst div=4 fps=1 : wh : 19200/19200(100.0%) : fin 9.63s frm : 10/10(100.0%) : fin 1m 44.46s estimated 13.93 hour at 640*480 30fps
適当に5秒の時刻の1コマを。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=10 yaml=dat2.yaml data_name=colosseum name=out_v41/col_ init_sec=5 n=1 show_sec=-1 : wh : 307200/307200(100.0%) : fin 1m 42.06s frm : 1/1(100.0%) : fin 2m 14.52s
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=10 yaml=dat2.yaml data_name=colosseum name=out_v41/col : wh : 307200/307200(100.0%) : fin 2m 5.81s frm : 300/300(100.0%) : fin 14h 8m 10.53s $ ls -lt out_v41/ | head -rw-r--r-- 1 kondoh staff 3087005 5 25 14:27 col.mp4 : ギリギリ3Mバイト
ほぼ粗削りのときの予想時間通りで14時間でした。
ここでちょと番外編のデータを。
$ wget http://kondoh2.html.xdomain.jp/rt/dat3.yaml $ wget http://kondoh2.html.xdomain.jp/rt/noshi.jpg $ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat3.yaml data_name=colosseum name=out_v42/noshi : frm : 600/600(100.0%) : fin 28h 52m 21.35s Traceback (most recent call last): File "./cg.py", line 68, inimg.video_to_d1v3M(fn) :
しまった3M分割の箇所でtypoが... 次回のパッチで修正しておきます。
$ ls -lt out_v41/ -rw-r--r--@ 1 kondoh staff 9224643 5 29 08:04 noshi.mp4 : 9Mバイト $ ./img.py dmy out_v41/noshi.mp4 cmd=div3M : で3Mバイトに分割
色々とデータを試してみると、画像のマッピングが無しだと何だかすごく処理速度が速い感じ。
これは画像サーバとのやりとりが、かなり重いのでは?
という事で、レイトレサーバから画像サーバに要求を出して動画のピクセルを取得する箇所で、 クライアントであるレイトレサーバの中で、一コマ分の画像全体をまとめて取得しキャッシュするようにしてみました。 メモリ使いまくりです。
これで最初のピクセルの取得時に、画像全体のデータをまとめて取得しますが、 以降は次のコマに時間が進むまでは、画像サーバへのアクセスは発生しません。
画像サーバには、動画のフレーム数やフレームレートを取得するAPIと、 ある時刻の一コマ分の画像全体を取得するAPIを追加しました。 クライアント側はC言語の実装の方だけ、キャッシュの機構を追加しています。
マッピングしても、画像全体のピクセルを使う訳じゃないので、 初回の取得時間が無駄になる場合があるかも知れませんが、 毎回プロセス間通信する方が、やっぱり負担が大きいでしょう。
$ mv rt_v41 rt_v42 $ cat v42.patch | ( cd rt_v42 ; patch -p1 ) $ cd rt_v42 $ make clean $ make
では、さっそくいつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v42/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.16s
以前の v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
!!! まじでか。こんなに効果ありなん?
前回のデータで、ちょっと上下の移動を増やしてみて、分割はdiv=2程度で試してみます。
$ ./cg.py eyep=[0,0,0],[300,300,200],10 sec=10 yaml=dat2.yaml data_name=colosseum name=out_v42/col2 div=2 : wh : 72895/76800(94.9%) : total 7.92s : rest 0.40s : 2018/05/29 22:36:59 wh : 76800/76800(100.0%) : fin 7.53s frm : 300/300(100.0%) : fin 46m 39.03s estimated 3.11 hour at 640*480 30fps $ ls -lt out_v42/ | head -rw-r--r-- 1 kondoh staff 1868348 5 29 22:37 col2.mp4 :
やはり速い。予想時間3.11時間になってます。 v41では同じdat2.yamlで14時間かかってました。
では、せっかくなので20秒で。
$ ./cg.py eyep=[0,0,0],[300,300,200],10 sec=20 yaml=dat2.yaml data_name=colosseum name=out_v42/col :
バグってました。
ローカル変数のアドレスをハッシュテーブルのキーとして使ってました。 よって、関数を抜けるとキーの値は不定。
テーブルに登録したはずのキーが見つからず、何度も画像をサーバから引っ張ってきて登録しなおした末に、 メモリを使いきってしまい、swap領域が不足だの、ディスクが不足だのとエラーが出て落ちてました。
修正します。
また、rt.cのサーバプロセスにはcg.pyからの複数のスレッドが接続してくるので、 rt.cから呼び出すimg.c img_col_cache()の中で、 キャッシュの操作箇所にロックをかけてスレッドセーフにしてみました。
ut.[ch] の ut_cache_tbl のあたり、少々複雑になってきたのでメモを残しておきます。
struct ut_cache_tbl{ int n; /* tbl[] の要素数を指定する */ int chain_max_n; /* <= 0 : no limit */ /* tbl[i] --> の先にチェーンで連結する ut_cache の個数の上限を指定する 値が0以下なら制限なし */ struct ut_cache **tbl; /* tbl[] 本体 */ int (*geti)(void *k, int ksz); /* k, ksz からテーブルの添字の整数、 つまり tbl[i] の i の元になる整数を返す関数を指定する 関数が返した整数をさらに % n で n未満の値にして i として使う */ }; /* ソースコード上と順を入れ換えて tbl[i] --> の先にチェーンで連結する ut_cache */ struct ut_cache{ void *k; /* キーのデータ */ int ksz; /* キーのデータのサイズ */ void *v; /* 値のデータ */ struct ut_cache *next; /* チェーンの次の ut_cache (NULLで終端) */ }; void ut_cache_alloc(struct ut_cache_tbl *t); /* t->n を設定した状態で呼び出す t->tbl[] をアロケート t->tbl[i] の指してる先は、NULL(終端)で初期化 */ struct ut_cache **ut_cache_get_pptr(struct ut_cache_tbl *t, void *k, int ksz); /* 主に内部で使用するので略 */ struct ut_cache *ut_cache_get_ptr(struct ut_cache_tbl *t, void *k, int ksz); /* 主に内部で使用するので略 */ void *ut_cache_get(struct ut_cache_tbl *t, void *k, int ksz); /* キー情報 k, ksz から t->tbl[] の添字を求めて チェーンをたぐって一致するキー情報がある ut_cache を探す 見つかれば ut_cache の値のデータ v を返す 見つからなければ NULL を返す */ void *ut_cache_set(struct ut_cache_tbl *t, void *k, int ksz, void *v); /* ut_cache をアロケートして値 v をセット キー情報 k, ksz から t->tbl[] の添字を求めて、 チェーンに追加する チェーンの長さが t->chain_max_n の上限にひっかかると、 末尾のut_cacheを削除する 削除したut_cacheがあれば、その値のデータ v を返す 削除したut_cacheがなければ、NULLを返す */ void *ut_cache_del(struct ut_cache_tbl *t, void *k, int ksz); /* キー情報 k, ksz から t->tbl[] の添字を求めて チェーンをたぐって一致するキー情報がある ut_cache を探す 見つかれば ut_cache をチェーンから外し、 その ut_cache のメモリを解放し、 設定されていた値のデータ v を返す 見つからなければ NULL を返す */ void ut_cache_free(struct ut_cache_tbl *t); /* t->tbl[] の全てのチェーンについて、 ut_cache のメモリを解放し、 ut_cache_alloc() でアロケートした t->tbl[] のメモリも解放する 解放する各 ut_cache の値のデータ v は解放もせず、 値も返さないので注意 */ int ut_cache_geti_int(void *k, int ksz); /* キーを整数として使うときの geti 関数 ut_cache_tbl t の t->geti に指定して使う */ int ut_cache_geti_str(void *k, int ksz); /* キーを文字列として使うときの geti 関数 ut_cache_tbl t の t->geti に指定して使う */
$ mv rt_v42 rt_v43 $ cat v43.patch | ( cd rt_v43 ; patch -p1 ) $ cd rt_v43 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v43/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 2.96s
以前の v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
念のため粗削り設定で
$ ./cg.py eyep=[0,0,0],[300,300,200],10 sec=20 yaml=dat2.yaml data_name=colosseum name=out_v43/col4 div=4 : wh : 19200/19200(100.0%) : fin 1.05s frm : 600/600(100.0%) : fin 21m 35.86s : estimated 5.76 hour at 640*480 30fps $ ls -lt out_v43/ | head -rw-r--r-- 1 kondoh staff 3141783 5 30 22:03 col4_1.mp4 -rw-r--r-- 1 kondoh staff 27952 5 30 22:03 col4_2.mp4 -rw-r--r-- 1 kondoh staff 3417683 5 30 22:00 col4.mp4 :
予想時間は6時間弱。
では、リベンジの20秒データで。
$ ./cg.py eyep=[0,0,0],[300,300,200],10 sec=20 yaml=dat2.yaml data_name=colosseum name=out_v43/col : wh : 307200/307200(100.0%) : fin 19.01s frm : 600/600(100.0%) : fin 6h 4m 18.08s (n, fps)=(600, 30.0) : ./v.mp4 382/600 $ ls -lt out_v43/ | head -rw-r--r-- 1 kondoh staff 1607345 5 31 04:14 col_2.mp4 -rw-r--r-- 1 kondoh staff 3142862 5 31 04:14 col_1.mp4 -rw-r--r-- 1 kondoh staff 5193725 5 31 04:12 col.mp4 :
ほぼ6時間でした。
先のデータの一部を拡大して配置して、再帰風にして試してみたところ...
$ cat dat4.yaml pillar: - kind: cube rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ ax.zoom_z(10) ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([2,2,1])', ax.slide_z(-11) ] rxs: - [ m2g, append, 2, [ ax.slide_z(22) ] ] big_ball: - kind: ball rtd: { diff: 0.3 } maps: - fn: IMG_3999_4.mov fn_r: IMG_3999_4.mov t2m: [ ax.zoom_all(2), ax.rot_x(90) ] - fn: IMG_3999_4.mov fn_r: IMG_3999_4.mov t2m: [ ax.zoom_all(2), ax.rot_x(90), ax.rot_z(180) ] m2g: [ ax.zoom_all(1000) ] colosseum: - kind: export export: pillar m2g: [ ax.slide_x(20) ] rxs: - [ m2g, append, 16, [ ax.rot_z(360.0/16) ] ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([24,24,1])', ax.slide_z(-13) ] rxs: - [ m2g, append, 2, [ ax.slide_z(26) ] ] all: - kind: export export: colosseum rxs: - [ m2g, append, 2, [ ax.zoom(6) ] ] - kind: ball rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ ax.zoom_all(6) ] - kind: export export: big_ball # EOF
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat4.yaml data_name=all name=out_v44/wf_ wf : frm : 599/600(99.8%) : total 57m 15.79s : rest 5.72s : 2018/06/01 17:11:39 frm : 600/600(100.0%) : fin 57m 15.88s (n, fps)=(600, 30.0) $ ls -lt out_v44/ | head -rw-r--r-- 1 kondoh staff 3016737 6 1 17:14 wf__3.mp4 -rw-r--r-- 1 kondoh staff 3144875 6 1 17:14 wf__2.mp4 -rw-r--r-- 1 kondoh staff 3140882 6 1 17:12 wf__1.mp4 -rw-r--r-- 1 kondoh staff 9270739 6 1 17:11 wf_.mp4 :
ん?
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat4.yaml data_name=all name=out_v44/all : wh : 307200/307200(100.0%) : fin 1m 20.94s frm : 600/600(100.0%) : fin 27h 47m 53.95s (n, fps)=(600, 30.0) : $ ls -lt out_v44/ | head -rw-r--r-- 1 kondoh staff 2207354 6 1 13:29 all_2.mp4 -rw-r--r-- 1 kondoh staff 3145411 6 1 13:29 all_1.mp4 -rw-r--r-- 1 kondoh staff 5764500 6 1 13:27 all.mp4 :
28時間ほどもかかったけど、やっぱり「ん?」
拡大した方の外側の「柱」の上下の円柱部分。 天井と床部の円柱部分の配置が意図した通りになってません。dat.py : def d_setup(d): : if 'rxs' in d: rxs = d.get('rxs') if not rxs: d.pop('rxs') return d_setup(d) (targ_k, i_a, n, lx) = rxs.pop(0) targ = d.get(targ_k, []) ds = [] for i in range(n): d_ = d_copy(d) d_[targ_k] = targ[:] ds.append(d_) targ = lx + targ if i_a == 'insert' else targ + lx return sum( map( d_setup, ds ), [] ) : if kind == 'export' and 'export' in d: data = ydic.get( d.get('export'), [] ) data = ut.map_lst( d_copy, data ) ds = [] for d_ in data: d_['m2g'] = d_.get('m2g', []) + d.get('l2g') ds += d_setup(d_) for d_ in ds: d_['maps'] = d_.get('maps', []) + d.get('maps', []) return ds :
この処理の順番に問題が。
dat4.yaml : all: - kind: export export: colosseum rxs: - [ m2g, append, 2, [ ax.zoom(6) ] ] :
例えばここの展開で、 先にrxsの拡大の結果がm2gの末尾に追加されて、 そのあとでexportの処理で、
colosseum: : - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([24,24,1])', ax.slide_z(-13) ] rxs: - [ m2g, append, 2, [ ax.slide_z(26) ] ] :
こちらの'm2g'。このzoomとslide_z。ここまではオッケー。export の
d_['m2g'] = d_.get('m2g', []) + d.get('l2g')
allのrxsのm2gに追加された拡大は、d.get('l2g') に反映されているので、 zoomとslide_zのm2gよりも後方に追加されます。
問題はそのあとd_['m2g'] = d_.get('m2g', []) + d.get('l2g') ds += d_setup(d_)
このd_setup(d)から
rxs: - [ m2g, append, 2, [ ax.slide_z(26) ] ]
が展開されて、m2gのさらに後ろ側に、このslize_z()が追加されます。
なんともややこしい...
そもそも、exportの展開を先に処理して、export元のrxs展開込みで済ませた状態で、 外側のrxsのコピー展開を処理するのが自然かと。
ということで、exportとrxsの処理順を入れ替えてみました。
そのままではダメ。一部rxs展開がうまく成されません。抜けがありました。 なかなか手強い。
以前の処理順では、exportの展開時にはrxsは展開済みの前提で、 データ中にrxsが現れる事はありませんでした。
処理順を変えたので、前提が崩れます。 exportの展開時でもrxsがあれば展開先に追加するように修正します。
$ mv rt_v43 rt_v44 $ cat v44.patch | ( cd rt_v44 ; patch -p1 ) $ cd rt_v44 $ make clean $ make
視点移動はちょっと引き気味にしてみます。
$ ./cg.py eyep=[0,0,0],[450,450,150],10 sec=20 yaml=dat4.yaml data_name=all name=out_v44/wf_tst wf fps=2 : frm : 39/40(97.5%) : total 3m 51.44s : rest 5.78s : 2018/06/03 05:26:49 frm : 40/40(100.0%) : fin 3m 51.59s estimated 0.96 hour at 640*480 30fps
円柱部分の配置OK
$ ./cg.py eyep=[0,0,0],[450,450,150],10 sec=20 yaml=dat4.yaml data_name=all name=out_v44/rough fps=4 div=8 : frm : 79/80(98.8%) : total 2m 22.23s : rest 1.77s : 2018/06/03 05:31:27 wh : 0/4800(0.0%) : not start yet wh : 4800/4800(100.0%) : fin 0.98s frm : 80/80(100.0%) : fin 2m 21.78s estimated 18.91 hour at 640*480 30fps
それでは19時間で。
$ ./cg.py eyep=[0,0,0],[450,450,150],10 sec=20 yaml=dat4.yaml data_name=all name=out_v44/fix : wh : 307200/307200(100.0%) : fin 1m 4.04s frm : 600/600(100.0%) : fin 18h 52m 12.35s (n, fps)=(600, 30.0) : ./v.mp4 315/600 $ ls -lt out_v44/ | head -rw-r--r-- 1 kondoh staff 2762196 6 4 00:31 fix_2.mp4 -rw-r--r-- 1 kondoh staff 3141307 6 4 00:31 fix_1.mp4 -rw-r--r-- 1 kondoh staff 6391237 6 4 00:29 fix.mp4 :
ほぼ19時間でした。
手前の大きな角柱の横切りが、あまりにチラチラするのでもう一丁。 dat5.yaml で試してみます。
$ diff -u dat4.yaml dat5.yaml --- dat4.yaml Sun Jun 3 04:12:50 2018 +++ dat5.yaml Mon Jun 4 04:58:05 2018 @@ -36,7 +36,7 @@ - kind: export export: colosseum rxs: - - [ m2g, append, 2, [ ax.zoom(6) ] ] + - [ m2g, append, 2, [ ax.zoom(16) ] ] - kind: ball rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ ax.zoom_all(6) ] $
外側の柱の拡大率をアップして、視点移動の引きも元に戻してみます。
$ wget http://kondoh2.html.xdomain.jp/rt/dat5.yaml $ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat5.yaml data_name=all name=out_v44/dat5 : wh : 290062/307200(94.4%) : total 1m 18.96s : rest 4.40s : 2018/06/05 02:43:04 wh : 307200/307200(100.0%) : fin 1m 14.59s frm : 600/600(100.0%) : fin 21h 35m 6.34s $ ls -lt out_v44/ | head -rw-r--r-- 1 kondoh staff 2559915 6 5 02:45 dat5_2.mp4 -rw-r--r-- 1 kondoh staff 3132526 6 5 02:45 dat5_1.mp4 -rw-r--r-- 1 kondoh staff 6155197 6 5 02:43 dat5.mp4 :
21時間半。 視点の開始位置と終了位置がちょうど、柱に埋まった位置になってました。
そろそろ物体を動かしてみます。
一旦効率は無視。 時刻とともに ax.xxx() のアフィン変換のパラメータを変化出来るようにして、 時刻の更新ごとにデータをyamlファイルのロードからやりなおします。
元々yamlファイル中のax.xxx()箇所は全て文字列として扱っていて、 ロード後にeval()でアフィン変換のオブジェクトを生成してます。
ソースコード中のeval()の箇所で変数secの時刻を用意しておけば、 文字列中でsecを参照する式が利用できるはずです。 (ああ、インタープリタは便利)
さすがに、以前の静止したyamlファイルのデータを使うときに、 フレーム毎に同じデータをロードしなおすのも何なので、 安易にyamlファイル中に単語 sec が含まれているかどうかで判定するようにしておきます。
$ mv rt_v44 rt_v45 $ cat v45.patch | ( cd rt_v45 ; patch -p1 ) $ cd rt_v45 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v45/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.00s
以前の v43 wh : 76800/76800(100.0%) : fin 2.96s v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
追加したdat6.yaml
$ diff -u dat5.yaml dat6.yaml --- dat5.yaml 2018-06-04 04:58:05.000000000 +0900 +++ dat6.yaml 2018-06-04 23:11:09.000000000 +0900 @@ -1,7 +1,7 @@ pillar: - kind: cube rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } - m2g: [ ax.zoom_z(10) ] + m2g: [ 'ax.zoom_z( way.get([(10,2),(1,2)], sec, True) )' ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } m2g: [ 'ax.zoom([2,2,1])', ax.slide_z(-11) ] @@ -28,7 +28,7 @@ - [ m2g, append, 16, [ ax.rot_z(360.0/16) ] ] - kind: pipe rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } - m2g: [ 'ax.zoom([24,24,1])', ax.slide_z(-13) ] + m2g: [ 'ax.zoom([24, way.get([(24,4),(1,4)], sec, True), 1])', ax.slide_z(-13) ] rxs: - [ m2g, append, 2, [ ax.slide_z(26) ] ] @@ -39,6 +39,7 @@ - [ m2g, append, 2, [ ax.zoom(16) ] ] - kind: ball rtd: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } + l2m: [ 'ax.slide( way.liss([-3,-3,-3],[3,3,3],[3,4,5])(sec) )' ] m2g: [ ax.zoom_all(6) ] - kind: export export: big_ball
角柱の高さを2秒間隔で伸び縮み、 天井と床の円柱を4秒間隔でひしゃげさせて、 中央の球(6倍に拡大する前の半径1の段階)を(-3,-3,-3)から(3,3,3)の範囲を、 (3,4,5)秒の周期で適当にリサージュ図形の軌跡で移動させてみます。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat6.yaml data_name=all name=out_v45/dat6_tst div=8 fps=8 : wh : 4800/4800(100.0%) : fin 1.11s frm : 160/160(100.0%) : fin 4m 57.65s estimated 19.84 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=dat6.yaml data_name=all name=out_v45/dat6 : wh : 291116/307200(94.8%) : total 1m 20.21s : rest 4.19s : 2018/06/05 20:15:31 wh : 307200/307200(100.0%) : fin 1m 16.05s frm : 600/600(100.0%) : fin 14h 7m 18.73s $ ls -lt out_v45/ | head -rw-r--r-- 1 kondoh staff 3047631 6 5 20:17 dat6_2.mp4 -rw-r--r-- 1 kondoh staff 3144862 6 5 20:17 dat6_1.mp4 -rw-r--r-- 1 kondoh staff 6587792 6 5 20:15 dat6.mp4
14時間ほどでした。 確かに、ねらい通り動いてます。
このスピンするコインのような動きを再現してみます。
wf_15.patch あたりのパッチの wf_ex.c の箇所
diff -urN wf-/wf_ex.c wf/wf_ex.c --- wf-/wf_ex.c 2015-12-24 00:00:00.000000000 +0900 +++ wf/wf_ex.c 2015-12-30 00:00:00.000000000 +0900 @@ -64,6 +64,9 @@ : @@ -301,9 +305,9 @@ { type_slide_way, &(struct way){ .n=2, .ps=(pos_t[]){{0,-20,0},{0,20,0}}, .ts=(double[]){4.5,4.5}, .vs=NULL, .dg=3} }, { type_slide_way, &(struct way){ .n=2, .ps=(pos_t[]){{-20,0,0},{20,0,0}}, .ts=(double[]){3,3}, .vs=NULL, .dg=3} }, { type_rot_way, &(struct rot_way){ - .l={D3_O,D3_I}, .deg_way={ .n=2, .vs=(double[]){0,360*2}, .ts=(double[]){1,1}, .ps=NULL, .dg=3} } }, + .l={D3_O,D3_I}, .deg_way=WAY_V2(0,360*2, 1,1, 3) } }, { type_end } }}, - .data = &(data_t){ type_cube } + .data = &(data_t){ type_circle, &(struct circle){ .r=1,.n=10*4 } } }}; data.type = type_arr;
確か下から上へと読むはずでした。
wf_13.patch あたりのパッチの wf_ex.c の箇所
diff -urN wf-/wf_ex.c wf/wf_ex.c --- wf-/wf_ex.c 2015-12-22 00:00:00.000000000 +0900 +++ wf/wf_ex.c 2015-12-23 00:00:00.000000000 +0900 : + data_t *lissajours = &(data_t){ type_op_data_set, &(struct op_data_set){ + .op = &(data_t){ type_arr, (data_t[]){ + { type_copy_timeshift, &(struct copy_timeshift){ + .n=10, .init_sec=0, .step_sec=-0.3, .init=D3_O, .step=D3_O } }, :
という事で、 時間をズラしながらコピーして分身させる機能を追加してみました。
yamlファイルをロードして、 文字列をeval()してしまうと時刻のパラメータは消えてしまうので、 その前に付け焼き刃的にゴニョゴニョしてます。
あと、 yamlファイル中に何度も同じ長い記述が現れるのもなんなので、 defsのキーの箇所で定義して展開できるように、 ut.py に defs_eval() を追加してみました。
$ mv rt_v45 rt_v46 $ cat v46.patch | ( cd rt_v46 ; patch -p1 ) $ cd rt_v46 $ make clean $ make
データロード時の処理が増えてますが、 いつもの速度確認のデータは、 そもそも時刻依存なしなので省略。
視線の先に何か目標物が欲しかったので、 球を平たくつぶした円盤を配置してみました。 (UFOと子機のよう)
$ ./cg.py eyep=[0,0,0],[200,200,100],10 sec=20 yaml=spin_coin.yaml data_name=all name=out_v46/coin_wf wf : frm : 599/600(99.8%) : total 9m 41.48s : rest 0.96s : 2018/06/05 22:56:41 frm : 600/600(100.0%) : fin 9m 41.57s $ ls -lt out_v46/ | head -rw-r--r-- 1 kondoh staff 1616074 6 5 22:56 coin_wf.mp4 :
$ ./cg.py eyep=[0,0,0],[200,200,100],10 sec=20 yaml=spin_coin.yaml data_name=all name=out_v46/coin_tst div=8 fps=8 : wh : 4800/4800(100.0%) : fin 0.06s frm : 160/160(100.0%) : fin 37.33s estimated 2.49 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[200,200,100],10 sec=20 yaml=spin_coin.yaml data_name=all name=out_v46/coin : wh : 307200/307200(100.0%) : fin 9.03s frm : 600/600(100.0%) : fin 1h 50m 12.39s $ ls -lt out_v46/ | head -rw-r--r-- 1 kondoh staff 581794 6 6 05:26 coin_2.mp4 -rw-r--r-- 1 kondoh staff 3142385 6 6 05:26 coin_1.mp4 -rw-r--r-- 1 kondoh staff 3964603 6 6 05:24 coin.mp4 :
子機のコインは意図した通りに動いてるようですが、、、 どうも、添え物的に配置してみた母艦のUFOに目がいってしまいますね。
球や立方体などの単純な物体ですが、 アフィン変換で並行移動、拡大縮小、回転などできます。
でも、もうちょっと複雑な図形を表示してみたいところ、、、
複数の物体の領域のAND、つまり論理積というか「かつ」な領域を表示してみます。
視線の直線と物体の表面との交点を求めるのが、レイトレーシングの基本ですが、 そこからもうちょっと頑張って、視線の直線を物体にぶすりと串刺しにしてみます。
おのおのの単純な物体に、視線という名の串を突き刺して、串に物体の内部の範囲の印をつけていきます。
範囲の印のついた串を束ねてANDをとって、全ての串に存在してる領域を割り出します。 視線の裏側の部分は除外して、一番手前にぶちあたる領域の開始位置、あるいは終了位置から交点を算出します。
(夜中に目をこすりながらデバッグして文章を書いてるので、 コードも文章もかなりとっちらかってしまいました...)
なんとかANDが出来たので、NOTも少し手を出してみましたが、 平面に展開される系の物体は未だ完成できず...
とりあえず球のNOTだけは確認できました。
$ mv rt_v46 rt_v47 $ cat v47.patch | ( cd rt_v47 ; patch -p1 ) $ cd rt_v47 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v47/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.04s
以前の v45 wh : 76800/76800(100.0%) : fin 3.00s v43 wh : 76800/76800(100.0%) : fin 2.96s v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
まぁ、AND指定のデータじゃないのでさほど変わらず。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=and.yaml data_name=all name=out_v47/and_wf div=8 fps=8 wf : frm : 160/160(100.0%) : fin 32.02s estimated 2.13 hour at 640*480 30fps
ワイヤーフレームはAND未対応です。 単に球と立方体が並んでるだけです。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=and.yaml data_name=all name=out_v47/and_tst div=8 fps=8 : wh : 4800/4800(100.0%) : fin 0.10s frm : 160/160(100.0%) : fin 33.08s estimated 2.21 hour at 640*480 30fps
そう、これ。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=and.yaml data_name=all name=out_v47/and :
残念。メモリリークで落ちてました。 デバッグ前に、ディスクに残っている画像をできるだけ救済しておきます。
$ ./img.py out_v47/and out_v47/and_ng
まず前回のメモリリークの原因から。
--- cross.c- 2018-06-08 23:53:48.000000000 +0900 +++ cross.c 2018-06-08 23:54:19.000000000 +0900 @@ -456,6 +456,7 @@ n = cross_cross_one( d->kind, &d->l2g, prev_idx == j, l_g, &ret_ ); if( n == 0 && ( is_pl || !d->not ) ){ + my_area_free(&area, NULL); return 0; } ret_.idx = j;
ここでした。 見事にfree抜けてました。
v47で、この修正だけ入れてみて無事20秒の動画を生成できました。
$ ./skill.sh $ make $ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=and.yaml data_name=all name=out_v47/and : wh : 293787/307200(95.6%) : total 9.49s : rest 0.41s : 2018/06/08 11:31:06 wh : 307200/307200(100.0%) : fin 9.10s frm : 600/600(100.0%) : fin 1h 51m 59.51s $ ls -lt out_v47/ | head -rw-r--r-- 1 kondoh staff 1416918 6 8 11:33 and_2.mp4 -rw-r--r-- 1 kondoh staff 3139752 6 8 11:33 and_1.mp4 -rw-r--r-- 1 kondoh staff 4862955 6 8 11:31 and.mp4 :
では本題。
v47のコードを整理しつつ、 物体のAND演算の箇所でOR演算でもXOR演算でも指定できるように作り変えてみました。
物体といっても対応してるのは未だ「球」と「立方体」だけです。
物体のOR演算は、素の状態で普通にORになってるはずです。 ですが、あえてOR演算として指定すると、OR演算した結果のNOTが取れたりできるので、 複雑な演算の指定をするときは便利かと。
(OR結果のNOTなら、ドモルガンの定理で展開して 個別にNOTしてANDすれば良いのでは? などと突っ込んではいけません)
視線で串刺しにして領域の演算をするときに使う area.[ch]は、 できるだけシンプルにまとめなおしてみました。
それを使う側の cross.c 。 「とっちらかり」を押さえ込んでシンプルに。 まとめなおしてふと気づくと、 先のv47のメモリリークの対応箇所は、原因の箇所自体が消えてしまいました。
サンプルデータは op.yaml を追加してます。
前回同様ワイヤーフレーム側の処理は、物体の演算には対応してません。 というか、しません。
$ mv rt_v47 rt_v48 $ cat v48.patch | ( cd rt_v48 ; patch -p1 ) $ cd rt_v48 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v48/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.11s
以前の v47 wh : 76800/76800(100.0%) : fin 3.04s v45 wh : 76800/76800(100.0%) : fin 3.00s v43 wh : 76800/76800(100.0%) : fin 2.96s v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02sそれでは op.yaml で試してみます。
$ cat op.yaml defs: rtd_A: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } mov4: IMG_3999_4.mov big_ball: - kind: ball rtd: { diff: 0.3 } maps: - fn: '*mov4' fn_r: '*mov4' t2m: [ ax.zoom_all(2), ax.rot_x(90) ] - fn: '*mov4' fn_r: '*mov4' t2m: [ ax.zoom_all(2), ax.rot_x(90), ax.rot_z(180) ] m2g: [ ax.zoom_all(1000) ] all: - kind: export export: big_ball - kind: or args: - kind: ball rtd: '*rtd_A' - kind: cube rtd: '*rtd_A' m2g: [ 'ax.zoom_all(0.8)' ] m2g: [ 'ax.slide([-1,-1,0])', 'ax.zoom_all(20)' ] - kind: and args: - kind: cube rtd: '*rtd_A' m2g: [ 'ax.zoom_all(0.8)' ] - kind: ball not: True rtd: '*rtd_A' m2g: [ 'ax.slide([1,-1,0])', 'ax.zoom_all(20)' ] - kind: and args: - kind: ball rtd: '*rtd_A' - kind: cube not: True rtd: '*rtd_A' m2g: [ 'ax.zoom_all(0.8)' ] m2g: [ 'ax.slide([-1,1,0])', 'ax.zoom_all(20)' ] - kind: and args: - kind: ball rtd: '*rtd_A' - kind: cube rtd: '*rtd_A' m2g: [ 'ax.zoom_all(0.8)' ] m2g: [ 'ax.slide([1,1,0])', 'ax.zoom_all(20)' ] # EOF
になってます。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op.yaml data_name=all name=out_v48/op_tst div=4 fps=15 : wh : 19200/19200(100.0%) : fin 0.83s frm : 300/300(100.0%) : fin 6m 57.12s estimated 3.71 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op.yaml data_name=all name=out_v48/op : wh : 260050/307200(84.7%) : total 20.16s : rest 3.09s : 2018/06/09 04:46:31 wh : 307200/307200(100.0%) : fin 17.19s frm : 600/600(100.0%) : fin 4h 10m 41.01s $ ls -lt out_v48/ | head -rw-r--r-- 1 kondoh staff 3098316 6 9 04:48 op_2.mp4 -rw-r--r-- 1 kondoh staff 3142561 6 9 04:48 op_1.mp4 -rw-r--r-- 1 kondoh staff 6684097 6 9 04:46 op.mp4 :
円柱と円すいも「物体の論理演算」に対応してみました。
$ mv rt_v48 rt_v49 $ cat v49.patch | ( cd rt_v49 ; patch -p1 ) $ cd rt_v49 $ make clean $ make
結構変更を入れたので、一応前回v48のデータで軽く確認をば。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op.yaml data_name=all name=out_v49/opck fps=0.25 : 2018-06-10 22:52:49.994 Python[20334:447913] mMovieWriter.status: 3. Error: Cannot Save frm : 5/5(100.0%) : fin 2m 28.28s estimated 4.94 hour at 640*480 30fps $ ls -lt out_v49/ | head -rw-r--r-- 1 kondoh staff 110069 6 10 22:52 opck00005.jpg -rw-r--r-- 1 kondoh staff 93857 6 10 22:52 opck00004.jpg -rw-r--r-- 1 kondoh staff 115985 6 10 22:51 opck00003.jpg -rw-r--r-- 1 kondoh staff 104601 6 10 22:51 opck00002.jpg -rw-r--r-- 1 kondoh staff 78305 6 10 22:50 opck00001.jpg :
なにやらエラーが出てますが、 たぶんfpsの指定が小さい値過ぎて動画へのフレームの追加が出来なかったとかでしょうか? 静止画のファイルは出来ているのでOK。
では、円柱と円すいのデータop2.yamlをば。
$ cat op2.yaml defs: rtd_A: { base: 0.1, diff: 0, reflect: 0.5, reflact: 0.5, density: 2 } mov4: IMG_3999_4.mov big_ball: - kind: ball rtd: { diff: 0.3 } maps: - fn: '*mov4' fn_r: '*mov4' t2m: [ ax.zoom_all(2), ax.rot_x(90) ] - fn: '*mov4' fn_r: '*mov4' t2m: [ ax.zoom_all(2), ax.rot_x(90), ax.rot_z(180) ] m2g: [ ax.zoom_all(1000) ] all: - kind: export export: big_ball - kind: and args: - kind: ball not: True rtd: '*rtd_A' m2g: - ax.zoom_all(0.5) - ax.slide_x(1) - kind: cube not: True rtd: '*rtd_A' m2g: - ax.zoom_all(0.5) - ax.slide_x(-1) - kind: xor args: - kind: pipe rtd: '*rtd_A' m2g: - 'ax.slide( way.liss([-1,-1,-1],[1,1,1],[3,4,5])(sec) )' - kind: cone rtd: '*rtd_A' m2g: - ax.zoom_z(2) - ax.slide_z(-1) - 'ax.slide( way.liss([1,1,1],[-1,-1,-1],[4,5,6])(sec) )' m2g: - ax.rot_x(90) - ax.zoom_all(20) # EOF
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op2.yaml data_name=all name=out_v49/op2_tst div=4 fps=15 : wh : 19200/19200(100.0%) : fin 0.24s frm : 300/300(100.0%) : fin 2m 27.70s estimated 1.31 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op2.yaml data_name=all name=out_v49/op2 : wh : 307200/307200(100.0%) : fin 9.04s frm : 600/600(100.0%) : fin 1h 50m 22.71s $ ls -lt out_v49/ | head -rw-r--r-- 1 kondoh staff 1627032 6 10 22:24 op2_2.mp4 -rw-r--r-- 1 kondoh staff 3145033 6 10 22:24 op2_1.mp4 -rw-r--r-- 1 kondoh staff 5046499 6 10 22:22 op2.mp4 :
円柱と円すいは、リサージュで適当に移動させてXORをとってます。 視線の先あたりに「球のNOT」と「立方体のNOT」が隠れていて、それらとANDをとってます。
もはや完成像の想像がついていけず、、、 これが正しい結果なのか、全然判りません。
ちょっと、円柱と円すいを角柱と角すいに置き換えてためしてみます。
$ cp op2.yaml op3.yaml op3.yaml を編集して... $ diff -u op2.yaml op3.yaml --- op2.yaml 2018-06-10 20:28:40.000000000 +0900 +++ op3.yaml 2018-06-10 23:29:55.000000000 +0900 @@ -34,11 +34,13 @@ - ax.slide_x(-1) - kind: xor args: - - kind: pipe + - kind: poly_n_prism + n: 16 rtd: '*rtd_A' m2g: - 'ax.slide( way.liss([-1,-1,-1],[1,1,1],[3,4,5])(sec) )' - - kind: cone + - kind: poly_n_pyramid + n: 16 rtd: '*rtd_A' m2g: - ax.zoom_z(2)
などと16角柱と16角すいに置き換え
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op3.yaml data_name=all name=out_v49/op3 : wh : 307200/307200(100.0%) : fin 19.84s frm : 600/600(100.0%) : fin 5h 11m 24.03s $ ls -lt out_v49/ | head -rw-r--r-- 1 kondoh staff 853892 6 11 04:57 op3_4.mp4 -rw-r--r--@ 1 kondoh staff 3140471 6 11 04:57 op3_3.mp4 -rw-r--r-- 1 kondoh staff 3145345 6 11 04:56 op3_2.mp4 -rw-r--r-- 1 kondoh staff 3129328 6 11 04:55 op3_1.mp4 -rw-r--r--@ 1 kondoh staff 10784054 6 11 04:53 op3.mp4 :
円柱1つのところが16*3個の三角形の平面に展開されるので、 さすがに時間がかかりますね。
これは、、、円すいの時と比べて、明らかに角すいの表示がおかしいです(>_<)
底面の多角形が、同じ平面上にある複数の三角形に展開されるところが、 領域の演算の処理的には問題が出てるのかも知れません...
前回のv49で、角柱と角すいで試したときの変な挙動を修正してみました。
結構根深い問題で、根本的に勘違いしてる箇所がありました。
例えば、球の表面の法線ベクトルは、中心から表面までのベクトルの方向にしてます。
アフィン変換で球をひしゃげさせたとしても、 法線ベクトルにも同じアフィン変換をかけて、ひしゃげさせて使ってます。
球は、おそらくこれで問題ないでしょう。
角すいの斜めな側面の平面について。
平面上の表面の法線ベクトルは、平面の法線の方向にしてます。
アフィン変換で角すいをひしゃげさせたとき、 球の時と同様に法線ベクトルにも同じアフィン変換をかけて、ひしゃげさせておりました。
/ . / . / . / / / / /
つまり、こういう斜めの直線と、直行する法線ベクトルがあったとして 横方向に押しつぶすと
/ . / . / ./ / / / /
直行じゃなくなります。
/ / .. / ../ / / / /
図がアレですが、押しつぶした後も直線に対して直行してほしいのです。
という理屈からすると、 円柱や円すいの側面も、例えば回転で斜めに倒してから上下に押しつぶすようなアフィン変換をかけると、 まずい気がします...
ですが、とりあえず、平面の場合だけ修正して試してみます。
$ mv rt_v49 rt_v50 $ cat v50.patch | ( cd rt_v50 ; patch -p1 ) $ cd rt_v50 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v50/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.03s
以前の v48 wh : 76800/76800(100.0%) : fin 3.11s v47 wh : 76800/76800(100.0%) : fin 3.04s v45 wh : 76800/76800(100.0%) : fin 3.00s v43 wh : 76800/76800(100.0%) : fin 2.96s v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
まずはop2.yamlの円柱、円すいで
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op2.yaml data_name=all name=out_v50/op2ck fps=1 : wh : 307200/307200(100.0%) : fin 11.04s frm : 20/20(100.0%) : fin 4m 32.99s estimated 2.27 hour at 640*480 30fps $ ls -lt out_v50/ | head -rw-r--r-- 1 kondoh staff 668844 6 12 00:17 op2ck.mp4 -rw-r--r-- 1 kondoh staff 63314 6 12 00:17 op2ck00020.jpg -rw-r--r-- 1 kondoh staff 67621 6 12 00:17 op2ck00019.jpg -rw-r--r-- 1 kondoh staff 63586 6 12 00:17 op2ck00018.jpg -rw-r--r-- 1 kondoh staff 101408 6 12 00:16 op2ck00017.jpg -rw-r--r-- 1 kondoh staff 93465 6 12 00:16 op2ck00016.jpg -rw-r--r-- 1 kondoh staff 73056 6 12 00:16 op2ck00015.jpg -rw-r--r-- 1 kondoh staff 88722 6 12 00:16 op2ck00014.jpg -rw-r--r-- 1 kondoh staff 50637 6 12 00:16 op2ck00013.jpg
大丈夫そうですね。
そしてop3.yamlの16角柱、16角柱すい
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op3.yaml data_name=all name=out_v50/op3 : wh : 289697/307200(94.3%) : total 21.32s : rest 1.21s : 2018/06/12 06:06:35 wh : 307200/307200(100.0%) : fin 20.15s frm : 600/600(100.0%) : fin 5h 40m 58.89s $ ls -lt out_v50/ | head -rw-r--r-- 1 kondoh staff 1560496 6 12 06:08 op3_2.mp4 -rw-r--r-- 1 kondoh staff 3142729 6 12 06:08 op3_1.mp4 -rw-r--r-- 1 kondoh staff 5021109 6 12 06:06 op3.mp4 :
5時間40分。OKです。
今回のパッチに、しれっと視点移動の箇所に変更というか、指定の追加を入れてみました。
物体の方でリサージュな動きをさせたときに、視点も合わせて追随しやすいかと。
コインのデータで試してみます。
最後尾のコインのさらに後ろに11個目のコインがある場合の位置に視点をもってきて、 最後尾のコインを目標にして視線を設定してみました。
ジェットコースターの後からの眺めを狙ってみましたが、はたして?
$ ./cg.py ep=[-20,-20,-20],[20,20,20],[3,4,5],-3 et=[-20,-20,-20],[20,20,20],[3,4,5],-2.7 sec=20 yaml=spin_coin.yaml data_name=all name=out_v50/coin : wh : 290213/307200(94.5%) : total 9.08s : rest 0.50s : 2018/06/12 11:10:49 wh : 307200/307200(100.0%) : fin 8.62s frm : 600/600(100.0%) : fin 1h 44m 44.07s ls -lt out_v50/ | head -rw-r--r-- 1 kondoh staff 3049291 6 12 11:11 coin_1.mp4 -rw-r--r-- 1 kondoh staff 3170370 6 12 11:10 coin.mp4 : 1時間45分。 久々に、3Mバイトを超えてるけど、展開してまとめなおすと3Mバイトに収まるパターンでした。
ジェットコースター。激し過ぎて何が何やら、、、
アフィン変換でひしゃげたときの「法線ベクトル問題」について、 円柱や円すいの側面の場合も対応してみました。
平面の場合も前回のv50のやり方では、-1倍の拡大をかけた場合とか 意図しないケースで法線が反転していたので、 方式を変更しておきました。
デバッグしやすいように、 dat.py でのデータの展開結果について、 なるべく文字列の段階で展開を終えさせて、 展開結果の表示が見易いようにしてみました。 文字列からバイナリへの変換は、後段でまとめて処理するようにしてみました。
$ mv rt_v50 rt_v51 $ cat v51.patch | ( cd rt_v51 ; patch -p1 ) $ cd rt_v51 $ make clean $ make
では、いつもの速度確認。
$ ./cg.py eyep=[0,0,0],200,10 sec=10 data_name=objs name=out_v51/objs_1_2_sc n=1 init_sec=5 div=2 : wh : 76800/76800(100.0%) : fin 3.09s
以前の v49 wh : 76800/76800(100.0%) : fin 3.03s v48 wh : 76800/76800(100.0%) : fin 3.11s v47 wh : 76800/76800(100.0%) : fin 3.04s v45 wh : 76800/76800(100.0%) : fin 3.00s v43 wh : 76800/76800(100.0%) : fin 2.96s v42 wh : 76800/76800(100.0%) : fin 3.16s v39 wh : 76800/76800(100.0%) : fin 15.37s v38 wh : 76800/76800(100.0%) : fin 15.09s v37 wh : 76800/76800(100.0%) : fin 15.49s v36 wh : 76800/76800(100.0%) : fin 15.13s v35 wh : 76800/76800(100.0%) : fin 16.16s v34 wh : 76800/76800(100.0%) : fin 38.47s v32 wh : 76800/76800(100.0%) : fin 26.84s v31 wh : 76800/76800(100.0%) : fin 40.50s v30 wh : 76800/76800(100.0%) : fin 38.39s v29 wh : 76800/76800(100.0%) : fin 1m 44.72s v28 wh : 76800/76800(100.0%) : fin 1m 18.06s v27 wh : 76800/76800(100.0%) : fin 1m 8.39s v26 wh : 76800/76800(100.0%) : fin 1m 6.02s
op2.yamlの円柱、円すいのデータで反射の絵柄の違いを見てみます。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=op2.yaml data_name=all name=out_v51/op2ck fps=0.25 : wh : 307200/307200(100.0%) : fin 9.30s frm : 5/5(100.0%) : fin 1m 6.17s estimated 2.21 hour at 640*480 30fps $ ls -lt out_v51/ | head -rw-r--r-- 1 kondoh staff 144 6 14 01:45 op2ck.mp4 -rw-r--r-- 1 kondoh staff 101409 6 14 01:45 op2ck00005.jpg -rw-r--r-- 1 kondoh staff 50623 6 14 01:45 op2ck00004.jpg -rw-r--r-- 1 kondoh staff 73917 6 14 01:44 op2ck00003.jpg -rw-r--r-- 1 kondoh staff 68342 6 14 01:44 op2ck00002.jpg -rw-r--r-- 1 kondoh staff 55695 6 14 01:44 op2ck00001.jpg
fpsの指定が小さいときは、動画の1コマ追加でエラーが出てたので、 fpsが1未満なら動画はあきらめる対策を入れてみました。;-p)
右となりに対応するv50の絵を並べてみます。
間違い探し? どこが違うかよく判りませんね。
では、AND,OR,NOTを駆使して、 スポーツカーっぽい物体のデータを cool_car.yaml に作ってみました。
$ ./cg.py eyep=[0,0,0],[300,300,100],10 sec=20 yaml=cool_car.yaml data_name=all name=out_v51/car : wh : 256259/307200(83.4%) : total 11.62s : rest 1.92s : 2018/06/14 04:18:10 wh : 307200/307200(100.0%) : fin 10.26s frm : 600/600(100.0%) : fin 2h 12m 4.18s $ ls -lt out_v51/ | head -rw-r--r-- 1 kondoh staff 484681 6 14 04:20 car_2.mp4 -rw-r--r-- 1 kondoh staff 3142210 6 14 04:20 car_1.mp4 -rw-r--r-- 1 kondoh staff 3885846 6 14 04:18 car.mp4 :
2時間12分。 視点がそう少し近い方が良かったかな。 ボデー表面で屈折光ましましにしたので、透けてる感が強いです。
良さげな静止画を選んでみました。
モーターショーの展示のような、 断面むき出しの「カットモデル」な表示を目指してみました。
$ mv rt_v51 rt_v52 $ cat v52.patch | ( cd rt_v52 ; patch -p1 ) $ cd rt_v52 $ make clean $ make
まずは前回悔やまれた視点接近バージョンをば。
$ diff -u cool_car.yaml cool_car_r.yaml --- cool_car.yaml 2018-06-14 00:58:53.000000000 +0900 +++ cool_car_r.yaml 2018-06-15 21:57:23.000000000 +0900 @@ -144,5 +144,6 @@ export: cool_car m2g: - ax.zoom_all(0.2) + - ax.rot_z(180) # EOF
前後の向きだけちょっと変更。
$ ./cg.py eyep=[0,0,0],[130,90,30],10 sec=20 yaml=cool_car_r.yaml data_name=all name=out_v52/car_ : wh : 307200/307200(100.0%) : fin 17.96s frm : 600/600(100.0%) : fin 3h 44m 43.21s $ ls -lt out_v51/ | head -rw-r--r-- 1 kondoh staff 451544 6 14 13:37 car__2.mp4 -rw-r--r-- 1 kondoh staff 3142600 6 14 13:37 car__1.mp4 -rw-r--r-- 1 kondoh staff 3846140 6 14 13:35 car_.mp4 :
さて、カットモデル用のデータ cool_car_cut.yaml。
元々ボデーの曲面は、 球に対してx,y,z方向に異なる割合で拡大をかけた楕円体を3つ用意して、 ANDをとった領域になってます。
固形石鹸のような感じになってしまうかと思ったら、 案外いい感じの曲面になってます。
まずは、この3つの楕円体を移動させつつ、 楕円体そのものも薄い透明で表示させてみました。
さらにカットモデルにするため、 カット用の立方体を用意して、 スポーツカー本体とANDをとって断面を見せてみます。
$ ./cg.py eyep=[0,0,0],[300,300,100],20 sec=20 yaml=cool_car_cut.yaml data_name=all name=out_v52/cut_tst div=8 fps=3 : wh : 4800/4800(100.0%) : fin 0.23s frm : 60/60(100.0%) : fin 46.13s estimated 8.20 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[300,300,100],20 sec=20 yaml=cool_car_cut.yaml data_name=all name=out_v52/cut : wh : 307200/307200(100.0%) : fin 12.50s frm : 600/600(100.0%) : fin 5h 58m 1.88s $ ls -lt out_v52/ | head -rw-r--r-- 1 kondoh staff 3139682 6 16 04:32 cut_1.mp4 -rw-r--r-- 1 kondoh staff 97864 6 16 04:32 cut_2.mp4 -rw-r--r-- 1 kondoh staff 3479803 6 16 04:30 cut.mp4 :
$ ./cg.py eyep=[0,0,0],[130,90,30],10 sec=20 yaml=cool_car_cut.yaml data_name=all name=out_v52/cut2_tst div=8 fps=3 : wh : 4800/4800(100.0%) : fin 0.59s frm : 60/60(100.0%) : fin 1m 36.82s estimated 17.21 hour at 640*480 30fps
$ ./cg.py eyep=[0,0,0],[130,90,30],10 sec=20 yaml=cool_car_cut.yaml data_name=all name=out_v52/cut2_ : wh : 307200/307200(100.0%) : fin 24.96s frm : 600/600(100.0%) : fin 15h 10m 20.77s $ ls -lt out_v52/ | head total 198360 -rw-r--r-- 1 kondoh staff 930308 6 16 22:45 cut2__2.mp4 -rw-r--r-- 1 kondoh staff 3139356 6 16 22:45 cut2__1.mp4 -rw-r--r-- 1 kondoh staff 4354425 6 16 22:43 cut2_.mp4
15時間ちょい。