目錄
一、前言
二、Transform基礎(chǔ)
1、幾種坐標(biāo)系
2、position和localPosition屬性
3、rotation屬性
三、攝像機(jī)的平移
1、鍵盤控制平移
2、鼠標(biāo)控制平移
3、整合?
四、攝像機(jī)的旋轉(zhuǎn)
1、繞自身旋轉(zhuǎn)
2、繞目標(biāo)物體旋轉(zhuǎn)
3、整合?
五、優(yōu)化功能
1、調(diào)整速率
2、切換目標(biāo)物體
3、設(shè)置常用攝像機(jī)觀察點(diǎn)
一、前言
? ? ? ? 在做虛擬仿真或數(shù)字孿生等項(xiàng)目中,常常會(huì)遇到需要自由移動(dòng)視角的場(chǎng)景。最近在用unity制作一個(gè)有關(guān)3D打印機(jī)的數(shù)字孿生項(xiàng)目時(shí)遇到了這種情況,本文將結(jié)合unity和blender的視角移動(dòng)功能,介紹一個(gè)類似這兩個(gè)軟件的視角移動(dòng)的方法。
二、Transform基礎(chǔ)
????????Unity3D中的Transform組件是每個(gè)GameObject對(duì)象都有的組件,它控制著對(duì)象的位置、旋轉(zhuǎn)和縮放。?在介紹視角移動(dòng)前,本文將先介紹transform的position、rotation兩個(gè)屬性和unity中的坐標(biāo)系。
1、幾種坐標(biāo)系
? ? ? ? 在unity中常見(jiàn)的有兩種坐標(biāo)系,分別是全局坐標(biāo)(World Space)和局部坐標(biāo)(Local Space),在unity場(chǎng)景窗口(Scene)中可以切換這兩種坐標(biāo)系,如圖所示:
????????全局坐標(biāo):也稱為世界坐標(biāo),表示物體在場(chǎng)景中的絕對(duì)位置和方向。全局坐標(biāo)是相對(duì)于場(chǎng)景的原點(diǎn)(0,0,0)而言的。
????????局部坐標(biāo):也稱為相對(duì)坐標(biāo),表示物體相對(duì)于其父物體的位置和方向。局部坐標(biāo)是相對(duì)于父物體的原點(diǎn)(0,0,0)而言的。
2、position和localPosition屬性
? ? ? ? position和localPosition都是三維向量(Vector3),前者用于描述物體在場(chǎng)景中的絕對(duì)位置,即相對(duì)于世界原點(diǎn)的位置;后者描述物體相對(duì)于其父級(jí)對(duì)象的位置,以父物體為原點(diǎn)。
????????在沒(méi)有設(shè)置父物體時(shí),Transform.position和Transform.localPosition的值相同,都等于物體的全局坐標(biāo)。
????????當(dāng)物體P被設(shè)為物體Q的子物體時(shí),物體P的Transform.localPosition表示與父物體Q的相對(duì)位置,當(dāng)只改變父物體Q的Transform.position時(shí),子物體P將跟隨父物體Q移動(dòng),因此子物體P的Transform.position隨物體Q改變,然而子物體P相對(duì)于父物體Q的相對(duì)位置不變,所以子物體P的Transform.localPosition保持不變。
? ? ? ? 值得一提的是,在unity的檢查器(Inspector)面板的Transform組件中,所顯示的position為localPosition,對(duì)于無(wú)父物體的物體而言,其代表全局(世界)坐標(biāo),對(duì)于有父物體的物體而言,則表示兩者的相對(duì)位置。
3、rotation屬性
? ? ? ? 和描述位置的屬性一樣,描述旋轉(zhuǎn)的屬性也分為rotation和localRotation。它是一個(gè)四元數(shù)(Quaternion)。rotation與localRotation的關(guān)系和position與localPosition一樣,這里就不多做贅述。不過(guò)值得注意的一點(diǎn)是,在unity中文文檔中提到:
????????“請(qǐng)勿嘗試編輯/修改 rotation?!?/p>
????????“要旋轉(zhuǎn)?Transform,請(qǐng)使用?Transform.Rotate,它將使用歐拉角?!?/p>
三、攝像機(jī)的平移
? ? ? ? 在unity場(chǎng)景窗口中我們可以按住鼠標(biāo)滾輪進(jìn)行平移,而在blender中我們可以按住左Shift+鼠標(biāo)滾輪平移視角,除此之外,在unity中也可以通過(guò)鍵盤上下左右鍵控制視角移動(dòng)。而在項(xiàng)目中,我們將嘗試控制攝像機(jī)平移模仿上述效果。
1、鍵盤控制平移
? ? ? ? 鍵盤控制平移的代碼非常簡(jiǎn)單,不過(guò)在此之前應(yīng)該在unity的項(xiàng)目設(shè)置(Project Setting)中設(shè)置好輸入管理器(Input Manager)。如下圖所示:
?
? ? ? ? 在腳本分別調(diào)用Input.GetAxis("Vertical")和Input.GetAxis("Horizontal")將返回一個(gè)float值,由于類型設(shè)置為“Key or Mouse Button”,則返回-1、0、1三個(gè)值。
? ? ? ? 當(dāng)按下鍵盤W或者↑鍵時(shí)Input.GetAxis("Vertical")將返回1,按下S或者↓鍵時(shí)將返回-1,不按任何鍵將返回0;同理當(dāng)按下D或→鍵時(shí)Input.GetAxis("Horizontal")將返回1,按下A或者←鍵時(shí)將返回-1,不按則返回0。
? ? ? ? 根據(jù)這個(gè)屬性可得到控制平移的代碼:
float moveZ = Input.GetAxis("Vertical") * moveSpeedWithKeyBoard * Time.deltaTime;
float moveX = Input.GetAxis("Horizontal") * moveSpeedWithKeyBoard * Time.deltaTime;
transform.position += transform.forward * moveZ + transform.right * moveX;
2、鼠標(biāo)控制平移
? ? ? ? 我將用按下滾輪拖動(dòng)鼠標(biāo)的方式控制攝像機(jī)上下左右平移,滾動(dòng)滾輪控制前后平移。
? ? ? ? 首先是前后移動(dòng),確保你的輸入管理器(Input Manager)設(shè)置如圖所示:
?
? ? ? ? 通過(guò)調(diào)用Input.GetAxis("Mouse ScrollWheel")獲取前后移動(dòng)的值,同樣這個(gè)函數(shù)將返回一個(gè)float值,滾輪向前滾為正,向后為負(fù)。代碼如下:
float MouseScroll = Input.GetAxis("Mouse ScrollWheel") * moveSpeedWithScroll * Time.deltaTime;
transform.position += transform.forward * MouseScroll;
? ? ? ?
? ? ? ? 然后是上下左右移動(dòng)?,當(dāng)鼠標(biāo)滾輪按下時(shí)獲取鼠標(biāo)在xy軸移動(dòng)的值:
if (Input.GetMouseButton(2))
{
float moveX = -Input.GetAxis("Mouse X") * moveSpeedWithMouse * Time.deltaTime;
float moveY = -Input.GetAxis("Mouse Y") * moveSpeedWithMouse * Time.deltaTime;
transform.position += transform.right * moveX + transform.up * moveY;
}
3、整合?
????????綜合上述,不難發(fā)現(xiàn)這幾段代碼的相似之處:接收來(lái)自鼠標(biāo)或鍵盤的輸入并算出攝像機(jī)在forward、right、up三個(gè)方向上的移動(dòng)值,再乘以對(duì)應(yīng)的方向向量并加到相機(jī)的位置上,因此可以整合成以下函數(shù):
/// <summary>
/// 相機(jī)移動(dòng)
/// </summary>
public void Move()
{
float moveX = 0;
float moveY = 0;
float moveZ = 0;
// 接收鍵盤輸入
moveZ = Input.GetAxis("Vertical") * moveSpeedWithKeyBoard * Time.deltaTime;
moveX = Input.GetAxis("Horizontal") * moveSpeedWithKeyBoard * Time.deltaTime;
// 接收滾輪輸入
moveZ = Input.GetAxis("Mouse ScrollWheel") * moveSpeedWithScroll * Time.deltaTime;
// 接收鼠標(biāo)輸入
if (Input.GetMouseButton(2))
{
moveX = -Input.GetAxis("Mouse X") * moveSpeedWithMouse * Time.deltaTime;
moveY = -Input.GetAxis("Mouse Y") * moveSpeedWithMouse * Time.deltaTime;
}
// 控制移動(dòng)
transform.position += transform.forward * moveZ + transform.right * moveX + transform.up * moveY;
}
四、攝像機(jī)的旋轉(zhuǎn)
?????????常見(jiàn)的攝像機(jī)旋轉(zhuǎn)有兩種,即攝像機(jī)自身旋轉(zhuǎn)和攝像機(jī)繞目標(biāo)物體旋轉(zhuǎn)。在unity的場(chǎng)景窗口中按住鼠標(biāo)滾輪為繞自身旋轉(zhuǎn),按住左Alt+鼠標(biāo)左鍵時(shí)繞選中物體旋轉(zhuǎn)。下面我們將嘗試做出上述效果。
1、繞自身旋轉(zhuǎn)
? ? ? ? 繞自身旋轉(zhuǎn)的思路很簡(jiǎn)單,只需要獲取鼠標(biāo)輸入并更改攝像機(jī)自身的旋轉(zhuǎn)。代碼如下:
if (Input.GetMouseButton(0))
{
float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;
Vector3 eulerAngles = transform.eulerAngles;
eulerAngles.y += rotateX;
eulerAngles.x -= rotateY;
transform.eulerAngles = eulerAngles;
}
2、繞目標(biāo)物體旋轉(zhuǎn)
? ? ? ? 繞目標(biāo)物體轉(zhuǎn)動(dòng)較為復(fù)雜,需要同時(shí)改變position和rotation的值。首先確定目標(biāo)物體,再改變position值,這個(gè)過(guò)程和上文的鼠標(biāo)控制平移一樣,接下來(lái)需要改變r(jià)otation的值確保攝像機(jī)始終面向目標(biāo)物體,只需調(diào)用transform.LookAt()函數(shù)即可。
? ? ? ? 當(dāng)然使用上述方法可以粗略實(shí)現(xiàn)圍繞旋轉(zhuǎn),但是依舊有個(gè)小問(wèn)題,就是攝像機(jī)會(huì)在旋轉(zhuǎn)的過(guò)程中逐漸遠(yuǎn)離目標(biāo)物體,原因是我們每次改變position的值都將增加一點(diǎn)二者之間的距離(根據(jù)三角形的斜邊大于直角邊的原理),而后面的步驟沒(méi)有抵消掉這個(gè)距離變化。
? ? ? ? 所有在以上步驟之后還應(yīng)矯正一下距離,將攝像機(jī)的位置在目標(biāo)物體的方向上移動(dòng)至距離不變的位置,最終的代碼如下:
if (Input.GetMouseButton(1))
{
float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;
float distance = Vector3.Distance(target.transform.position, transform.position);
transform.position += transform.right * -rotateX + transform.up * -rotateY;
transform.LookAt(target.transform);
transform.position = target.transform.position + -transform.forward * distance;
}
3、整合?
? ? ? ? 同樣的,我們將以上兩段代碼整合封裝成函數(shù),可以得到以下代碼:
/// <summary>
/// 相機(jī)旋轉(zhuǎn)
/// </summary>
public void Rotate()
{
//接收輸入
float rotateX = Input.GetAxis("Mouse X") * rotateSpeed * Time.deltaTime;
float rotateY = Input.GetAxis("Mouse Y") * rotateSpeed * Time.deltaTime;
// 繞自身旋轉(zhuǎn)
if (Input.GetMouseButton(0))
{
Vector3 eulerAngles = transform.eulerAngles;
eulerAngles.y += rotateX;
eulerAngles.x -= rotateY;
transform.eulerAngles = eulerAngles;
}
// 繞噴頭旋轉(zhuǎn)
if (Input.GetMouseButton(1))
{
float distance = Vector3.Distance(target.transform.position, transform.position);
transform.position += transform.right * -rotateX + transform.up * -rotateY;
transform.LookAt(target.transform);
transform.position = target.transform.position + -transform.forward * distance;
}
}
五、優(yōu)化功能
1、調(diào)整速率
? ? ? ? 上述方法中,移動(dòng)的速率是不變的,這樣可能會(huì)導(dǎo)致當(dāng)攝像機(jī)離物體很遠(yuǎn)時(shí)會(huì)顯得移動(dòng)很慢,離物體很近時(shí)會(huì)顯得太快,可以寫一個(gè)函數(shù),根據(jù)距離目標(biāo)物體的遠(yuǎn)近自動(dòng)調(diào)整速率或許可以獲得更好的手感。?
2、切換目標(biāo)物體
? ? ? ? 上述方法中沒(méi)有提到目標(biāo)物體的切換與選擇,可以添加一個(gè)功能,通過(guò)鼠標(biāo)點(diǎn)擊選中游戲中的對(duì)象作為目標(biāo)物體圍繞旋轉(zhuǎn),切換目標(biāo)只需選擇其他對(duì)象即可。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-760859.html
3、設(shè)置常用攝像機(jī)觀察點(diǎn)
? ? ? ? 在實(shí)際項(xiàng)目中,可設(shè)置幾個(gè)常用的攝像機(jī)機(jī)位,用戶可通過(guò)快捷鍵快速切換到該位置觀察。例如在3D打印機(jī)的仿真中,可以在打印機(jī)窗口前設(shè)置一個(gè)觀察點(diǎn)來(lái)模擬實(shí)際中用戶觀察3D打印機(jī)的視角。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-760859.html
到了這里,關(guān)于【unity】關(guān)于unity3D攝像機(jī)視角移動(dòng)的幾種方式詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!