Unity3D之空間轉換學習筆記(一):場景物體變換

該系列筆記基于Unity3D 5.x的版本學習帐要,部分API使用和4.x不一致怠李。

目前在Unity3D中殿衰,除了新的UGUI部分控件外朱庆,所有的物體(GameObject)都必帶有Transform組件,而Transform組件主要是控制物體在3D空間中的位置闷祥、旋轉以及縮放娱颊。

學習和掌握物體的變換是Unity3D開發(fā)者必備的基礎知識。

基礎變換

最基礎的變換就是通過腳本直接對物體的位置旋轉縮放等進行變換蜀踏。

勻速移動

我們下面實現一個勻速移動物體的效果维蒙,我們在場景中添加一個Cube物體,把下面的腳本綁定到攝像機上并把Cube拖拽賦予transfrom屬性果覆。

using UnityEngine;

using System.Collections;

public class Demo01Script : MonoBehaviour

{

????public Transform myTransform;

????void Start()

????{

????}

????void Update()

????{

????????myTransform.position = new Vector3(myTransform.position.x, myTransform.position.y + 1.0f * Time.deltaTime, myTransform.position.z);

????}

}


運行游戲颅痊,我們會發(fā)現Cube會勻速上升。我們回到編輯場景局待,對Cube進行任意的旋轉后運行游戲該Cube仍然是向上上升斑响,這是因為位置和旋轉是相互獨立的,我們直接操作位置的話程序是不會理會旋轉屬性的钳榨,更換為localPosition效果也是一致的舰罚。

根據物體方向勻速移動

我們發(fā)現如果使用上面的方法來按照物體面向的方向移動物體是不容易的,我們需要根據物體的朝向計算出x薛耻、y营罢、z這3個分量的數值再應用回物體中才行,這需要扎實的3維運算功底饼齿,不過好在Unity已經給我們提供了大量的屬性及方法饲漾,方便我們直接調用來達到我們需要的效果娇澎。

本地坐標系變量

transform.right:物體本地坐標的x軸正方向朝向坤按,1米的單位。

transform.up:物體本地坐標的y軸正方向朝向前联,1米的單位证鸥。

transform.forward:物體本地坐標的z軸正方向朝向僚楞,1米的單位。

由于我們知道了物體本地坐標的信息枉层,所以可以方便的通過這個來按照物體的朝向移動物體了泉褐,比如,下面的代碼會朝著物體的y軸正方向每秒1米的速度勻速移動:

using UnityEngine;

using System.Collections;

public class Demo01Script : MonoBehaviour

{

????public Transform myTransform;

????void Start()

????{

????}

????void Update()

????{

????????Vector3 pos = myTransform.position;

????????pos.x += myTransform.up.x * 1.0f * Time.deltaTime;

????????pos.y += myTransform.up.y * 1.0f * Time.deltaTime;

????????pos.z += myTransform.up.z * 1.0f * Time.deltaTime;

????????myTransform.position = pos;

????}

}

坐標系轉換

由于坐標系存在本地坐標系和世界坐標系兩種鸟蜡,那么就需要有方法可以對這兩種坐標系進行轉換膜赃。

transform.localToWorldMatrix:本地坐標轉世界坐標的矩陣信息。

transform.worldToLocalMatrix:世界坐標轉本地坐標的矩陣信息矩欠。

transform.TransformDirection:將方向從本地坐標轉換為世界坐標财剖,不受縮放影響。

transform.InverseTransformDirection:將方向從世界坐標轉換為本地坐標癌淮,不受縮放影響躺坟。

transform.TransformPoint:將位置從本地坐標轉換為世界坐標,受縮放影響乳蓄。

transform.InverseTransformPoint:將位置從世界坐標轉換為本地坐標咪橙,受縮放影響。

transform.TransformVector:將坐標點從本地坐標轉換為世界坐標虚倒,不受位置影響但受縮放影響美侦。

transform.InverseTransformVector:將坐標點從世界坐標轉換為本地坐標,不受位置影響但受縮放影響魂奥。

TransformPoint和TransformVector的區(qū)別

下面我們看看這兩個方法的區(qū)別菠剩,首先,我們添加一個空物體到舞臺并設置該物體的坐標為(1,1,1)耻煤,然后把Cube對象拖入該空物體成為其子項設定其坐標為(2,2,2)具壮,修改腳本如下:

