Unity陀螺儀使用-仿崩壞3旋屏效果實(shí)現(xiàn)

O(∩_∩)O哈哈~大家好,這是本菜雞的第一篇分享,主要介紹如何還原類似崩壞3主界面的陀螺儀旋屏效果。以下實(shí)現(xiàn)僅基于個(gè)人的分析理解邮府,難度挺低的,大佬們湊合看看就好啦溉奕,寫(xiě)的不好的地方歡迎指正哈~

需求分析

崩壞3的主界面陀螺儀效果具備以下兩個(gè)特點(diǎn):

1褂傀、當(dāng)用戶轉(zhuǎn)動(dòng)手機(jī)的時(shí)候,攝像機(jī)的視角會(huì)朝指定的方向旋轉(zhuǎn)加勤。

2仙辟、攝像機(jī)的視角旋轉(zhuǎn)速度和回復(fù)速度的大小與用戶轉(zhuǎn)動(dòng)手機(jī)的速度大小成正比。

設(shè)計(jì)實(shí)現(xiàn)

首先了解下Unity中提供的陀螺儀相關(guān)信息鳄梅。如下圖所示叠国,陀螺儀的坐標(biāo)軸是右手坐標(biāo)系與unity的左手坐標(biāo)系不同,在使用時(shí)需要注意戴尸!

手機(jī)平放粟焊,x軸為右手邊,y軸為正前方,z軸為正上方项棠。


圖1 陀螺儀坐標(biāo)軸

陀螺儀主要參數(shù)詳解:

Input.gyro.enabled:bool類型悲雳,返回陀螺儀的啟用狀態(tài)。

Input.gyro.attitude:Vector3類型沾乘,返回手機(jī)當(dāng)前的姿態(tài)信息怜奖,即與手機(jī)初始姿態(tài)相比在x、y翅阵、z軸上的偏離情況(單位:弧度)歪玲,初始姿態(tài)指的是手機(jī)水平正向放置(此時(shí)Input.gyro.attitude為(0,0,0))。

Input.gyro.rotationRate:Vector3類型掷匠,返回陀螺儀測(cè)量的各軸上的旋轉(zhuǎn)速率的原始值滥崩,單位為“弧度/秒”。

Input.gyro.rotationRateUnbiased:Vector3類型讹语,返回陀螺儀測(cè)量的各軸上的旋轉(zhuǎn)速率的修正值钙皮,單位為“弧度/秒”。

Input.gyro.updateInterval:float類型顽决,返回陀螺儀參數(shù)的更新間隔,單位:秒短条。

Input.gyro.gravity:Vector3類型,返回陀螺儀測(cè)量的重力加速度向量才菠。

Input.gyro.userAcceleration:Vector3類型茸时,返回設(shè)備的加速度向量。

注意:在手機(jī)的Portrait(豎屏)和Landscape(橫屏)模式下赋访,陀螺儀的坐標(biāo)軸并不一致,如果需要的話需要相應(yīng)變換可都。

了解陀螺儀相關(guān)參數(shù)的作用后,我們開(kāi)始分析如何實(shí)現(xiàn)需求蚓耽。首先渠牲,只有當(dāng)用戶轉(zhuǎn)動(dòng)手機(jī)的時(shí)候,攝像機(jī)的視角才會(huì)相應(yīng)變化步悠,說(shuō)明攝像機(jī)的變化跟手機(jī)的當(dāng)前姿態(tài)無(wú)關(guān)签杈。這意味著我們的輸入應(yīng)該是陀螺儀測(cè)量的旋轉(zhuǎn)速率(rotationRate)而非手機(jī)的當(dāng)前姿態(tài)(attitude)信息。由于rotationRateUnbiased是在rotationRate的基礎(chǔ)上進(jìn)行修正鼎兽,測(cè)量結(jié)果更加準(zhǔn)確答姥,我們使用該屬性控制攝像機(jī)視角的旋轉(zhuǎn)。

