2019年5月4日土曜日

copyToPointの回転まわり

オブジェクトをcopyToPointでコピーする際、v,N,up,orient,rotを使用して回転する方法をまとめました。なかでも、よく使用するpopで動きを付けた後、sopで回転制御する方法です。
このまとめの発端は、以下のcase3で起こる問題に悩んでたのですが、odforceでみつけたhipにより道がひらけ色々学べたことです。
なので、問題を解決したベースのアイデアとしては、そのhipがもとになっております。
また、他にもっとシンプルなやり方があるかもしれないです。なるべくシンプルで分かりやすい方法でやりたいので、そういうのありましたら教えてくださいませ。

前提知識として、以下の2項目に触れておくと、検証動画もすんなり理解できるかもしれません。

▼v,N,up,orient,rotについて
こちらに詳細が書かれてあります。使い方はこちらとか。
orientはN,upのようにquatanionで姿勢を制御できるようです。なので姿勢を制御するならN,upの二つのアトリビュートかorientの1つのアトリビュートかどちらかでよさそうです。orientは、N,up含む値なのでNとupはdeleteしても大丈夫です。
次に、orientともう一つのquatanionのrotというものがあります。
現状自分なりの解釈ではorientで姿勢決めてrotでその姿勢の任意の軸をもとにspinしてやるときに使うのが分かりやすく便利かなと思います。orientだけでいきたい!という方は姿勢を決めたorientにrotのquatanionをかけてあげれば、同じ結果が得られます。
また、N,up,orient,rotがない場合vがあれば回転してくれるようです。
※姿勢と回転(spin)という言葉がまじりあってますが、計算自体は同じquatanionで、わかりやすく区別しています。

▼quatanionについて
google検索すればたくさん情報でてきますね。
その中でも、こちらがとても参考になりました。
まだ、記事全てを把握はできてませんが、quatanionで姿勢を制御することや補間についてイメージできました。式より図で示してくれるとわかりやすいですね。
他にも姿勢、回転を制御するにはオイラー方式がありますが、制限や計算の負荷の面から考えるとquatanionの方が優位だそうです。2D空間の回転の場合はオイラーのほうがよいでしょう。お互いの利点を見極め使っていくとよいでしょう。そして、quatanion,オイラーは最終的には回転行列に変換され回転されます。
mayaのヘルプにも面白いの発見しました。案外丁寧に説明されてました。mayaだとquatanionの補間にも最短と最長があり選べたりできるみたいですね。
cg wikiにもあります。これ一通りやるほうがためになるでしょう。自分は、まだ追えてません。

では、簡単な回転からやっていきましょう。
ちなみに、以下の検証したhip※随時更新中)です。すべて言葉でカバーするのは大変なのでデータ観ながら以下見てもらった方がよいかもです。

  • case1

randomSpinBasic
適当な姿勢(N,up)をランダムに作り、cross(N,up)で作成した軸をもとにspinさせました。動画を見る通り、時間軸に対し姿勢の各軸に変化はなく一定で、安定したspinです。はじめに回転軸を決めてあげるってのがポイントですね。やり方として飛び散る破片とかはこれで十分ではないでしょうか。

  • case2

VelocitySpinBasic
次に、進行方向vをNとして姿勢(N,up)をつくりspinさせます。姿勢は進行方向vに沿って時間軸で変化が見られますが、これくらいの変化であれば、問題はありません。

velocityDirectionBasic
spinを切って確認しても問題はありません。

  • case3

次に、姿勢が大きく変化するケースを見てみます。シチュエーションでいうと、ジェット機とかのエアロバティックス、空中を飛び回る生物、物体に衝突したり、forceによる強い外力を受けるときなどでしょうか。
こういった姿勢の変化はNG動画のようにやり方によって意図せぬ回転を引き起こします。

velocityDirectionBasicNG
よく見ると、方向転換する時クルっとフリップしたかのように回転しています。エラーのように見えます。
ちなみに今の設定は、case2同様に進行方向vをNにしてcross関数でupを作っております。

velocityDirectionBasicOK
こちらは、フリップのような回転を調整したものになります。
次から、どのように調整したのかを細かく進めながら原因も探っていきます。

  • case4

分かりやすく豚1匹にしました。
そして、それぞれのアトリビュートを比べてみます。

Only v attribute
Only N attribute
v,Nは変わらないようですね。

Only_N&Up_attribute
N&Upはcase.3のNGと同じ動きですが、頭の方向をupで指定することで、姿勢は保たれました。

orient
orientは、豚の初期方向とvからquatanionを作りそれをorientとしました。visualize用に、各軸quatanionで回転させています。
どれも意図しない回転が入ってNGですね。

