[Unity初心者向け]Transformの値を数学的に計算出来るようになろう

Unityのチュートリアルで有名な「Roll a ball」

「Roll a ball」を試したことが無くても結構ですが、一言でいうと、
そのチュートリアルでは以下のような「ボールが転がるための舞台」を作ることになります。

※各数値は左から「x,y,z」

さて、ここで質問です。

中央のPlaneオブジェクト(青)のScaleは「2 1 2」なのに、どうして周囲のPlaneオブジェクト(壁)のScaleは「0.5 1 20.5」のような半端な数値になるのでしょうか?

このTransformの値は、目視で何となくそれっぽい値ではなく、
数学的に説明できるように「必然的に」決まっています。

「目視でなんとなく」の問題点

案件によっては、それで何とかなることもあるでしょう。
しかしそれでは必ず災いが起こりますし、Unity開発者としても成長できません。

あなたは今「ピタゴラスイッチのようなゲーム」を作っているとしましょう。
その「なんとなくの0.001の誤差」は必ず重力計算で歪みを起こし、予期せぬ動作(バグ)を生むでしょう。

または「建築パースVR」を作っているとしても同様です。
実際の建築設計において「曖昧」は許されませんよね?

VR制作でも同様です。そんな誤差のある実装では、いびつな作品となってしまいます。

「0.001」でも違ってたらダメなんだ!と自信を持って説明できる開発者になるために、疑問を持ったらなぜそうなるのか理解しましょう。

目視でなんとなく調整するだけの開発者は、その目視調整にこれからも無駄に膨大な時間を費やすでしょう。
「そしてなぜうまくいかないのか?」をロジック的に思考しようとせずに、
目とクリックと時間だけを費やして、またバグを生むでしょう。

「なぜそうなるのか?を理論的に理解している開発者」は、数秒間の計算をした後に数値を決定するだけで、
デザインの変更がない限り、もうその工程に戻ってくることは無いでしょう。

「Position/Rotation/Scale」のおさらい

以下の表でそれぞれの意味を簡単におさらいしておきましょう。

Position 移動 x y zに原点からの距離を指定します
Rotation 回転 x y zに回転角 (単位:度)を指定します
Scale 拡大/縮小 x y zに倍率を指定します。1 の場合は、元の大きさ (オブジェクトがインポートされた大きさ)になります

それぞれX,Y,Zで数値を指定しますが、ワールド座標 or ローカル座標どちらの指定かによって結果が変わります。

ワールド座標とは、3D空間上の原点(中心)からの座標、つまり絶対指標です。
ローカル座標とは、親オブジェクトを原点として、それに対しての相対指標です。

プリミティブオブジェクト

プリミティブオブジェクトとは、普段みなさんも使っている
「Unityに最初から入っている基本的な3Dオブジェクト」です。

オブジェクトの型

プリミティブオブジェクトには「Cube, Sphere, Capsule, Cylinder, Plane, Quad」などの型があります。

オブジェクトの初期値

冒頭で使った画像を再掲します。

ここで使っているPlaneオブジェクトとCubeオブジェクトの初期値をご存知でしょうか?
こちらの公式サイトによると、
以下の通りです。

Plane(青の床) これは平らな正方形であり、ローカル座標空間において XZ 平面で 10 単位の長さです
Cube(壁) キューブは 1 辺が 1 単位の長さである単純な立方体であり、六つの面で画像が繰り返されてテクスチャ化されます。
….
キューブの 1 辺が 1 単位の長さであるため、シーンにインポートされたメッシュの寸法を確かめるには大きさを比較することができます。

もう分かってきましたか?それではいよいよ答え合わせに移ります。

質問の答え合わせ

ここで、冒頭の質問を再掲します。

中央のPlaneオブジェクト(青)のScaleは「2 1 2」なのに、どうして周囲のPlaneオブジェクト(壁)のScaleは「0.5 1 20.5」のような半端な数値になるのでしょうか?

解答

Plane型(青い床)の初期値はXZ平面で10単位でした。
これを「Scale: 2 1 2」、つまりXZを2倍にしているので、実際の長さはXZ平面で「20×20」の正方形となります。

つぎにCubeです。
Cubeの初期値は1辺が1単位の立方体でした。つまり、XZ平面では「1×1」の正方形となります。

画像は横がX方向、縦がZ方向ですので、
Cubeを置いた初期状態では以下のようになります。
中心にある白いCubeは「1×1」の正方形です。

さて、ではこの中心のCubeで上辺の壁Aを作ってみましょう。

青の床は「20×20」の正方形でしたが、
現在Cubeはその中心に居ますので、上辺までの距離はその半分の「Z方向に-10」となります。

