【Unity道場スペシャル 2017博多】クォータニオン完全マスター

Post on 21-Jan-2018

9.190 views 1 download

Transcript of 【Unity道場スペシャル 2017博多】クォータニオン完全マスター

クォータニオン完全マスター

ユニティ・テクノロジーズ・ジャパン合同会社

安原祐二

Unity スクリプトリファレンスより抜粋

座標変換

CG

オイラー角

複素数

クォータニオン本セッションの旅程

座標変換

CGのきほん

たくさんの点を動かす!

© Unity Technologies Japan/UCL

P(1, 2)

x

y

二次元座標

P’(-2, 1)

x

y

P(1, 2)

P(1, 2) P’(-2, 1)

ある変換で点を移動

変換

ある変換=なんらかのルール

同じ変換でたくさんの点を移動

Q(2, 0) Q’(0, 2)変換

P(1, 2) P’(-2, 1)変換

R(1, 1) R’(-1, 1)変換

こういう式にしてみよう

x’ = ax + by

y’ = cx + dy

P’(x’, y’) = [変換]P(x, y)

x’ = ax + by

y’ = cx + dy

x’ = 1x + 0y

y’ = 0x + 1y

a=1 b=0 c=0 d=1 なら

x’ = x

y’ = y変化しない変換

色々できそう!

色々できそう!x’ = ax + by

y’ = cx + dy

x’ = 1x + 0y

y’ = 0x + 1y

a=1 b=0 c=0 d=1 なら

x’ = x

y’ = y変化しない変換

x’ = 0x + 1y

y’ = 1x + 0y

a=0 b=1 c=1 d=0 なら

x’ = y

y’ = xxy入れ替え変換

abcdをまとめてしまおうx’ = ax + by

y’ = cx + dy

a b

c d( )

これを行列と呼ぶ!

変換を行列Mとして

P(1, 2) P’(-2, 1)変換

P’=MP

P’(x’, y’) = [変換]P(x, y)

a b

c d( )P’= P

変換を行列Mとして

P(1, 2) P’(-2, 1)変換

P’=MP

P’(x’, y’) = [変換]P(x, y)