突き詰めて探ってないので、想像ですが、考えられる原因として述べます。
なぜ意図しない回転が入るのかは、sopなので毎フレcrossだったり、quatanionだったり計算しなおしているので連続性が保たれないのが原因だと思います。
このケースではcrossやquatanionを計算する際、固定された任意の軸をもとに計算しています。
その任意の固定軸と進行方向vによって計算されるので、crossの計算で言うと、フレームによってはvが負の方向で次フレームで正の方向むけば右回り左回りと変化します。
quatanionも演算で外積使ってるみたいなので同じ理由かと。。適当。


  • case5

orient_QuaternionShortest
case4で連続性が保たれていないことが原因とみられたので、クォータニオンの作り方を変えます。そして、ここからはquatanionの性質を利用したいのでNとupは使用しません。性質というのは、quatanionの合成です。
まず、前フレームのvと現フレームのvからクォータニオンを計算します。そのクォータニオンを前フレームのクォータニオンにマルチプライする事で、合成します。そうすることで、前フレームからの最短のクォータニオンが得られます。ベクトル感覚なのが素敵ですね。
これで、大分安定してきました。

  • case6

orient_slerp
さらに、調整を加えます。
case.5をもとに方向転換する際、1フレで回転する量に制限をかけ急な方向転換を抑えます。
これには、quatanion同士をブレンド(球形補間)する方法を取ります。
vに遅れてNが回転するのが見て取れます。
これで姿勢のorientの制御は、充分に安定したかと思います。

  • case7

姿勢が安定したので、現在の姿勢の任意の軸を元に回転させてみます。こういったシチュエーションめったになさそうですが、続けます。
ようやく、初めの方に触れたrotの出番です。任意の軸はvisualizeで作ってる軸のどれかにします。その軸とangleでrotをquatanionとして作ります。そうすると、姿勢を保ったまま回転spinします。※追記5/25 rotをわざわざ作らなくてもqmultiplyで、rotのquatanionをorientにかけてあげればよい。
orientにランダムを加えることも簡単にできます。

orient_spin
orientRand_spin


※追記5/21
vのspeedで回転量を調整したい場合は、注意が必要で回転量が累積処理されているか確認しながらやるとよい。

以上です。
copyToPointは、なんだかんだ頻度高いので回転が必要になった際、自身が困らないようにの意味を含めてまとめました。全てを説明していくと時間がかかるため結構説明を省いてますが、hipをたどればある程度は理解できると思います。
又、houdiniの機能を使えば、quatanionなどの小難しいことに関しても、わかりやすく、そして深いところまで視覚的に説明できるのではないかとも思っています。自分のように数式アレルギーの方にはhoudiniは絶好の勉強道具ではないでしょうか。



2014年7月5日土曜日

TPで建物の破壊に挑戦してみた。




Destruction FX - (ThinkingParticles + FumeFx) from notchmen on Vimeo.


これまで、TPのR&Dを様々やってきましたが、ようやくTPの真骨頂とも言うべき破壊FXに挑戦してみました。小規模な破壊FXは仕事でも少なからず経験し今回のは、カテゴリにすると中規模?くらいになるかと思っています。なかなか仕事では、こういったクラスの仕事が入ってこないので自主制作という形でトライしてみました。そして、米岡さんによる破壊エフェクトセミナー後でもありタイミング的にもよかったと思います。

後、ムービー中に色々情報記載していますが、いくつか追記したいと思います。
今回制作に関わった者は会社の後輩と自分の二人になります。後輩には、隕石周りをお願いしました。建物のモデルは、turbosquidから自腹で購入しました。自分で制作してもよかったのですが時間ないのと破壊のスキルのほうを上げるのがメインだったので購入にいたりました。それでも、そのままでは使い物にはならないので、簡単にレタッチ、そして破壊モデル用として修正しています。

破壊用のプリカットモデルの作成には、Advanced Fragment scriptを使用しました。
rayfireと比べるとこちらは、破壊用のプリカットモデルを作る際に必要な機能だけチョイスされたようなものだと思います。直感的に分割できるのでおすすめです。

次にTPシーンの解説と行きたいところですが、その力は残っていないです^^
てか、解説するほどの新しい手法はあまり使ってないですね。
一つ上げるならば、debrisをVBされた破片にも継承させる事ですかね。
基本は、破壊エフェクトセミナーでの手法を取り入れさせてもらっています。A,B,C,Dと四往復以上読みましたw
又最近、 TheHouseFXrman197 といったマスター達が破壊のシーンを配布しております。前者は有料ですが。これは、TPで破壊やるなら通るべきものだと思うので落ち着いたら勉強しようと思います。