using UnityEngine;

using System.Collections;

public class Demo01Script : MonoBehaviour

{

public Transform myTransform;

void Start()

{

????Vector3 pos = myTransform.TransformPoint(new Vector3(1, 1, 1));

????Debug.Log(pos);

????//(4.0, 4.0, 4.0)

????Vector3 vec = myTransform.TransformVector(new Vector3(1, 1, 1));

????Debug.Log(vec);

????//(1.0, 1.0, 1.0)

}

void Update()

{

}

}


接下來我們把空物體的尺寸縮小一半看看結果會如何:



結論

TransformPoint轉變會受物體的位置和縮放影響轉換,而TransformVector僅受物體的縮放影響轉換哈蝇。

Demo01

這里做了一個示例棺妓,具體的功能是按下指定的鍵抓取到場景中的小盒子,使其始終位于屏幕前方炮赦,按下另一個鍵將這個小盒子拋出怜跑。

下面我們看核心的實現。

using UnityEngine;

using System.Collections;

public class Demo01Script : MonoBehaviour{?

?public Transform cube;?

?void Start() { }?

?void Update()?

?{

?//抓取小盒子 if (Input.GetKey(KeyCode.Q))

?{?

?//設定小盒子的位置到屏幕前方?

?cube.transform.position = transform.TransformPoint(new Vector3(0, 0, 2));?

?//將小盒子設定為讀取對象的子對象, 保證跟隨運動

?cube.transform.SetParent(transform);?

?//去掉物理交互?

?cube.GetComponent().isKinematic = true;?

?}?

?//扔出小盒子

?if (Input.GetKey(KeyCode.E))?

?{

?if (cube.transform.parent == transform)?

?{

?//使用掉物理交互?

?cube.GetComponent().isKinematic = false;

?//解除所有子物件的綁定關系

?transform.DetachChildren();?

?//獲取方向?

?Vector3 cameraDirect = transform.TransformDirection(0, 0, 5);?

?//添加緩沖的力?

?cube.GetComponent().AddForce(cameraDirect, ForceMode.Impulse);

}

}

}

}

我們先將攝像機前的一個點轉換為世界坐標賦予給小盒子的世界坐標使其位于攝像機之前吠勘,拋出時把攝像機向前方向的一個向量轉換為世界方向賦予小盒子拋出性芬。

位移

Unity3D里提供了方便控制物體位移的屬性及方法。

本地和世界坐標

transform.position:設置和獲取物件的世界坐標看幼。

transform.localPosition:設置和獲取物件的本地坐標批旺,相對于父級的坐標。

注意诵姜,在Inspector面板中的Transform里顯示的是本地坐標汽煮。

Translate

Transform的Translate方法可以更加方便的對物體的位移進行操作,該方法有四個重載:

1publicfunction Translate(translation: Vector3, relativeTo: Space = Space.Self):void;2publicfunction Translate(x:float, y:float, z:float, relativeTo: Space = Space.Self):void;

相對于本地坐標系或世界坐標系對物體進行位移操作棚唆。

1publicfunction Translate(translation: Vector3, relativeTo: Transform):void;2publicfunction Translate(x:float, y:float, z:float, relativeTo: Transform):void;

相對于指定物體的坐標進行位移操作暇赤。

注意:如果是相對于本地坐標系,則如果向上移動就是朝向物體本身的上方移動宵凌,如果是相對于世界坐標系則是向世界的上方向移動鞋囊,如果是相對于其他物體則是向這指定的物體的上方向移動。

AnimationCurve

AnimationCurve可以用來定義自定義的動畫軌跡瞎惫,我們通過在腳本中聲明一個該類型的對象溜腐,就可以在編輯器窗口對其進行編輯译株,然后使我們的物體按照編輯的軌跡進行移動等操作。

比如我們想要得到一個物體在X軸勻速移動挺益,Y軸進行上下循環(huán)移動的時候歉糜,可以使用下面的腳本:

using UnityEngine;

using System.Collections;

public class Demo02Script : MonoBehaviour

