UnityのTransformのワールド空間とローカル空間について

UnityのゲームオブジェクトはインスペクタのTransformでPosition、Rotation、Scaleの値を見る事が出来ます。

Unityを使い始めの頃はPositionで言うと(0, 0, 0)を基準点とした数値だと思っていました。

しかしゲームオブジェクトは他のゲームオブジェクトの子要素として配置する事が出来、子要素のゲームオブジェクトは(0, 0, 0)を基準としたPositionにはなっていません。

子要素のゲームオブジェクトのPositionは親のゲームオブジェクトのPositionからの相対値が表示されています。

そこで今回は親のゲームオブジェクトと子のゲームオブジェクトを使って実験し、違いを確認してみたいと思います。

スポンサーリンク

親と子のTransform情報の確認

ヒエラルキー上で右クリックし3D Object→Cubeを作成し、名前をParentとします。

その子要素にCubeを作成し名前をChildとします。

親と子のゲームオブジェクトを作成

ChildをParentの子要素にドラッグ&ドロップし移動させます。

親と子のインスペクタ

親と子のゲームオブジェクトのインスペクタでPosition、Rotation、Scaleを↑のようにまったく同じ数値を設定します。

親と子のゲームオブジェクトの絵

すると同じ数値を設定したにもかかわらず↑のように位置や角度、大きさが変わりました。

右上が子要素であるChildゲームオブジェクトですが、ChildのTransform情報はParentからの相対値になっている事がなんとなくわかると思います。

ワールド空間とローカル空間

子のゲームオブジェクトのTransform情報は親のゲームオブジェクトからの相対値という事が確認出来ました。

親を持たないゲームオブジェクト(親)のPositionやRotation、Scaleはワールド空間になります。

親を持つ子のゲームオブジェクトは親からの相対値で表示されるのでローカル空間になります。

ワールド空間とローカル空間の表示の仕方

Unityで位置や角度、サイズを扱う時にもワールド空間でのデータ、ローカル空間でのデータと取得の仕方を変更する事が出来ます。

↑のようにゲームオブジェクトのワールド空間での情報、ローカル空間での情報を取得出来ます。

ワールド、ローカル値を両方表示してみる

さきほどの親と子のゲームオブジェクトの親にスクリプトを取り付けどのようなデータが出力されるか確認してみます。

スクリプトの名前はWorldLocalという名前にします。

↑のようにpublicで親のゲームオブジェクトと子のゲームオブジェクトをインスペクタで設定出来るようにし、それぞれのワールド、ローカルでの値を表示しています。

ワールド空間とローカル空間のデータを表示

親のゲームオブジェクトは自身の親がないのでワールドでもローカルでも表示は同じです。

子のゲームオブジェクトはワールドの場合はインスペクタで表示されているデータではなくワールド値が表示されています。

ローカルの場合はインスペクタで表示されているデータと同じですね。

ワールド空間とローカル空間の相互変換

ワールド空間とローカル空間の表示の仕方がわかりました。

次に、ワールド空間の値とローカル空間の値を相互変換出来るようにしてみましょう。

例えば子のゲームオブジェクトが向いている方向に移動させたいと思います。

親のゲームオブジェクトであればtransform.forwardが前方を指しますのでこのプロパティを使えば済みます。

実は子のゲームオブジェクトでもtransform.forwardを使用すればワールド空間での方向が取得出来るので問題はありませんが・・・、

場合によっては子のゲームオブジェクトのローカルの前方を取得したい事があります。

例えが浮かばない・・・・(^_^;)

そんな時にワールドとローカルの相互変換が出来ると便利です。

引数として渡すのは全てVector3の値で戻り値も全てVector3の値が返ってきます。

これらの処理は実に混乱しやすい処理になります。(^_^;)

サンプルを作成し実行してみます。

↑のようなサンプルスクリプトを作成し親と子両方のゲームオブジェクトに設定します。

child.forwardで子の向いているワールドの方向、child.positionでワールド位置を取得出来ます。

それらを設定したスクリプトのゲームオブジェクトから見た変換を行います。

サンプルを実行する前に親と子のデータをわかりやすいものに変えます。

親のPositionは(0, 0, 0)、Rotationは(0, 0, 0)、Scaleは(1, 1, 1)に設定します。
子のPositionは(1, 1, 1)、Rotationは(0, 45, 0)、Scaleは(1, 1, 1)に設定します。

親と子に設定したスクリプトのどちらかを無効化し実行します。

親と子両方にスクリプトを設定

↑が実行結果です。

スクリプトを設定した位置で実行結果が変わっていますね、かなり混乱します・・・・。

スクリプトを設定したゲームオブジェクトから見たワールドの位置やローカルの位置になるからです。

InverseTransformDirectionでは親にスクリプトを設定した場合(0.7, 0, 0.7)、子に設定した場合(0, 0, 1)が出力されています。

これは親から見た子の方向をローカルに変更すると子をローカル表示した時にZ軸がそちらの方向を向いているからです。

子に設定した場合は子の向いている方向を子から見ているのでZ軸と子の向いている方向が同じになり(0, 0, 1)になっています。

同じ理由でInverseTransformPointも親から見た子のローカル位置は(1, 1, 1)、子から見た子のローカル位置は(0, 0, 0)となります。

TransformPointも同じで親の場合は(1, 1, 1)、子の場合は(2.4, 2.0, 1.0)となります。

子をドラッグして親子関係を解消すると子のPositionが(2.4, 2.0, 1.0)となるのでわかりやすいと思います。

最後のTransformDirectionの場合は子の値がX軸向きになっています。

TransformDirectionはローカルの方向をワールドに変換するものなので指定している引数がワールドの方向を渡している為おかしな結果となっていると思います。

これらの解説を見てわかるとおり非常にこれらの処理は解り辛いですね・・・・(^_^;)

その為、必要に迫られない限りはこれらの処理は使わない方が混乱の元にならないと思います。

わたくしは完全に混乱しました・・・・・( ノД`)シクシク…

終わりに

ワールド空間、ローカル空間の値を得るには専用のプロパティを使えば簡単に取得する事が出来ます。

ただし、それらを相互変換しようと思うと非常に解り辛い処理が絡んできます・・・・。

大体のローカル値の取得はtransform.localPositionやtransform.localRotation、transform.localScaleを使えば事足ります。

相互変換が必要になるのはtransform.forward等の方向のプロパティを使う時だと思うので、それ以外は相互変換を使わない方がいいかもしれません。

単純に混乱の元です・・・・(-_-)

スポンサーリンク

記事をシェアして頂ける方はこちら

フォローして頂くとやる気が出ます