物体の繰り返しコピー配置

同じ物体をコピーして繰り返し位置をズラして配置できるようにしてみました。

もともと立方体(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() にしてみました。

v36.patch

$ 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秒

そういうものなのだろうか。なんかどこかで間違ってたりしないだろうか?