最後になりますが、この経験を経て、一番重要な点を上げるとしたら、いかにトライ&エラーできるセッティングにするかですかね。
それぞれの環境にもよると思うのですが、キャッシュ用のマシンがないとキツイと思います。あったとしてもやはり無駄な計算をさせないようにセッティングしていくのは重要な点でしょう。
破壊の見た目とは直接関わらないことかもしれませんが、最終的なできは違ってくるので気をつけたいところです。

2013年11月16日土曜日

TPでboidsをセットアップしてみる。その7 シェイプの向き解決?

さて、色々調べ物して更新までに時間がかかった。
前回、シェイプのある軸がフリップする現象に悩まされた。
色々探ったが、もうわからんのでCGTalkで質問したら、Hrist氏より「Just don't use the Z axis」とコメント頂いた。
--------------------
2013/11/18更新
Hrist
It's complicated, and I don't really understand 3D rotations completely, but let's try. When you define a rotation by one vector, say, the direction of travel, that's not actually enough information to align the particle. So it just assumes one more direction (up), and then gets the third by vector cross product of the two. And it might flip because at some point in rotating it the 'up' gets wrong because of the assumed second vector :)

っていうコメント追加でいただいたけど、、?
ん~フリップする原因はあるポイントで不正なベクトルを得ることによるため??なんか回避はできなそうだな。。外積での三つ目のベクトル計算のときに、二つ目のベクトルがフリップするからなんだろうけど、原因がわからん。適当に仮定したベクトルだからかな。

ちゃんとした方向を設定するには軌道方向( direction of travel)では、情報が少ない。だからクロスベクトルを必要とする。クロスベクトルは任意の仮定したベクトルから作ってやる。
問題点として、クロスベクトルを得る際に、仮定した二つ目のベクトルが元の方向( direction of travel)と重なった場合にフリップは起こるという事だと解釈。
なので、重ならないようになるべくすることが必要。くるくる回転されたらいつか重なるのは回避できない。
こういうときはクオータニオン??ただ整列させるだけには使わないのかな。整列+回転がクオータニオンの出番といったところか。
---------------


あーこれジンバルロックという事かな?
Alignmentの軸をx axisにすると思い通りの結果になった。






画質悪くてわかりづらいと思うが、意図した方向にお魚が向いている。
しかし、ゴールなしでこんな風にboidを放てばどっかでジンバルロックが起きるはず。。。
その解決法はクオータニオン??
謎は深まるばかりorz

とりあえず、一旦締めということでムービーでも作ろうかな。
でもboidは、色々勉強になるので、まだまだ探って行きたいと思います。

2013年10月26日土曜日

TPでboidsをセットアップしてみる。その6 シェイプの向き

う~最後の最後で、手詰まり。。。
解決はできていないが、問題をメモしたいと思う。
なんに手詰っているかというと、魚のシェイプの向きの設定だ。。
以前のAlignmentの記事では進む方向には向いているものの、体の上面、下面が揃っていない。

こんな感じ↓↓
青の方向が進む方向で、赤の矢印が上面下面だ。赤の矢印が上向いたり下向いたり安定しない。

次に試しに、赤の矢印が下向かないようにエクスプレッションで赤の矢印の-値を+値にするよう調整したが、今度は青の矢印が上手くいかなくなった。なんかぴくぴくしてるし。。
という具合で、あれこれ試しながら手詰まっている。
回転周り、ほんと苦手。。。
ちょっと、数学周り勉強しないと駄目なようだ。。

時間かかりそうだな~。。

2013年10月16日水曜日

TPでboidsをセットアップしてみる。その5 AvoidObstacles

いよいよ、終わりに近づいてきた。目標として、セットアップは次で終わりにしたい。
今回は、Separation(引き離し)の障害物版だ。前のSeparationでは、boids同士の引き離しのみをやった。
又、パーティクルが障害物を避ける記事は、前に記事に取り上げている。
前の記事と基礎的なフローは一緒と考えてよいかな。今回のと比べたいところだが長くなるのでやめとく。いえるのは、どっちも勉強になるということ。障害物は、引き出し多いほうが対処できるしね。

障害物追加設定した動画↓




なかなか、いい感じにできた。オリジナルのルールで障害物に近づくと、スピード落とすのも上手く機能している。


ではまず、障害物に対し、ある距離近づくとintersectで自身の進む方向にrayを飛ばし、rayが障害物にhitしたときに、メモリに必要データを保存している。
ここでは、メモリの使い方に注目してほしい。memoryのhitをONにしたりOFFにしたりしている。
画像の説明でわかるとよいが、、。。
勉強になるな~この辺はのメモリの使い方に関しては、ナイスガイのデータを参考にした。
前の記事ではObstclesはノードヘルパーで、やったのでこのようなことは必要なかった。障害物をPshapeにしたいときはPPassでこう組めばよいかな^^


