Unity第一人称可视化传送门制作
引言
游戲中很多地方用得到傳送門,就跟哆啦A夢的任意門一樣,從這邊走進去,從那邊走出來,用Unity實現一下它吧。
先來個效果圖,請原諒沒有給門添加漂亮的門框、或者特效,因為手頭沒有合適的素材,但這不影響任意門的功能,也不影響介紹它的原理。另外,機器上也沒有按裝gif截屏,所以不帶動態,但圖中的“能量波動花紋”是帶動態的哦,請自行腦補。
這里是另一個,傳送門嘛,至少得兩個。
從一端走進去,就會從另一端走出來。效果還是可以的。
下面介紹一下原理和制作方法:
原理是這樣的,用一個攝像機,觀察傳送門另一邊的圖像,然后渲染到本端傳送門的平面上,這樣,就能在本端門內看到遠端的畫面了。
一、創建shader
用ShaderGraph制作一個Shader如下圖:
這個shader的原理比較簡單,事實上最關鍵的是下面兩個節點,上面的那一堆都是為了加能量波動的效果的。將攝像機畫面也就是一張紋理連接到BaseColor節點即可,最關鍵的是UV節點,要使用屏幕空間,否則的話,攝像機畫面會被壓縮到門的尺寸,就變形了。還要注意,這個shader勾選一下雙面渲染,否則跑到門的后面就看不到了。
然后用這個Shader制作一個材質,右鍵剛剛建好的ShaderGraph文件,選創建材質即可。
二、創建門
建一個Quad平面,作為傳送門。將上面的材質賦給它。然后在門的下面創建一個相機、兩個空物體,結構如下圖:
由于要在門上顯示另一個門外的場景,所以,本地門材質上顯示的是遠端門相機的畫面。另外需要注意的是,上面shader中所說過了,一定要使用屏幕空間作為紋理UV,這還有一個問題,那就是紋理尺寸,要跟屏幕尺寸相符,至少比例要一致,否則門上的畫面是要變形的。這個其實很容易解決,紋理使用動態創建的就好,根據屏幕尺寸動態建一張紋理即可:
然后就是將紋理設置到門的材質了,也是用代碼:
if( TargetDoor != null ) {// 獲取到門的渲染組件MeshRenderer renderer = GetComponent<MeshRenderer>();foreach (var m in renderer.materials){// 將本地門的材質紋理,設置為目標門攝像機的渲染紋理m.SetTexture("_MainTex", TargetDoor.ProtalCameraTexture);} }那么,為啥還要有兩個空物體呢?介紹一下原理:
如上圖所示,由于傳送門的兩端朝向是任意的,所以搞清楚攝像機的相對位置尤為重要,否則在A門看到的B門處的圖像角度就會不正確。有了上面那個空物體,這一切就變得簡單多了,甚至不需要計算,也不需要什么數學知識。
請看上述代碼中的注釋,文字有點繞,但道理比較容易理解。
三、實現傳送
上面步驟中共建了兩個空物體,但目前只說了其中一個的用途,另一個是干嘛的呢?試想一下,當角色被傳送時,從A門離開時相對于A的位置,應該與他到達B門時相對于B門的相對位置是相同的。這樣才不會顯得突兀,畫面跳轉也會比較正常。那么剩下的這個空物體,就是解決這個的,原理跟上面相機相對位置的原理是一模一樣的:
// 當角色進入門的碰撞范圍,觸發碰撞器 private void OnTriggerEnter(Collider other) {// 將角色的世界位置和朝向賦予門記錄目標位置的空物體m_TargetPos.position = other.transform.position;m_TargetPos.rotation = other.transform.rotation;// 使目標門用于記錄角色位置的空物體相對于目標門的相對位置與源門的相同TargetDoor.m_TargetPos.localPosition = m_TargetPos.localPosition;TargetDoor.m_TargetPos.localRotation = m_TargetPos.localRotation;// 將角色傳送過去other.transform.position = TargetDoor.m_TargetPos.position;other.transform.rotation = TargetDoor.m_TargetPos.rotation; }四、完善一下
是不是很簡單,完事了么?NO,還需要處理幾個小問題。試想一下,如果角色進入A門的觸發器,那么A門會把它傳送到B門去,但是,角色一旦到達B門,就會立即觸發B門的觸發器,然后B門又會把他傳送到A,然后,你的玩家就會被兩個門傳來傳去。。。怎么解決這個問題呢?還有,測試中發現,如果你的角色控制器用的是unity自帶的CharacterController組件的話,那么就會有點小問題,一并解決一下:
private void OnTriggerEnter(Collider other) {// 加一個接受傳送的變量,只有在接受傳送時,角色才能被傳過去。// 另外,順便判斷一下目標物體是否允許被傳送(通過層來判斷)if (bAcceptTrans && (((1 << other.gameObject.layer) & TransformTargetLayer) != 0)){// 暫時關閉目標門傳送觸發TargetDoor.bAcceptTrans = false;// 計算角色相對本地門的相對位置,保證傳送到目標門后,與目標門的相對位置一致。m_TargetPos.position = other.transform.position;m_TargetPos.rotation = other.transform.rotation;TargetDoor.m_TargetPos.localPosition = m_TargetPos.localPosition;TargetDoor.m_TargetPos.localRotation = m_TargetPos.localRotation;// 如果是CharacterController組件控制的角色,先禁用一下,傳送完了再打開// 如果你的代碼不是用這個組件,可以刪掉CharacterController cc = other.GetComponent<CharacterController>();if (cc != null)cc.enabled = false;other.transform.position = TargetDoor.m_TargetPos.position;other.transform.rotation = TargetDoor.m_TargetPos.rotation;if (cc != null)cc.enabled = true;} }五、更多的門
好了,把傳送門做成預制體,盡情在你的游戲中擺放吧。。A傳到B,B再傳回A,或者A傳到B,B傳到C,C又傳到D…只要你愿意,你可以一直這么擺下去。擺完之后,只要把目標門拖到Inspector面板即可。如下圖:
Transform Target Layer :允許被傳送的物體層,比如玩家層、子彈層…
Target Door:這個門的目標門(要把待傳送物體傳送到哪個門,就把哪個門拖到這里即可)
使用起來很簡單吧。。
六、還能完善嗎
本文到這里就結束了,它已經可以實現基本的傳送門的功能,但仍有很多優化和完善的余地,比如,shader可以寫的更炫酷一點,可以添加啟用或者禁用傳送門的效果和機關,傳送的瞬間添加一些特效…如果要繼續完善,那么就盡情的發揮想象力吧。
七、相關下載
猛擊此處下載可執行演示
猛擊此處下載工程源碼
總結
以上是生活随笔為你收集整理的Unity第一人称可视化传送门制作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一文详解泊车感知的摄像头需求
- 下一篇: 在Ubuntu 16.04中安装FBRe