すると、以下の図のようになります。

Cubeの中心が青い床の上辺にちょうど(串刺しのように)重なるように乗りました。
Cube自身も「1×1」の面積をもっているので、中心からの半分である「0.5」が外側にはみ出している状態です。

この状態で冒頭のサンプル通りにScaleをZ=0.5に設定するとどうなるでしょう?
すると、以下のようにZ軸=縦幅が半分になります。

つまり、「0.5の半分 = 0.25」だけ、はみ出ている計算になります。
「0.25」..このあとすぐに登場するのでこの数字覚えておいてください。
STEP2

そして、次がいよいよ最後の計算になります。

上記のCubeは「横幅=1」なので、壁Aを作るには横幅がまだ足りませんね?
現在、青の床は「20×20」なので、その一辺である横幅は「20」です。
一方、Cubeの横幅は「1」なので、単純にScale X=20 (つまり20倍)すれば良さそうです。

しかしここで、「0.25のはみ出し」を思い出してください。

4つの壁がうまくかみ合うには、「0.25のはみ出し」がそれぞれうまくかみ合う必要があります。
つまり横(=X)方向にも、わざと0.25のはみ出しを作ってあげれば、4辺は、はみ出し同士でうまくかみ合うことになります。

・・ということで、以下の図のように
Scale X=20ではなく、Scale X=20.5を指定することになります。
原点(=中心)から見て左右にそれぞれ拡大されるので、
「20.5の半分 = 10.25 = 0.25がはみ出す」計算になりますね。

STEP3

以上の経緯を踏まえて、
壁AのTransformの値は冒頭の画像と同じく以下の画像の設定通りとなりました。

残りの3つの壁は、鏡の反射鏡のように考えれば同じ理屈で解決できます。

これで数学的にはようやく解決!

ですが・・この記事を書きたかった本当の理由は・・

この記事で本当に伝えたかったこと

数学自体は簡単だったはず!

上記は決して数学的には難しい話ではなかったはずです。

今回が難しいと感じた方は、単純にUnity or XYZ座標の概念に慣れていないだけなはずです。

なので、数学を言い訳に逃げないでください。そして、
Transformの値を「必然的絶対値(=計算された値)」として決定することの大事さから逃げないでください

自己解決力とググり力!

これで読者の方は、
「数学的に・必然的にTransformの値を操作出来る開発者」に近づけたはずです。
ですが、これで終わりではありません。

伸びるタイプの開発者

伸びる開発者は、「今回の事象を解決出来たこと」だけで満足せず、
「今回のような事象がまた起きても自分で解決出来る術を身につけたこと」に満足するでしょう。
この記事を通して貴方はそうなったはずです。

今後あなたが、また新しいチュートリアルを進めていくうえで、
今回は取り扱わなかった、「円柱型」「カプセル型」のプリミティブオブジェクトが登場することもあるでしょう。
それでも貴方は、「そのTransform設定値がなぜ、その値になるか?」の正解に辿り着けるでしょうか?

この記事を読み返せば正解にたどり着けるはずです!

是非、そういう疑念を持ってチュートリアルを進めて見てください。
そして、「そのTransform設定値がなぜ、その値になるか?」を他人に説明出来るほどの理解が出来るようになりましょう。

やる気

大事なのは、以下のやる気・意気込みだと思います。

「本当に理解しながらチュートリアルを進める事、そして 疑問を持つ事」
「疑問を解消しようとする事」
「疑問についてGoogle先生と格闘すること(わざと英語でググるなど、”ググる力”も大事)」
「数学・英語から逃げないこと(英語が読めない人は翻訳しましょう。それは単純に一手間加えるだけです)」
「それでも分からなければコミュニティや質問掲示板など、手助けになる場くらいはググって見つける => 質問する(たとえ外人相手でも)」

最後に

貴方は今後どれほどの膨大な時間、Unityを触るでしょう?
今回のことはTransformに限らず、そしてUnityに限らず、
物事のラーニングにおいて根本的に大事だと思う事について語りました。

「0.001」でも違ってたらダメなんだ!と自信を持って説明できる開発者になるために、疑問を持ったらなぜそうなるのか理解しましょう。

目視でなんとなく調整するだけの開発者は、その目視調整にこれからも無駄に膨大な時間を費やすでしょう。
「そしてなぜうまくいかないのか?」をロジック的に思考しようとせずに、
目とクリックと時間だけを費やして、またバグを生むでしょう。

「なぜそうなるのか?を理論的に理解している開発者」は、数秒間の計算をした後に数値を決定するだけで、
デザインの変更がない限り、もうその工程に戻ってくることは無いでしょう。

——–
あなたは、どちらになりたいでしょうか?