次に、AvoidTargetを作成する。
これは、この方向へ避けますよというガイド的なもので、次ダイナミクスでベロシティにaddするために必要なデータをメモリに入れる。詳細はこちらの④と大体同じなので伏せて確認すると良い。

最後に、velocityの設定を行う。
ナイスガイは、上記の条件で方向を置き換えする設定にしていた。これだと、条件満たすと急に方向が変わるのでピクッとした動きになるかと思う。 これを、いつものvelocityにaddでできるだけ滑らかに表現したいと思った。
と、、記事を書きながら思ったんだけど、その方向を変えるベクトルを小さく(上記画像の半径にあたる)して、徐々に毎サンプルすることで急に方向が変わることは免れるのか!
まあ、でもvelocityにaddという方法を取り入れたことで、解かりやすいし色々スピード調整も可能だ。上記のオリジナルルールも取り入れる事ができた。
結局、addでなくて方向を置き換えることにした。動画は結果あまり変わらないので更新しない。
更新前

更新後



記事書きながら途中で気づいた点もあったりして、消化不良な感じになったがこれまで。
たぶん、最後のvelosityの設定は調整するかも。そのときは更新する。

以上。。





2013年10月15日火曜日

TPでboidsをセットアップしてみる。その4 Alignment

今回は、Alignment(整列)についてだ。
前回は、目に見えたboidsの合計平均位置を求めて、そこに飛ぶようにした。
Alignment(整列)も同じ感じで、目に見えたboidsの合計平均ベロシティを求めて周りとスピードを合わせるというものだ。後、boidsの向きを周りと合わせる。
さらに、boidsの最高速度を設定してスピードの制限をした。
この3つについて、みていきたい。

まず、それらを設定した動画↓↓




その2から比べると、周りのboidsにCohesion、Alignmentを設定したため、それらしくなっている。
又、お魚さんのシェイプも適当に割り当ててみた^^

始めに、前回と同じようにSumVelocityとpcountのメモリを用意する。

これは次の、SumVelCalcダイナミクスでもそうだが、 目に見える条件は一緒なのでCohesionとまとめるほうがデータ的には軽くなると思う。とりあえず、解かりやすさを優先して最終的に整理するようにしたい。
上記でいったように、SumPosisionとダイナミクスを分けている。条件は全く一緒で、ベロシティのaddしていく感じも大体一緒だ。


 ここで、平均ベロシティをaddしていく。vif関数でp-countを条件化して平均ベロシティを計算する。


boidsが進む方向に向きを設定。
次に、boidsの最高速度を設定する。これは結構使うと思うので、要チェックしておきたい。
MaxSpeedより、現在のスピードが速かったら、現在の方向にMaxSpeedを乗算する。それ以外は、現在のスピードという感じ。
シェイプダイナミクスの説明は、省く。


以上。

2013年10月14日月曜日

TPでboidsをセットアップしてみる。その3 Cohesion

今回は、個々が独りぼっちにならないように結合(Cohesion)の設定を行う。
これまでの、boidの個々はgoalに向かうよう設定されているため、はぐれる事はない。
だがgoalがないときやgoalを見失ったときどこに進めばよいか?
そんなときのために、自身の視界(目の悪さも含む即ち距離)に入るboids達の方向に進む設定を行いたいと思う。
さらに誰も視界に入らなかったときの設定は、次回にしたい。

まず、Cohesionの設定の有無を動画にしてみた↓
解かりやすくするため、ゴールの追従はなしにしている。


結果、いい感じだけど、メマトイのような感じになって気持ち悪くなった^^

今回は、ちょっと難しかった。
特に、どのように視界に入ったboidから合計平均した位置を取得するかに悩んだ。
ちっらっと、ナイスガイのデータをのぞき見た^^
ふむふむ、メモリを二つ使って再帰的にやっているね。


では、一旦それは置いといて、必要なデータをメモリに用意する。
用意と同時に、次サンプリング時に初期化されるようになっている。
次サンプリング時には、視界に入ったboidの合計位置は変化するから必ず必要である。p-countも0ね。


次に、ppassでall取得して、その個々を結ぶベクトルとベロシティの角度が○○度ならば、という条件で視界の入るboidの数とその合計位置を生成する。
メモリの使い方がナイス過ぎる。こういうの、なかなか考え付かないんだよな~。。勉強になる。
あと、角度計算するときのベクトルの向き重要!ここでいう、subtractionにinputするベクトル。


最後に、上記の合計平均位置へのベロシティを調整する。
ここの、ダイナミクスはこれまでやってきたように、boidのvelocityにSumPosへのvelocityをaddしていく。

 以上。