日本でハリウッドVFXを制作! 「経産省アイディアボックス」 結果:  
●まとめエントリはこちら ●FAQ ●お問い合わせは左のメールフォームから

2010年1月26日火曜日

sin関数

sin(Mayaオンラインヘルプ
(今回は上記ヘルプを元にまとめてあります)

sin(float number) :引数は、正弦(sin)を求める角度(ラジアン単位)
引数を一定の割合で増加もしくは減少させると、sin 関数は一定の割合で、-1 ~ 1 の範囲内を増減させた値を返します。 これはアトリビュート値をリズミカルに振動させる場合に便利です。
(日本語版ヘルプは若干、翻訳が違っているようなので、修正したものです。)

例:ヘビのような波打つ動き、ライトの明滅、胸などの上下動、膨張と縮小の繰り返し。パーティクルのOpacityやColorを循環的に変化させる。


----------------------------------------
ここで180度=πラジアンと覚えるのは、簡単なのですが、へそ曲がりなので、その理由がわからないと使う気になれません。
そこで、ラジアンについてもう調べてみることにしました。


ラジアンについては、ほんだ・しげちか氏のコラム「なぜ直角は90度?」にわかりやすく説明されていました。

半径1の円Oがあるとき、その円周上に二点A、 Bを弧ABの長さが半径とおなじ長さ1になるようにとるとします。 このとき、OA、OBをつないでできる角、∠AOBを新しい1度(1弧度あるは1ラジアンという)と約束します。 このとき全円周は2×半径×π(3.14…)=2πとなりますから、
(注:半径は「1」なので省略できる)
たとえば、半円周はπ、4分の1円周はπ/2、6分の1円周はπ/6ということになります。
(半径1の全円周(360度の)は2πの孤をもっている。1の弧を持つとき「1ラジアン」と読んだので、2πは「2πラジアン」と弧の長さで呼ぶことができる。)
すなわち、このルールに従うと、従来の角度360度を2π(6.282…)、180度をπ(3.14…)、90度をπ/2(1.57…)、60度をπ/6(0.523…)といったように、長さで角度を表わすことができることになります
(中略)
弧度法というこの新たな角度の登場によって、角度を表わす横軸のほうも縦軸同様に実数目盛りをもてることになったわけですから、各種の三角関数やそのグラフはいっきに実用性の高いものになったのです。
(引用元:ほんだ・しげちか氏 「なぜ直角は90度?」
(参考:Wikipedia「ラジアン」

ちなみに、ラジアンの概念は、ロジャー・コーツが1714年に考えたらしい。
詳しくは英語版Wikipediaに書かれているが、Yahoo知恵袋に、その翻訳がある。



しかし、高校の物理で習ったにもかかわらず、十分に理解してませんでした。
ずっと「角度=長さ」ということを鵜呑みにするのに抵抗がありましたが、少しわかってきました。
もう一度、自分の理解を深めるために確認してみます。

弧度法は、「半径と弧の長さがあれば角度がだせる。」ことが出発点で、
「弧と半径が1の時の角度を1とする」ことで新しい単位(ラジアン)を定義している。
そしてこれを「無次元量」とよぶらしい。

Yahoo知恵袋「無次元数は「数」か「量」か」をみると、以下のように書かれている。
「無次元量」=「次元 1 を持つ量」であり, そのような量を表す単位記号は (普通は表記しないけど)「数字の 1」となります。
(参考:yahoo知恵袋

ラジアンは、半径と弧の比率で角度を表す単位であり、
1ラジアン=半径1:弧1
半径1は省略できるので、
1ラジアン=弧1
よって「ラジアン=弧」と考えで良いのだろうか。(?)

また、「無次元量」の意味である「次元 1 を持つ量」から解釈すれば、
「ラジアン」という量をあらわす単位は「1ラジアン」のことを示している。
なので、「ラジアン」という時には、
1ラジアン=半径1:弧1の条件下にあることを暗示している(?)のだと思う

(参考:角度の単位と極座標系
(参考:「無次元量」には数学的な意味がある


これを別の言葉であらわすと、以下のようになる。
「弧度法の角度=弧の長さ」

以前は、この「角度」を通常の「度」表記の角度とどこかで混同していたので、混乱があったのだろう。


360度の円を考えたとき、
円の角度をラジアンで表記すると、2πr(弧/円周):1(半径)=ラジアン
2×π×1:1=2πなので、
円の角度「360度」は「2πラジアン」となる。
半円の角度「180度」はこの半分なので「πラジアン」である。
●180度の場合:1π=3.14159
●360度の場合:2π=3.14159×2

これを確認するために
rad_to_deg関数を使ってみます。
これは、ラジアン単位を度に変換してくれる関数です。

1π=3.14159の場合;
rad_to_deg(3.14159);
// Result: 179.999849 //

2π=3.14159×2
rad_to_deg(3.14159*2);
// Result: 359.999699 //

まあ多少の誤差はありますが、間違いないようです。



----------------------------------------
sin関数の記述についてもう一度見てみます。

sin(float number)
カッコ内の引数は、ラジアン単位の角度=弧の長さです。
そして「π」という表記は使えず、すべて数値もしくは数値の変数を使います。
「π」を使いたい場合は「3.14159」という数値を入れることになります。

さてヘルプを見ると、このカッコ内の引数の値によって返り値がプラスになる場合とマイナスになる場合があることがわかります。
●0~πラジアン(0~180度)=>  値:0~1(プラス値)
●π~2πラジアン(180~360度)=>値:-1~0(マイナス値)


<πラジアン>

sin(3.14159);

// Result: 2.65359e-006 //

πをもう少し詳しく書くと
3.141592653589793
となりますがこれで計算するとMayaの限界なのか返り値は、ゼロになります。

sin(3.141592653589793);
// Result: 0 //


桁数を変えていろいろ試してみましたが
小数点以下9桁までが限界のようです。それより小さな桁数はどんな数字を入れてもゼロになります。

sin(3.1415926535);
// Result: 0 //

sin(3.1415926536);  //最後の桁がπを上回る。
// Result: 0 //


桁数を一桁づつ変えて入力してみました。

sin(3.141592653);
// Result: 5.89793e-010 //

sin(3.14159265);

// Result: 3.58979e-009 //

sin(3.1415926);

// Result: 5.35898e-008 //

sin(3.141592);

// Result: 6.5359e-007 //


***********
<周波数について>
次に、0~3.14(π)の間で値が変化した時に返り値はどのように変化するのかということを見てみます。
πラジアンは180度、すなわち半円なので、真ん中の値1.570795(=3.14/2)を境として
●1.570795以下なら返り値が増加し、1に近づき、
●1.570795以上なら返り値が減少し、0に近づくはず。

sin(1.1);
// Result: 0.891207 //

sin(0.5);
// Result: 0.479426 //

sin(1);
// Result: 0.841471 //

sin(1.570795);
// Result: 1 //

sin(1.6);
// Result: 0.999574 //

sin(2);
// Result: 0.909297 //

sin(2.5);
// Result: 0.598472 //

sin(3);
// Result: 0.14112 //

sin(3.14159);
// Result: 2.65359e-006 //

ということで推測通りの変化が見られました。

これは、一定の増加率をもった数値が入力されるとき、
●増加率が急だと周波数が短くなる=波の繰り返しが頻繁になる。
●増加率が緩やかだと周波数が長くなる=波の繰り返しが少なくなる。

ようするに
sinのカッコ内に入れる引数の増加の具合によって、周波数が決まります。


ヘルプの例では「sin(time)」という使い方をしています。
time は、エクスプレッションのみで使用できるキーワードで、タイムラインのカレント タイム ポジション(秒数)を返します。
Ball.translateX = time;
Ball.translateY = sin(Ball.translateX);

この例ではX方向がtimeになっておりBallがXY平面上で、X方向へ6.283(2π)秒毎にS字のパターンを繰り返します。

ヘルプでは、6.283秒となっていますが、
●24fpsだと24×6.283=150.792フレーム
●30fpsだと30×6.283=188.49フレーム
がS字を繰り返す1周期となります。

●24fpsの場合1フレームあたり:0.0417秒
●30fpsの場合1フレームあたり:0.0333秒
という計算になります。

(参照:エントリ「時間に関する名称の混乱」)


timeはタイムラインにおけるカレント タイム ポジションを返してくるので、「0」フレームがスタート地点になります。
そのため、よくスタートフレームに設定される1フレーム目はすでに0.0417秒経過していることになります。

1フレーム目の値を計算してみます。
sin(0.0417);
// Result: 0.0416879 //

これを上記のエクスプレッションを入れたBallで確認するとtranslateYが確かに「0.042」となっていました。


***********
<π(180度)以上のとき>

2πラジアンのときは、以下のようになります。
sin(3.14159*2);
// Result: -5.30718e-006 //

では数値が大きくなったとき、たとえば3π、4πではどうなるのか?

3πラジアンのとき
sin(3.14159*3);
// Result: 7.96077e-006 //

4πラジアンのとき
sin(3.14159*4);
// Result: -1.06144e-005 //

このように実際は以下のようになっていることがわかります。
●奇数値×π=プラス値
●遇数値×π=マイナス値
※値が増加してもプラス値とマイナス値を交互に繰り返すだけ。

これが、最初にヘルプで書かれていたことです。

sinに継続的に増加もしくは減少する値が入力されるとき、出力は-1~1の間を継続的に増減します。
要するに一方的に変化していく値を繰り返しの値へと変換できるということです


----------------------------------------
sinによる、継続的な変化をコントロールするには、以下のように数値を乗算します。

amplitude(振幅):sin(number)×振幅数値
振幅とは、波形の最大値と最小値の差を 2 で割った値です。
振幅を小さくするには、 1 より小さい値(0.5 など)を掛けます。

frequency(周波数):sin(number×周波数値)
周波数とは、波形が 1 回循環するのに必要な時間です。
周波数を小さくするには、1 より小さい値(0.5 など)を掛けます。
正弦パターンの周波数を乗算(または除算)するため、「周波数乗数」と呼ばれます。

オフセット:sin(number)+オフセット数値
正の値を加算すると、波形が Y 軸に沿って上方向に移動します。
負の値を加算すると、波形が Y 軸に沿って下方向に移動します。


これらをまとめると以下のようになります。
Ball.translateY=(sin(Ball.translateX*2)*2)+2;
アトリビュート=(sin(周波数*周波数乗数)*振幅)+オフセット;

ただし、「周波数」に指定できるのは、継続的に増加もしくは減少していく値に限ります

例:
timeキーワード
frameキーワード
forループ
アニメートされたアトリビュート値
age(パーティクル)
Position(パーティクル)
  

0 件のコメント:

コメントを投稿