我們所說(shuō)的攝像機(jī)視角的旋轉(zhuǎn),實(shí)際上是攝像機(jī)基于自身坐標(biāo)軸根據(jù)陀螺儀的rotationRateUnbiased參數(shù)進(jìn)行旋轉(zhuǎn)接奈。結(jié)合圖1各軸的方向分析可知踢涌,手機(jī)橫屏放置時(shí),陀螺儀的x序宦、y軸和攝像機(jī)自身的x睁壁、y軸的正方向是吻合的(z軸正方向相反)。我們僅需要在x、y軸方向上旋轉(zhuǎn)攝像機(jī)潘明,陀螺儀z軸上的旋轉(zhuǎn)變化不應(yīng)對(duì)攝像機(jī)產(chǎn)生影響行剂。

我們可通過(guò)在Update方法里執(zhí)行以下語(yǔ)句控制攝像機(jī)的旋轉(zhuǎn)。

transform.Rotate(vertRotateRate, horiRotateRate, 0);

其中钳降,vertRotateRate和horiRotateRate分別表示陀螺儀在垂直(繞x軸)方向和水平(繞y軸)方向上的旋轉(zhuǎn)速率:

vertRotateRate = Input.gyro.rotationRateUnbiased.x;

horiRotateRate = Input.gyro.rotationRateUnbiased.y;

為了防止旋轉(zhuǎn)速率過(guò)大厚宰,導(dǎo)致攝像機(jī)瞬間旋轉(zhuǎn)較大角度從而影響表現(xiàn)的問(wèn)題,我們需要通過(guò)以下語(yǔ)句限制旋轉(zhuǎn)速率的大兴焯睢:

vertRotateRate = Mathf.Sign(vertRotateRate) * Mathf.Clamp(Mathf.Abs(vertRotateRate), 0, maxRotateRate);

horiRotateRate = Mathf.Sign(horiRotateRate) * Mathf.Clamp(Mathf.Abs(horiRotateRate), 0, maxRotateRate);

其中铲觉,maxRotateRate是我們?cè)O(shè)定的最大旋轉(zhuǎn)速率,其值可設(shè)為Mathf.PI吓坚,即最大為π rad / s撵幽。

實(shí)現(xiàn)攝像機(jī)的旋轉(zhuǎn)后,還要考慮如何在旋轉(zhuǎn)結(jié)束后讓其回復(fù)至初始旋轉(zhuǎn)狀態(tài)礁击,并且使得回復(fù)速率與陀螺儀輸入的旋轉(zhuǎn)速率成正比盐杂,即"轉(zhuǎn)得越快,回得越快"哆窿。為了實(shí)現(xiàn)攝像機(jī)得回復(fù)功能链烈,我們需要用一個(gè)變量initRotation(Quaternion類型)記錄攝像機(jī)的初始旋轉(zhuǎn)狀態(tài)。因此挚躯,我們可以通過(guò)在Update里面對(duì)相機(jī)的當(dāng)前rotation到initRotation進(jìn)行插值以實(shí)現(xiàn)回復(fù)效果强衡,實(shí)現(xiàn)如下:

transform.localRotation = Quaternion.Slerp(transform.localRotation, initRotation, restoreRate + restoreRate * factor);

其中,restoreRate是一個(gè)可設(shè)定的默認(rèn)值秧均,建議取值在0.05左右食侮,factor是一個(gè)縮放因子号涯,跟vertRotateRate 及horiRotateRate 相關(guān)目胡,其值為vertRotateRate 和horiRotateRate 中絕對(duì)值較大者和maxRotateRate的比值(factor的值在[0,1]之間)链快。通過(guò)restoreRate和factor構(gòu)建的簡(jiǎn)單線性關(guān)系誉己,可以實(shí)現(xiàn)回復(fù)速率與旋轉(zhuǎn)速率成正比。factor的計(jì)算如下:

