ぬうぱんの備忘録

技術系のメモとかいろいろ

作った曲一覧はこちら

今年DTMしてて大事だなぁって思ったことあれこれ

前置き

TUT Advent Calender 2016 の15日目の記事です。

先週末くらいから風邪をひいてしまって予定が狂ってヤバいです。
JSHRN5の締め切りも今日だったのが良くなかった。
あっ、風邪はやっと落ち着いてきた感じです(完治したとは言っていない)

すんごい大事なことを書き忘れてたんですけど、OB です…。

この記事は

今年、DTMしてて大事だなぁって思ったことをまとめる記事です。
技術系のネタにしようと思ってたんだけど、今年はひたすらDTMに自由時間を取られまくった1年だったからDTMネタにしようと思います。

続きを読む

C90ですよ!(DREAMING WITH YOU)


f:id:NU_Pan:20160811160614j:plain

3日目 西-q42 だぞ!

ラーメン部のアルバムにDREAMING WITH YOUという曲で参加しました。
な、なんと! BPM128のエレクトロポップと、それを原曲とするセルフリミックスの同時リリースだぁ! うひょー!

曲のほうは、可愛いメイドさんがかわいい感じの曲です。NIGHTLYなのは突貫作業で徹夜で編曲を仕上げたからです。正直すまんかったと思ってる。歌詞が難産だったんや…。
ボーカルはミクさんにお願いしました。えへへ。

続きを読む

右手系とか左手系とか回転とかの話

まぎらわしいよね

 3次元の回転行列とクォータニオンオイラー角の3つの話でもすでにめんどくさいのにそれに右手系と左手系の話が入ってくるともう脳細胞の活動が止まって気持ちええんじゃ。ということで、ここらへんのよく知られている事実をまとめてみようと思います。

右手系と左手系

「右手系 左手系」で画像検索をかけてください。それです。

レミングのあの手つきをして

  • X --> Y --> Z
  • 親指 --> 人差し指 --> 中指

を当てはめた時の向きがそれです。

また、回転方向も違います。
各軸の方向(フレミングの指が向いてる方向です)に、右手系なら右ねじの、左手系なら左ねじの親指を添わせた時の、残りの指の向きが回転方向です。

右手系と左手系の違いは、X軸とY軸が同じ向きになるように合わせた時

  • Z 軸が逆向き
  • X 軸と Y 軸の回転が逆

となります。

ちなみに、右手系を使いたいけどZ軸は奥を向いてほしいということのためだけに「 X 軸が上向きで Y 軸が右向きの右手系」という流派も存在します。
曰く、右手系だから一般的な数学の知識がそのまま適用出来て便利だとか。

行ベクトル系と列ベクトル系

右手系左手系とは全く無関係な別の話として、行列・ベクトルの式を書く時に、

列ベクトルに左から行列をかける、
{\displaystyle
{\boldsymbol y} = {\boldsymbol B}{\boldsymbol A}{\boldsymbol x},
}
という流派と、
行ベクトルに右から行列をかける、
{\displaystyle
{\boldsymbol y}^\top = {\boldsymbol x}^\top{\boldsymbol A}^\top{\boldsymbol B}^\top,
}
という流派がある。
(例えば、{\boldsymbol x}{\boldsymbol y} は2次元の列ベクトルで、{\boldsymbol A}{\boldsymbol B}{2{\times}2} の行列だとして考えてみてほしい。)

上下どちらも {\boldsymbol x}{\boldsymbol A} をかけて {\boldsymbol B} をかけるという意味で、計算結果は同じ。

右手 or 左手 vs. 行 or 列

この2つの選択肢はお互いに独立した物だが…

  • 3DCG系 : 左手系かつ行ベクトル
  • CV系 : 右手系かつ列ベクトル

という住み分け(?)がされている。
CV系は数学そのまんまなので疑問を挟む余地は無いが、3DCG の方は…さて? これと言って有力な理由も無いので単に「歴史的経緯でこうなっている」と思っておけばいいんじゃないでしょうか。

ちなみに、これ以外の組み合わせは聞いたこと無いので辞めたほうがいいと思います。

で、本題

