気泡とヘアライン

v55の パックマンもどき(その3) で気になった気泡とヘアラインを対策してみました。

まず「気泡」問題。

以前、 気泡 気泡 その2 で割としっかり対策したはずの「つぶつぶ」の表示が、 またしても出てる感じです。

カットアンドトライで状況を再現してみます。 パックマンのpac.yamlから再現する箇所を絞りこんでいくと、、、

$ cat bubble.yaml
all:
- kind: or
  args:
  - kind: pipe
  rtd: { base: 0.1, diff: 0.3, reflect: 0.5, reflact: 0.2, density: 1, reflect_backside: False }
  m2g:
  - ax.zoom_z(0.5)
  - ax.slide_z(-0.5)
  - ax.zoom_all(0.5)
# EOF

$ ./cg.py eyep=[0,2,-0.5-1.5],0,1 eyet=[0,0,-0.5] yaml=bubble.yaml data_name=all name=out_v56/b n=1 show_sec=-1 div=2

ところがこれ、OR演算してないと再現しません。

bubble.yaml を

$ cat bubble.yaml
all:
- kind: pipe
  rtd: { base: 0.1, diff: 0.3, reflect: 0.5, reflact: 0.2, density: 1, reflect_backside: False }
  m2g:
  - ax.zoom_z(0.5)
  - ax.slide_z(-0.5)
  - ax.zoom_all(0.5)

に書きかえてためしてみると

$ ./cg.py eyep=[0,2,-0.5-1.5],0,1 eyet=[0,0,-0.5] yaml=bubble.yaml data_name=all name=out_v56/bb n=1 show_sec=-1 div=2

ということは、物体の演算箇所があやしい。 cross.c cross_op()関数あたりにデバッグアウトを入れて確認していくと、 ここ。cross_op_ins()関数でした。

	  :
	}else if(n == 1){
		r->t = r->ts[0];
		line_on_line_p( &r->l, r->t, r->p );
		cross_get_nv( d->kind, &d->l2g, l_g, 0, r );
		r->flags = 0;
		area_ins( a, r->t, r, sizeof(*r) );
		if(r->ang_nv_eyev >= 0){
			area_not(a);
		}
	}else{ /* n == 2 */
		int i;
		for(i=0; i<2; i++){
			r->t = r->ts[i];
			line_on_line_p( &r->l, r->t, r->p );
			r->flags = 0;
			if( prev_idx == r->idx && fabs(r->t) < fabs(r->ts[1-i]) ){
				r->flags |= CROSS_FLAG_PREV;
			}
			area_ins( a, r->t, r, sizeof(*r) );
		}
	}
	  :

交点が2つの場合がある、球、円柱、円すいは、prev_idx を CROSS_FLAG_PREV に反映できてましたが、 平面系の交点が1つの場合に処理が抜けてました。

なので、モンスターの円柱の底面の平面の円の部分。 ここに気泡が出てたと。 対策しておきます。

続いて、「ヘアライン」問題。

カットアンドトライで絞って再現してみると。

$ cat hair_line.yaml
all:
- kind: or
  args:
  - kind: pipe
    rtd: { base: 0.1, diff: 0.3, reflect: 0.5, reflact: 0.2, density: 2 }
    m2g:
    - ax.rot_y(90)
    - ax.slide_y(2)
# EOF

$ ./cg.py eyep=[0,-50,20],0,1 yaml=hair_line.yaml data_name=all name=out_v56/h n=1 show_sec=-1 div=2

これで再現します。

そして、これまたOR演算をはずすと...

$ cat hair_line.yaml
all:
- kind: pipe
  rtd: { base: 0.1, diff: 0.3, reflect: 0.5, reflact: 0.2, density: 2 }
  m2g:
  - ax.rot_y(90)
  - ax.slide_y(2)
# EOF

$ ./cg.py eyep=[0,-50,20],0,1 yaml=hair_line.yaml data_name=all name=out_v56/hh n=1 show_sec=-1 div=2

これまた cross.c の物体の演算箇所にデバッグアウトを入れて、 area.c の area_show() を呼び出して確認していくと、、、

原因はここでした。

	  :
	}else if(n == 1){
		r->t = r->ts[0];
		line_on_line_p( &r->l, r->t, r->p );
		cross_get_nv( d->kind, &d->l2g, l_g, 0, r );
		r->flags = 0;
	/* --> さっき気泡対策した箇所 */
		if( prev_idx == r->idx ){
			r->flags |= CROSS_FLAG_PREV;
		}
	/* <-- さっき気泡対策した箇所 */
		area_ins( a, r->t, r, sizeof(*r) );
		if(r->ang_nv_eyev > 0){ /* ヘアライン問題の原因 ここ */
			area_not(a);
		}
	  :

なんと、さっき対策したばかりの箇所の直後の位置。

原因はここで、問題は r->ang_v_eyev の値が 0 の場合に、 ヘアラインが出てしまうのですが、、、

問題は、その対策です。 果たして、r->ang_nv_eyev >= 0 とするのが正解か?

例えば、物体「円柱」はdat.pyで展開されて、 内部的に「円柱の側面」、「円柱の上面の円」、「円柱の底面の円」のAND演算 として実現してます。

このAND演算に限れば、 r->ang_nv_eyev > 0 の箇所を、 r->ang_nv_eyev >= 0 に修正する対策で良さそうです。

でももしOR演算で物体を構成する場合なら、 r->ang_nv_eyev == 0 の場合は、area反転しない方が良いのでは?

でもでも、現状では、物体をOR演算で構成する場合が無いのでは?

まぁとりあえず、 趣味のプログラミングなので、 安易に対策して様子見です。

v56.patch

$ mv rt_v55 rt_v56
$ cat v56.patch | ( cd rt_v56 ; patch -p1 )
$ cd rt_v56
$ make clean
$ make

パックマンのデータで気になった「ちょうど」なアングルの静止画を確認してみます。

$ ./pac_dat.py

$ wget http://kondoh2.html.xdomain.jp/rt/pac.log
$ mv pac.log pac/

$ ./pac_dat.py

$ ./cg.py eyep=[0,0,20],[50,50,10],20 sec=30 yaml=pac.yaml data_name=all name=out_v56/pac_tst3_ fps=0.2
  :

v55の画像、v56の画像の順で並べてみます。

もともと底面の気泡は確認できない角度でしたが、、、 ヘアライン。一部改善されたものの、まだ出てます。

まだヘアライン対策、十分ではないですね。

気泡の方も確認してみます。

v54のこのアングル。 まぁ、これだと元々あまり気泡も気にならない感じですが、、、 以前のv54の実行時のパラメータが

$ ./cg.py eyep=[0,0,0],[60,60,40],10 sec=20 yaml=pac.yaml data_name=all name=out_v54/pac

30pfs 20秒で600コマ中の97コマめなので

時刻 20*(97-1)/600 = 3.2秒
$ ./cg.py eyep=[0,0,0],[60,60,40],10 sec=20 yaml=pac.yaml data_name=all name=out_v56/pac init_sec=3.2 n=1 show_sec=-1

モンスターのログデータの先頭の時刻の処理をちょっと変えてた気がするので、 若干絵が異なってしまいましたが、、、 底面の気泡は無事消えましたね。