factor = Mathf.Max(Mathf.Abs(vertRotateRate), Mathf.Abs(horiRotateRate)) / maxRotateRate;

需要注意的是域蜗,我們使用transform.localRotation旋轉(zhuǎn)攝像機(jī)巨双,如果你的項(xiàng)目中攝像機(jī)沒(méi)有父對(duì)象,請(qǐng)改為transform.rotation霉祸。

好了筑累,講到這里,我們的實(shí)現(xiàn)邏輯已經(jīng)很清晰了丝蹭,其實(shí)超級(jí)簡(jiǎn)單對(duì)不對(duì)慢宗,但效果還是可以的。值得再提的一點(diǎn)是,我們可以設(shè)置兩個(gè)縮放因子vertRotateRateScale镜沽、horiRotateRateScale來(lái)分別控制攝像機(jī)垂直敏晤、水平方向上旋轉(zhuǎn)速率的大小(使得兩個(gè)方向上的旋轉(zhuǎn)速率差異化),以增強(qiáng)靈活性缅茉。

最后嘴脾,放出我們最終的實(shí)現(xiàn)代碼,畢竟目前水平有限蔬墩,如果您有好的建議或優(yōu)化方案译打,還請(qǐng)不吝賜教哈O(∩_∩)O~感謝!

public class CameraGyroController : MonoBehaviour