右手列ベクトル系と左手行ベクトル系であれこれ違いがあるので、片方の系が前提になっている知識をもう一方に持ち込む時に割りと厄介です。
ていうことでそこら辺をまとめていきます。

列ベクトル系と行ベクトル系の相互変換

並び順を逆にして個別に転置すればOK。
上の方に書いた式そのまんまです。

回転行列の逆行列は転置行列

回転行列は転置で逆行列が求まります。つまり、{\boldsymbol R^{-1}}={\boldsymbol R^\top}です。正確には「逆行列=転置行列」を満たす行列を直交行列と言って、回転行列はこの条件をみたします。
また、直交行列は

  • <列ベクトル系>各列のベクトルは互いに直交
  • <行ベクトル系>各行のベクトルは互いに直交

という性質を持ちます。

回転行列は基底ベクトルのあつまり

  • <列ベクトル系> 回転行列の各列のベクトルは回転後の座標系の基底ベクトル
  • <行ベクトル系> 回転行列の各行のベクトルは回転後の座標系の基底ベクトル

「ほげほげ座標系の基底ベクトル」というのはほげほげ座標系の各軸に沿う方向ベクトルのことです。
3次元の回転行列だと、回転後のXYZ軸に沿う3本の単位ベクトルのことで、この3つのベクトルは互いに直交します。
そして、互いに直交する3つの単位ベクトルの場合、基本ベクトルと呼びます。

つまり、何らかの姿勢が基本ベクトルで与えられたとき、それは姿勢を表す回転行列を与えられたのと同義。その逆も同様。

回転行列の逆行列は逆回転

当たり前のことですが…回転行列の逆行列を求めたら、それは元の行列の逆回転の事です。

点の回転と基底ベクトルの回転

これは右手左手の話では無いですが、座標系を {\boldsymbol R} 回転させるのと、ベクトルを {\boldsymbol R^{-1}} 回転させるのは同じことです。

位置ベクトルの右手系<->左手系相互変換

Z要素の符号を反転すればよい。

回転行列の右手系<->左手系相互変換

  • <列ベクトル系> 回転行列の3列目の符号を反転する
  • <行ベクトル系> 回転行列の3行目の符号を反転する

「Z軸基本ベクトルを反転する」と覚えればよいでしょう。
当然ですが、この変換をかけても変わるのは右手系と左手系だけです。列ベクトル系と行ベクトル系の相互変換はこれとは別に必要です。

オイラー角の逆変換

これも右手左手の話ではないですが…。

X軸でx度->Y軸でy度->Z軸でz度の順番で回転させたときの逆変換は
Z軸で-z度->Y軸で-y度->X軸で-x度の順番。
回転をかける順番を逆にして、回転角度の符号を反転させる必要がある。
このとき、回転角度が(-180, +180)の範囲でなければならないことに注意。

std::numeric_limits<float>::min()について重大な思い違いをしていた話

何があった

線形探索で最大値を探すコードを書いていた。
簡単化するとこんな感じ。

using namespace std;

float FindMax(const vector<float>& source)
{
	float max = numeric_limits<float>::min();	// floatの最小値で初期化してるつもり
	for(const auto& value : source)
	{
		if( max < value )
		{
			max = value; //maxは最小値で初期化してるから必ず一度はここを通るはず
		}	
	}
	return max;
}

でも動かしてみるとなんだか挙動がおかしい。
なんか負数しかないデータ列が来た時に一度もmaxが更新されない。
おかしいと思ってデバッガで初期値を見てみると「1.17549e-38」になってる。
よく見たら正の数なんですがそれは。

どういうことなのか

numeric_limit::min() は確かに「最小値」を返すんです。
でも浮動小数点に限っては「最小値」っていうのは「表現可能な中で絶対値的に最も小さい値」みたいなものを指してるんですね。
正確には「正の正規化数のうち最小のもの」みたいです。
なのでマイナスの絶対値がすごくでっかい値が帰ってくるわけではないんですね。

じゃあどうするのか

numeric_limits::lowest() を使いましょう。
こっちはちゃんと最小値を返してくれます。
ちなみに、qnan みたいな無効値で初期化すると max < value が必ず false と評価されるのでうまく行きません。