2010年8月11日水曜日

VideoCube 9

何故か分からないが、この(Faceの中の)Groupの塊の中で、PolygonがMouseイベントを受けている。サイコロとしては一体なので、そもそもFaceで受けるというのは、その面をどうにかした(操作した)という意味だろう。だが、感覚的に3Dオブジェクトであるサイコロを回転させるという操作は、サイコロの外でマウスというよりジェスチャーで動きを指示しているイメージがある。もしかしたらそういう風にもできるのかもしれないが、回転させた面を書き換えるのと、サイコロ全体を書き換えるのの違いが分からない今としては、何とも言えないところ。とりあえず今わかっているのは面がonMouseClickedとonMouseDraggedを受けて、角度の変化を見て、cxとsxを(bindを通じて)書き換えておき、これをTimelineを通じて40msで(回転角があれば)rotateX//Yによりサイコロの8つの頂点を回転させるらしいということ。ただ今の時点では、rotateX/Yの中身が分かっていないので、8つの頂点を回転させるという処理自体も意味を分かってないし、PerspectiveTransformの効果と合わせて、サイコロが回転しているように見える原理がまるでワカランチンだ。

そもそも見た目3Dなので3Dで考えてしまっていたが、(ここから飛行機内で分かったこと)サイコロはあくまで2Dで描画されるのだと思う。で、サイコロが回転すると、2D的には変形することになるが、それを各面のPerspectiveTransformを使って実現している、と。

だとすると、その変形は結局2方向の成分の合成で求められると思う。つまり正面から見て前後に回転する場合、正面にある四角は徐々につぶれて行く。つまり、縦の長さが短くなって行く訳だ。また、この動きを真横からみると、円運動になる。つまり、面を斜辺とした三角形の回転と考えればわかりやすい。例えばサイコロを30度後ろにそらすと、横から見て、初め面は垂直だったのが、垂線から30度、水平線からは60度傾いた斜辺となり、それによる直角三角形の高さ部分が正面から見えている領域ということになる。だから更に後ろにそらして行くと、やがて水平になるが、このとき正面から見える面が全くなくなる。その後さらにそらしていくと、逆さになるが、正面からサイコロを見るという場合においては、裏側に行ってしまうので、この状態でも正面からは見えない状態になる。そうして一周してくると、徐々にまた見えだしてくるが、このとき見える領域は、マイナスの高さ分になるが、量としては最初と同じような変化になることは言うまでもない。

さて、こうしてみると、正面からみたサイコロの正面の面の見え方は、正面の面を斜辺とし、θを回転角とする直角三角形におけるcosθで表される事になる。もしサイコロが縦方向にしか回転しないのであれば、このcosθを高さとしてPerspectiveTransformすれば、正の高さを持つ間に関しては、単純に描画されると思われる。あとは裏側に行った場合にどうするか。他の面がそり上がってくることで、描画の重なりをうまく考慮できれば、常に最前面にそり上がってくる面が一番上で描画され、他は隠されると思われる。もっとも、隠されたときに無駄な描画が発生しないことも重要である。

ここまで来れば、あとは全ての面について、合成すれば、万事サイコロが書けるはず。ということは、そういうふうにVideoCubeはやっているのではないかと。

移動した量を角度としてどう算出するかは、マウスの移動量をどう角度に結びつけるかという、ある種決めの問題だが、実際の動作との兼ね合いで決めて行くしかない。VideoCubeは少なくともマウス移動の加速度や移動量から回転速度が変わるような高度な動きはしていないので、現状を理解すれば、その先の展開上の問題にあがるかもしれない。

だが、PerspectiveTransformは面にしかかかってないので、サイコロ全体を鳥瞰しているわけではない。3D的にはサイコロ全体に対してかけたいが、これはどうしたらいいか、分からない。とまた前述の3Dの話に戻るので止めよう。ここではPerspectiveTransformが各面に対して利いているだけで、またVideoCube的にはそれでOKになっているということだけ念を押して理解しておくこと。
onMouseDragged:function(event) {
ax = if (-5 < event.dragY and event.dragY < 5)
then 0 else - event.dragY/10000;
ay = if (-5 < event.dragX and event.dragX < 5)
then 0 else event.dragX/10000;
}
-5〜5なら0、それ以外は1万で割る。随分大きくでたねぇ。axはMath.sin(ax)となるのでラジアンである。ラジアンって360度で1?(2010.8.12追記 2πだから約6.28)まいいや。いま機中なのでWebに繋がらないから後で調べる事にする。何れにしてもドラッグ量から回転角を出すだけなので、この辺は感覚の問題でもあるし。

0 件のコメント:

コメントを投稿