(

行列に点ベクトルを掛ける

a b

c d( )=

a b

c d( ) 1

2)=)(-2

1

x’ = ax + by

y’ = cx + dy

-2 = a1 + b2

1 = c1 + d2

例えば

)(x’

y’ (x

y)

-2 = a1 + b2

1 = c1 + d2

行列に点ベクトルを掛ける

-2 = a1 + b2

1 = c1 + d2

1

2( )a b

c d( ) 1=)(-2

1 2

1

2

+

+

三次元では3x3行列になるx’ = ax + by + cz

y’ = dx + ey + fz

a b c

d e f

g h i( )

z’ = gx + hy + iz

概念は同じなので以降も二次元で続けます

いろいろな行列

2 0

0 2( ) 2倍に拡大スケーリング行列

cosθ -sinθ

sinθ cosθ( ) θ回転する回転行列

デモ

x

y

あれ?移動は?

行列の値をどう工夫しても移動はできない!

x’ = ax + by

y’ = cx + dy

x’ = ax + by + s

y’ = cx + dy + t

移動するために式を変更

これで(s,t)で移動できる

追加!

移動を実現するために行列を拡張

a b s

c d t( )

a b

c d( )

a b s

c d t

0 0 1( )

何かと都合がいいので3x3 にする

x’ = ax + by + s

y’ = cx + dy + t

行と列の数が同じ正方行列と呼ぶ

デモ

三次元でも同様にして移動を実現

つまり三次元では4x4行列を使う

a b c s

d e f t

g h i u

0 0 0 1)(

x’

y’

z’

1( ) =

x

y

z

1( )

a b s

c d t

0 0 1( )

二次元用3x3行列の各部分の役割

回転 移動

a b c s

d e f t

g h i u

0 0 0 1)(

回転 移動

三次元用4x4行列の各部分の役割

回転 移動

三次元用4x4行列の各部分の役割

transform.rotation transform.position

Quaternionクォータニオンで作る

Vector3ベクトル

で作る

a b c s

d e f t

g h i u

0 0 0 1)(

異なる変換をいくつも重ねる

これを点ごとに計算するのはたいへん…

P’=(○(○(○(○P))))

いくつも変換する場合は事前に計算しておける

点ごとにMを掛ければ済む

P’=MP

P’=○○○○P

P’=(○(○(○(○P))))

M=○○○○を事前に計算して…

座標変換

CG

オイラー角

複素数

クォータニオン

CGに応用する行列

3つの変換行列

• モデル行列

• ビュー行列

• プロジェクション行列

すべての変換前モデリングした物体の座標

データにはこの座標が格納されている

この変換がモデル行列

Transformで移動・回転

シーンにはカメラがある

カメラ

Transformで移動・回転

z

カメラが原点・ゼロ回転になるように変換

この変換がビュー行列

空間全体をモニタの位置に合わせる!

z

画角や near, far を処理w に z を格納など…

この変換がプロジェクション行列

Unity組み込みシェーダUnityShaderVariables.cginc より抜粋

M:モデル V:ビュー P:プロジェクション

モニタに映すための透視変換

この変換は行列ではなく奥行きで割る

遠くのものを小さく!

透視変換のようす

座標変換

CG

オイラー角

複素数

クォータニオン

オイラー角方式

二次元の回転はシンプル

回転軸はひとつcosθ -sinθ

sinθ cosθ( ) θ回転の回転行列

三次元では3軸の回転量をそれぞれ記述

あらゆる姿勢を表現可能これがオイラー角方式

x

y

z

直感的!

Unity の Inspector のRotation は…

表示に関してはオイラー角方式

P’=YXZP

X X軸まわりの回転行列

Y Y軸まわりの回転行列

Z Z軸まわりの回転行列

オイラー角方式の回転には順番がある

UnityはZYXの順番

プログラム例:オイラー角で作った回転を代入

transform.rotation = Quaternion.Euler(x, y, z);

変換を3回重ねている

座標変換

CG

オイラー角

複素数

クォータニオン

複素数と複素平面

クォータニオンは複素数の拡張

問題

は虚数単位

虚数の定義

虚数単位

複素数

:実部:虚部

2

1

普通の平面

P(1, 2)

x

y

実軸

虚軸

1+2i

1

2

複素平面

実軸

虚軸

半径1の円周上の点を考える

単位円と呼ぶ

実軸

虚軸

1+0i つまり 1

実軸

虚軸

-1+0i つまり -1

1

実軸

虚軸0+i つまり i

-1 1

実軸

虚軸

0-i つまり -i

-1 1

i

実軸

虚軸

-1 1

i

-i

実軸

虚軸

-1 1

i

-i

45°

実軸

虚軸

cos45°-1 1

i

-i

45°

sin45°

実軸

虚軸

cos45°+isin45°

-1 1

i

-i

45°

cos45°

sin45°

0.7+0.7iぐらい

実軸

虚軸

cosθ+isinθ

-1 1

i

-i

θ

cosθ

sinθ

重大な事実

単位円上の点は回転だった

実軸

虚軸

-1 1

i

-i

ゼロ回転

実軸

虚軸

-1 1

i

-i

180°回転

実軸

虚軸90°回転

-1 1

i

-i

実軸

虚軸

270°回転

-1 1

i

-i

実軸

虚軸

-90°回転

-1 1

i

-i270°と-90°は同じ意味

もしくは

もっと重大な事実

点と点を掛けると回転する

虚数の性質

実軸

虚軸i

-1 1

i

-i

i は90°回転

実軸

虚軸i

-1 1

i

-i

i は i をさらに90°回転

2

つまりi = -12

実軸

虚軸

-1 1

i

-i

-1

-1をさらに180°回転

つまり(-1) = 12

実軸

虚軸

0.7+0.7i

-1 1

i

-i

実軸

虚軸0.98i

-1 1

i

-i

0.7+0.7i

θ実軸

虚軸

cosθ+isinθ

-1 1

i

-i

(cosθ+isinθ)2回転角を足す

と複素数を掛ける

は同じ意味!

cos2θ+isin2θ

=

ところで…

この方程式を解いてみよう

実軸

虚軸

-1 1

i

-i

実軸

虚軸

-1 1

i

-iから正三角形!

120°

座標変換

CG

オイラー角

複素数

クォータニオン

クォータニオン

考案者はハミルトン(William Rowan Hamilton 1805-1865)

「複素平面の三次元版は作れないものか…」

虚軸を3つにすればうまくいく!

iが虚数単位

クォータニオン複素数

i, j, kが虚数単位

i =-12 i =-12 j =-12 k =-12

ij=k jk=i ki=jji=-k kj=-i ik=-j

驚愕のアイデア!

クォータニオンは複素数の三次元版

a+ib a+ib+jc+kd

クォータニオン複素数

複素数の要素はふたつクォータニオンの要素は4つ

クォータニオン要素をx, y, z, w とする

ix+jy+kz+w

(x, y, z, w)

実部虚部

複素平面の回転軸は固定だった

立体の場合

(x, y, z)

ix+jy+kz+w

(x, y, z, w)

実部虚部

回転軸が虚部のベクトル

複素数の回転とクォータニオンの回転

cosθ+isinθ

複素数

cosー+nsinー2 2

θ θ

n=inx+jny+knz

n(nx, ny, nz)は回転軸のベクトル

クォータニオン

重大な事実

あらゆる回転はひとつの軸回転で表現できる

そしてクォータニオンは軸回転を表現する

クォータニオンなら一発で決まる!

あらゆる回転はひとつの軸回転で表現できる

クォータニオンのテクニック

便利なテクニックSlerp (Spherical Linear Interpolation):球面線形補間

transform.rotation =

Quaternion.Slerp(transform.rotation,

target_rotation,

0.1f);

現在の値

目標の値

適当な率

凝ったテクニックバネトルク

目標との差分に比例したトルクをかける

基本戦略:目標への差分を求めて、トルクに変換する

差分クォータニオンの求めかた

差分=目標の値×現在の値-1

実演バネトルク実装例

4要素の符号を反転しても同じ回転になる

(x, y, z, w)

(-x, -y, -z, -w)

実は回転の方向が異なる

(x, y, z, w)

(-x, -y, -z, -w)

バネトルクを完成させるテクニック

wが負のときに反転すると短い方の回転になる

(x, y, z, w)

(-x, -y, -z, -w)

修正済みコード

追加

var rot = Quaternion.LookRotation(diff);

第二引数に Vector.up が省略されている

var up = transform.TransformVector(Vector3.up);

var rot = Quaternion.LookRotation(diff, up);

自分の姿勢から upベクトルを作る

水平を維持しないテクニック

修正済みコードその2

追加

デモ

このあと学習を続けるなら…

• トルクや物理を詳しく知りたい→Unity道場札幌講演をぜひ!https://www.youtube.com/watch?v=FqjM9oujyNE&feature=youtu.be

• クォータニオンの応用例を知りたい→Unite2017Tokyoをぜひ!https://www.youtube.com/watch?v=6EtTI5xC524 27分あたりから

• なんで と、 になるのか気になる→ ブログ「クォータニオンで回転を表現する定義にθ/2が使用される理由」をぜひ!http://qiita.com/yuji_yasuhara/items/a5b7c489e1d521adbd72

θ

2cosー+nsinー

2

θ

2

θー

参考:Inverse自前実装

虚部を反転するだけで逆クォータニオン

実軸

虚軸

-1 1

i

-i

マメ知識

逆変換は虚部の符号を反転

共役複素数と呼ぶ

おしまい