{

? ? public Vector3 initEuler = Vector3.zero;? ? ? ? ? ? ? ? ? ? //初始旋轉(zhuǎn)對(duì)應(yīng)歐拉角

? ? private Quaternion initRotation = Quaternion.identity;? ? ? //初始旋轉(zhuǎn)信息

? ? private Vector3 lastInitEuler = Vector3.zero;? ? ? ? ? ? ? //用于判斷初始?xì)W拉角是否變化

? ? public float vertRotateRateScale = 0f;? ? ? ? ? ? ? ? ? ? ? //垂直陀螺儀旋轉(zhuǎn)速率縮放系數(shù)

? ? public float horiRotateRateScale = 0f;? ? ? ? ? ? ? ? ? ? ? //水平陀螺儀旋轉(zhuǎn)速率縮放系數(shù)

? ? public float restoreRate = 0f;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //回復(fù)速率

? ? private float maxRotateRate = Mathf.PI;? ? ? ? ? ? ? ? ? ? //陀螺儀單軸最大旋轉(zhuǎn)速率

? ? private float factor = 0f;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //陀螺儀旋轉(zhuǎn)速率和回復(fù)速率間的關(guān)聯(lián)系數(shù)(旋轉(zhuǎn)速率越大回復(fù)越快)

? ? private float vertRotateRate = 0f;? ? ? ? ? ? ? ? ? ? ? ? ? //垂直方向旋轉(zhuǎn)速率

? ? private float horiRotateRate = 0f;? ? ? ? ? ? ? ? ? ? ? ? ? //水平方向旋轉(zhuǎn)速率

? ? void Init()

? ? {

? ? ? ? initRotation = transform.localRotation;

? ? ? ? initEuler = initRotation.eulerAngles;

? ? ? ? lastInitEuler = initEuler;

? ? ? ? Input.gyro.enabled = true;

? ? }

? ? /// <summary>

? ? /// 根據(jù)陀螺儀控制主界面mainCamera的旋轉(zhuǎn)

? ? /// </summary>

? ? void CameraRotateControl()

? ? {

? ? ? ? if (!Input.gyro.enabled)

? ? ? ? {

? ? ? ? ? ? return;

? ? ? ? }

? ? ? ? //如果初始旋轉(zhuǎn)角度發(fā)生變化,則更新

? ? ? ? if (lastInitEuler != initEuler)

? ? ? ? {

? ? ? ? ? ? initRotation = Quaternion.Euler(initEuler);

? ? ? ? ? ? lastInitEuler = initEuler;

? ? ? ? }

? ? ? ? vertRotateRate = Input.gyro.rotationRateUnbiased.x;

? ? ? ? vertRotateRate = Mathf.Sign(vertRotateRate) * Mathf.Clamp(Mathf.Abs(vertRotateRate), 0, maxRotateRate);

? ? ? ? horiRotateRate = Input.gyro.rotationRateUnbiased.y;

? ? ? ? horiRotateRate = Mathf.Sign(horiRotateRate) * Mathf.Clamp(Mathf.Abs(horiRotateRate), 0, maxRotateRate);

? ? ? ? factor = Mathf.Max(Mathf.Abs(vertRotateRate), Mathf.Abs(horiRotateRate)) / maxRotateRate;

? ? ? ? //z軸不旋轉(zhuǎn)

? ? ? ? transform.Rotate(vertRotateRateScale * vertRotateRate, horiRotateRateScale * horiRotateRate, 0);

? ? ? ? //逐幀往初始位置回復(fù)

? ? ? ? transform.localRotation = Quaternion.Slerp(transform.localRotation, initRotation, restoreRate + restoreRate * factor);

? ? }

? ? // Use this for initialization

? ? void Start()

? ? {

? ? ? ? Init();

? ? }

? ? // Update is called once per fram

????void Update()

? ? {

? ? ? ? CameraRotateControl();

? ? }

? ? void OnGUI()

? ? {

? ? ? ? GUILayout.Label("rotation rate unbiased:" + Input.gyro.rotationRateUnbiased);

? ? ? ? vertRotateRateScale = GUI.HorizontalSlider(new Rect(75, 400, 200, 40), vertRotateRateScale, 0f, 1f);

? ? ? ? GUI.Label(new Rect(300, 395, 200, 40), "Vert Rotate Rate:" + vertRotateRateScale);

? ? ? ? horiRotateRateScale = GUI.HorizontalSlider(new Rect(75, 475, 200, 40), horiRotateRateScale, 0f, 1f);

? ? ? ? GUI.Label(new Rect(300, 470, 200, 40), "Hori Rotate Rate:" + horiRotateRateScale);

? ? ? ? restoreRate = GUI.HorizontalSlider(new Rect(75, 550, 200, 40), restoreRate, 0f, 0.2f);

? ? ? ? GUI.Label(new Rect(300, 545, 200, 40), "Restore Rate:" + restoreRate);

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拇颅,一起剝皮案震驚了整個(gè)濱河市扶平,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔬蕊,老刑警劉巖结澄,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異岸夯,居然都是意外死亡麻献,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)猜扮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)勉吻,“玉大人,你說(shuō)我怎么就攤上這事旅赢〕萏遥” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵煮盼,是天一觀的道長(zhǎng)短纵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)僵控,這世上最難降的妖魔是什么香到? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮报破,結(jié)果婚禮上悠就,老公的妹妹穿的比我還像新娘。我一直安慰自己充易,他們只是感情好梗脾,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著盹靴,像睡著了一般炸茧。 火紅的嫁衣襯著肌膚如雪帆疟。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天宇立,我揣著相機(jī)與錄音踪宠,去河邊找鬼。 笑死妈嘹,一個(gè)胖子當(dāng)著我的面吹牛柳琢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播润脸,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼柬脸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了毙驯?” 一聲冷哼從身側(cè)響起倒堕,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎爆价,沒(méi)想到半個(gè)月后垦巴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铭段,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年骤宣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片序愚。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡憔披,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爸吮,到底是詐尸還是另有隱情芬膝,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布形娇,位于F島的核電站锰霜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏埂软。R本人自食惡果不足惜锈遥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一纫事、第九天 我趴在偏房一處隱蔽的房頂上張望勘畔。 院中可真熱鬧,春花似錦丽惶、人聲如沸炫七。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)万哪。三九已至侠驯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奕巍,已是汗流浹背吟策。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留的止,地道東北人檩坚。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诅福,于是被迫代替她去往敵國(guó)和親匾委。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容