{

public AnimationCurve myAnimationCurve;

public Transform myTransform;

void Start()

{

}

void Update()

{

myTransform.position = new Vector3(

myTransform.position.x + 1 * Time.deltaTime,

myAnimationCurve.Evaluate(Time.time * 0.5f) * 2,

myTransform.position.z);

}

}

編輯器編輯的曲線如下:



Demo02

在游戲中都會有一個最基本的需求,就是移動到指定的點望众,下面我們來實現一下這個基本的功能匪补,腳本如下:

using System;

using UnityEngine;

using System.Collections;

public class Demo02Script : MonoBehaviour

{

?public Transform myTransform;

?public Transform myTarget;?

?private bool _isArrived = true;?

?private Vector3 _origin;?

?private Vector3 _target;

?private float _speed;?

?private Action _onArrived;?

?private float _allTime;

?private float _time;

?void Start()

?{?

?MoveTo(myTarget.position, 1, () => Debug.Log("I am arrived!"));

?} void Update() { if (!_isArrived) { _time += Time.deltaTime; //判斷是否抵達終點 if (_time >= _allTime) { //校正位置 myTransform.position = _target; //標記到達和調用回調 _isArrived = true; if (_onArrived != null) { _onArrived(); } } else { //這里使用Lerp方法進行差值運算也可以得到相同的效果, 但是我們作為學習還是自己實現 //myTransform.position = Vector3.Lerp(_origin, _target, _time / _allTime); //獲取方向的單位向量 Vector3 dirction = _target - _origin; dirction.Normalize(); //朝方向運動 myTransform.Translate(dirction * Time.deltaTime); } } } ////// 移動到指定點.

//////目標點.? ? ///移動速度, 米/秒.? ? ///到達后調用的方法.? ? private void MoveTo(Vector3 targetPosition, float speed, Action onArrived)? ? {? ? ? ? _isArrived = false;? ? ? ? _origin = myTransform.position;? ? ? ? _target = targetPosition;? ? ? ? _speed = speed;? ? ? ? _onArrived = onArrived;? ? ? ? //計算總共需要花費的時間? ? ? ? _allTime = Vector3.Distance(myTransform.position, _target) / _speed;? ? ? ? //重置使用的時間? ? ? ? _time = 0;? ? }}


運行后小盒子會想指定的物體進行勻速移動,到達后會輸出“I am arrived!”的字符串烂翰。

旋轉之歐拉角

歐拉角是由3個軸的旋轉角度組成的旋轉數據夯缺,比如我們在Inspector界面的Transform中看到的就是物體本地坐標系的歐拉角:



歐拉角每個軸數字都在0-360之間,表示其旋轉的角度甘耿。

Rotate

官方提供的旋轉方法踊兜,其一共有三個重載方法:

1publicfunction Rotate(eulerAngles: Vector3, relativeTo: Space = Space.Self):void;2publicfunction Rotate(xAngle:float, yAngle:float, zAngle:float, relativeTo: Space = Space.Self):void;

指定在本地坐標系或世界坐標系下旋轉到指定的角度。

publicfunction Rotate(axis: Vector3, angle:float, relativeTo: Space = Space.Self):void;

指定在本地坐標系或世界坐標系下基于軸axis進行旋轉棵里,旋轉到angle角度润文。

RotateAround

我們先看看其參數:

publicfunction RotateAround(point: Vector3, axis: Vector3, angle:float):void;

表示我們的物體圍繞指定的點point在軸axis下旋轉angle的角度。

LookAt

可以使物體面向指定的點殿怜,我們看看其參數:

1publicvoidLookAt(Transform target, Vector3 worldUp =Vector3.up);2publicvoidLookAt(Vector3 worldPosition, Vector3 worldUp = Vector3.up);

即使我們的物體面向指定的物體或點典蝌。

旋轉之四元數

歐拉角理解和使用都相當的方便,但是在實際進行旋轉時存在萬向鎖的問題头谜,所以引入了比較抽象的四元數的概念骏掀,當然我們在Unity中只要直接使用即可,是非常方便的柱告。

這里提供一個視頻截驮,可以讓大家直觀的了解什么是萬向鎖:http://v.youku.com/v_show/id_XNzkyOTIyMTI=.html

Quaternion

在Transform中,eulerAngles屬性是使用歐拉角來表示旋轉际度,而rotation屬性則是使用四元數來表示旋轉葵袭。

四元數提供了許多的靜態(tài)方法來使我們完成特定需求的效果,點擊這里可查看幫助乖菱。

Demo03

如果我們想要實現一個效果坡锡,物體勻速旋轉到指定角度時,使用歐拉角對每個軸進行變換是相當復雜的窒所,同時如果兩個軸重合了就會出現萬向鎖的問題鹉勒,無法解決,而使用四元數則可以避免這些問題吵取,下面是實現的腳本:


using UnityEngine;

using System.Collections;

public class Demo03Script : MonoBehaviour

{

public Transform myTransform;

public Transform myTarget;

void Start()

{

}

void Update()

{

RotateToTarget();

}

private void RotateToTarget()

{

//獲取目標方向的單位向量

Vector3 dicetion = (myTarget.position - myTransform.position).normalized;

//獲取目標方向的四元數對象

Quaternion targetDicetion = Quaternion.LookRotation(dicetion);

//按照每秒 45 度的速度旋轉面向目標對象

myTransform.rotation = Quaternion.RotateTowards(myTransform.rotation, targetDicetion, 45 * Time.deltaTime);

}

}


這樣我們就可以使我們的物體勻速的轉向指定的目標對象了禽额。

縮放與位置關系

縮放

縮放比較簡單,沒有提供更多的方法皮官。

Transform.lossyScale:只讀脯倒,獲取本物體相對于世界坐標的縮放大小实辑。

Transform.localScale:設置或獲取本物體相對于父級IDE縮放大小。

位置關系

在Unity3D中藻丢,所有3D對象是按照樹形結構進行組合的徙菠,而操作物體之間的位置關系的所有API都存放在Transform對象中,下面我們看看常用的屬性及方法郁岩。

屬性

Transform.parent:設置和獲取父級對象。

Transform.root:獲取層次最高的對象缺狠。

Transform.childCount:獲取子級對象的數量问慎。

方法

Transform.Find:根據名字尋找子項。

Transform.IsChildOf:判斷是否為指定Transform對象的子項挤茄。

Transform.DetachChildren:解除所有子項如叼。

Transform.GetChild:根據索引獲取子項。

Transform.GetSiblingIndex:獲取同一級別的物體的索引穷劈。

Transform.SetAsFirstSibling:設置為同一級別的物體為第一個索引笼恰。

Transform.SetAsLastSibling:設置為同一級別的物體為最后一個索引。

Transform.SetSiblingIndex:設置同一級別的物體的索引歇终。

工程文件下載

http://pan.baidu.com/s/1sjQJ5j3

天道酬勤社证,功不唐捐!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末评凝,一起剝皮案震驚了整個濱河市追葡,隨后出現的幾起案子,更是在濱河造成了極大的恐慌奕短,老刑警劉巖宜肉,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異翎碑,居然都是意外死亡谬返,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門日杈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遣铝,“玉大人,你說我怎么就攤上這事达椰『泊溃” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵啰劲,是天一觀的道長梁沧。 經常有香客問我,道長蝇裤,這世上最難降的妖魔是什么廷支? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任频鉴,我火速辦了婚禮,結果婚禮上恋拍,老公的妹妹穿的比我還像新娘垛孔。我一直安慰自己,他們只是感情好施敢,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布周荐。 她就那樣靜靜地躺著,像睡著了一般僵娃。 火紅的嫁衣襯著肌膚如雪概作。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天默怨,我揣著相機與錄音讯榕,去河邊找鬼。 笑死匙睹,一個胖子當著我的面吹牛愚屁,可吹牛的內容都是我干的。 我是一名探鬼主播痕檬,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼霎槐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梦谜?” 一聲冷哼從身側響起栽燕,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎改淑,沒想到半個月后碍岔,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡朵夏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年蔼啦,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仰猖。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡捏肢,死狀恐怖,靈堂內的尸體忽然破棺而出饥侵,到底是詐尸還是另有隱情鸵赫,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布躏升,位于F島的核電站辩棒,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜一睁,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一钻弄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧者吁,春花似錦窘俺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至育八,卻和暖如春均芽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背单鹿。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留深纲,地道東北人仲锄。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像湃鹊,于是被迫代替她去往敵國和親儒喊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容