網(wǎng)站獨(dú)立ip多代表什么灰色詞快速排名接單
??? 相機(jī)Camera,是場景中最重要的GO,它的作用是在屏幕上渲染整個(gè)或部分二次元世界,代替了人類的眼睛。本篇將實(shí)現(xiàn)相機(jī)跟隨主角移動(dòng)的過程,使用的API有:三維向量類的Vector3.Distance、Vector3.Angle;數(shù)學(xué)類的Mathf.Clamp;輸入系統(tǒng)的Input.GetAxis,用于得到鼠標(biāo)或者鍵盤的輸入信息;插值計(jì)算的Vector3.Lerp、Quaternion.Lerp等工具。
目錄
1. Camera的應(yīng)用
2. Camera的參數(shù)設(shè)置
3. 第三人角度的Camera場景結(jié)構(gòu)和功能分析
4. 腳本實(shí)現(xiàn)
5. 完整腳本CameraCtrl
1. Camera的應(yīng)用
? ? Camera的重要性不需要多說,每個(gè)場景中至少要有一個(gè)Camera,不然在任何顯示終端都看不見任何關(guān)于場景的渲染。從實(shí)際應(yīng)用來看,Camera主要有以下幾個(gè)應(yīng)用場景:
? (1)場景中代替玩家的眼睛
? 第一人視角(這是VR中的):
? 第三人視角
? (2)制作小地圖
? (3)UI應(yīng)用——UICamera:專門對(duì)著拍攝UI控件的攝像機(jī),UI控件中
? (4)Cinemachine制作片頭、切換視角
2. Camera的參數(shù)設(shè)置
官方文檔的Camera參數(shù)解釋:Camera component - Unity 手冊(cè) (unity3d.com)
實(shí)際應(yīng)用中以下幾項(xiàng)為重點(diǎn)參數(shù):
?(1)Culling Mask:包含或忽略要由攝像機(jī)渲染的對(duì)象層。在檢視面板中將層分配到對(duì)象。
這些對(duì)象層是通過Layer來分配的,選定這一層的對(duì)象(GO)會(huì)被顯示到相應(yīng)的Camera中。
(2)Clipping Planes:開始和停止渲染位置到攝像機(jī)的距離,Near為相對(duì)于攝像機(jī)的最近繪制點(diǎn)。Far為相對(duì)于攝像機(jī)的最遠(yuǎn)繪制點(diǎn)。如果Far值非常大時(shí),渲染的內(nèi)容就會(huì)很多,對(duì)于GPU的要求也會(huì)非常高。
(3)Viewport Rect:通過四個(gè)值指示將在屏幕上繪制此攝像機(jī)視圖的位置。在視口坐標(biāo)中測量(值為 0–1)。其中:X為繪制攝像機(jī)視圖的起始水平位置;Y為繪制攝像機(jī)視圖的起始垂直位置;W和H分別為屏幕上的攝像機(jī)輸出的高度和寬度。
? 以小地圖的攝像機(jī)顯示為例,這是它的XYWH的顯示
?
? ?(4)Depth:??攝像機(jī)在繪制順序中的位置。具有更大值的攝像機(jī)將繪制在具有更小值的攝像機(jī)之上。默認(rèn)的攝像機(jī)為-1
? (5)Target Display:?定義要渲染到的外部設(shè)備。值為 1 到 8 之間。這與Game窗口的Display設(shè)置向匹配
3. 第三人角度的Camera場景結(jié)構(gòu)和功能分析
? 第三人視角的游戲,一般的結(jié)構(gòu)如下:
? (1)功能分析:1. Camera始終跟隨在主角背后的一定距離(Distance),并初始有一定的俯仰角度;2. 用鼠標(biāo)點(diǎn)擊電腦屏幕,Camera隨鼠標(biāo)給的位置旋轉(zhuǎn)視角。
? 這兩個(gè)功能分別的實(shí)現(xiàn)步驟:
? (2)實(shí)現(xiàn)跟隨:1. 計(jì)算distance:相機(jī)的目標(biāo)(就是主角)與相機(jī)之間的距離;2. 計(jì)算相機(jī)將要移動(dòng)到的位置:目標(biāo)的新位置與distance的差,方向朝向目標(biāo)。
? (3)實(shí)現(xiàn)旋轉(zhuǎn):1. 獲取鼠標(biāo)點(diǎn)擊的水平、豎直方向的位置變化;2. 相機(jī)根據(jù)鼠標(biāo)變化數(shù)值,繞X、Y軸旋轉(zhuǎn)(Z方向不轉(zhuǎn));3. 限制Y方向的旋轉(zhuǎn)角度?
4. 腳本實(shí)現(xiàn):
(1)實(shí)現(xiàn)相機(jī)跟隨:
? 第一步:在Start()中,使用Vector3.Distance獲取目標(biāo)和相機(jī)間的距離,這是一個(gè)float值:
distance = Vector3.Distance(Target.transform.position, transform.position);
? 并記錄一下相機(jī)的初始角度:
rotation=transform.rotation;
? 第二步:在Update()中,計(jì)算當(dāng)時(shí)的相機(jī)需要到達(dá)的位置:
resultPos = Target.transform.position - rotation*Vector3.forward * distance;
? 其中,rotation*Vector3.forward 是給了distance一個(gè)向前的方向。
*向量叉乘的意義:方向?yàn)閮上蛄康慕M成平面的法向量方向,大小為兩向量組成的平行四邊形的面積。
? 第三步:將這個(gè)計(jì)算的目標(biāo)位置賦值給相機(jī):
transform.position=resultPos;
? 不過直接賦值后,運(yùn)行結(jié)果非常的生硬,還是給它一個(gè)線性插值,相機(jī)跟隨就平滑一些:??
transform.position = Vector3.Lerp(transform.position, resultPos, Time.DeltaTime);
*Lerp-線性插值,Vector3類和Quaternion類都有這個(gè)方法,定義為:
public static Vector3 Lerp (from :?Vector3, to :?Vector3, t : float)
? 兩個(gè)向量之間的線性插值。按照數(shù)字t在from到to之間插值。t是夾在0到1之間。當(dāng)t=0時(shí),返回from。當(dāng)t=1時(shí),返回to。當(dāng)t=0.5時(shí)放回from和to之間的平均數(shù)
運(yùn)行結(jié)果如下:
?(2)實(shí)現(xiàn)相機(jī)旋轉(zhuǎn):
? 當(dāng)鼠標(biāo)左鍵點(diǎn)擊屏幕并移動(dòng)時(shí),獲取鼠標(biāo)的(x,y)坐標(biāo)值變化,并將這個(gè)二維的坐標(biāo)值計(jì)算成Camera的X、Y旋轉(zhuǎn)角度(Z方向不旋轉(zhuǎn)),方法如下:
? 第一步:記錄相機(jī)的X、Y方向的初始角度angleX、angleY,使用的是Vector3中一個(gè)十分實(shí)用的API:Vector3.Angle。以下得到的就是初始相機(jī)和X、Y軸的夾角,返回的是float值;
angleX = Vector3.Angle(transform.right, Vector3.right);angleY = Vector3.Angle(transform.up, Vector3.up);
? 第二步:在Update()中得到鼠標(biāo)的水平和垂直的變化數(shù)值,這個(gè)數(shù)值也是float值,并將這兩個(gè)數(shù)值計(jì)入一個(gè)二維向量inputPos中;
inputPos.x = Input.GetAxis("Mouse X");inputPos.y = Input.GetAxis("Mouse Y");
*Input:管理所有的鍵盤、鼠標(biāo)或其他一切外設(shè)的輸入設(shè)置,比如之前在第一人控制器中使用的Input.GetKey(KeyCode.A),就是取得鍵盤輸入的API。Input中的設(shè)置可以在unity中的Edit菜單->ProjectSettings->InputManager中調(diào)整:
? 比如上面獲取到的X方向的輸入,就是獲取了Mouse X的輸入值,也就是鼠標(biāo)在x方向上的移動(dòng)變化。新版的Input管理可連接的外設(shè)更多,包括游戲手柄、XR設(shè)備等,以后開一篇細(xì)說(挖坑)。
? 第三步:判斷是否有鼠標(biāo)(“0”值指的是左鍵)點(diǎn)擊屏幕,如果有,就根據(jù)XY軸的輸入值,調(diào)整相機(jī)的XY軸旋轉(zhuǎn),注意,這個(gè)旋轉(zhuǎn)的方向、速度(rotateSpeed)等都需要根據(jù)實(shí)際情況自行調(diào)整,調(diào)整到一個(gè)用戶舒適的狀態(tài)。當(dāng)然,旋轉(zhuǎn)時(shí)也可以使用Lerp做平滑過渡;
if(Input.GetMouseButton(0)){angleX += inputPos.x*rotateSpeed*Time.deltaTime;angleY += inputPos.y * rotateSpeed* Time.deltaTime;rotation = Quaternion.Euler(yAngle, xAngle, 0); }
效果如下:
? ?第四步:限制角度。在實(shí)際應(yīng)用中,一般俯仰角度(X軸)是不能360度旋轉(zhuǎn)的,所以要使用數(shù)學(xué)類中的鉗制Clamp方法限制一下,這里的最大值最小值也是需要測試確定的;
yAngle = Mathf.Clamp(yAngle, yAngleMin, yAngleMax);
5. 完整腳本CameraCtrl:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//對(duì)象:MainCamera
//作用:
//1. 主相機(jī)跟隨某一對(duì)象,使用差值Lerp做平滑跟隨處理
//2. 點(diǎn)擊鼠標(biāo)左鍵,根據(jù)鼠標(biāo)的位置調(diào)整相機(jī)旋轉(zhuǎn)public class _camCtrl : MonoBehaviour
{ public GameObject Target; //載入Camera跟隨的對(duì)象private float distance; //主角與相機(jī)之間的距離private Quaternion rotation; //相機(jī)的旋轉(zhuǎn)角度private Vector3 resultPos; //相機(jī)需要移動(dòng)到的位置private Vector2 inputPos; //獲取鼠標(biāo)位置private float angleX; //相機(jī)旋轉(zhuǎn)的水平角度private float angleY; //相機(jī)旋轉(zhuǎn)的垂直角度public float rotateSpeed = 50; //旋轉(zhuǎn)速度,需要測試得知public int yAngleMin = 2; //限制最小角度,需要測試得知public int yAngleMax = 60; //限制最大角度,需要測試得知void Start(){distance = Vector3.Distance(Target.transform.position, transform.position);rotation = transform.rotation;//初始的相機(jī)水平和垂直角度angleX = Vector3.Angle(Vector3.right, transform.right);angleY = Vector3.Angle(Vector3.up, transform.up);}void Update(){}private static float angleClamp(float angle, float min, float max){//一個(gè)限制角度最大最小值的方法if (angle < -360)angle += 360;if (angle > 360)angle -= 360;return Mathf.Clamp(angle, min, max);}void FixedUpdate(){ //相機(jī)跟隨在主角移動(dòng)之后,因此可以使用LateUpdate()//如果需要相機(jī)與Hero緊密跟隨,沒有時(shí)差//可將相機(jī)跟隨也和Hero移動(dòng)一樣,寫在FixedUpdate()中//但是需要在系統(tǒng)中設(shè)置腳本運(yùn)行先后順序//獲取鼠標(biāo)位置inputPos.x = Input.GetAxis("Mouse X");inputPos.y = Input.GetAxis("Mouse Y");if (Input.GetMouseButton(0)) //判斷鼠標(biāo)左鍵是否按下{ //實(shí)現(xiàn)Camera旋轉(zhuǎn)angleX += inputPos.x * rotateSpeed * Time.fixedDeltaTime;angleY += inputPos.y * rotateSpeed * Time.fixedDeltaTime;angleY = angleClamp(angleY, yAngleMin, yAngleMax);//相機(jī)旋轉(zhuǎn)角度限制//使用插值平滑旋轉(zhuǎn)transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(angleY,angleX ,0),Time.fixedDeltaTime*5);}resultPos = Target.transform.position - rotation*Vector3.forward * distance;//求出相機(jī)的位置,主角位置減去(主角與相機(jī)之間的舉例distance*方向)//rotation乘,是給一個(gè)相機(jī)的旋轉(zhuǎn),否則為0//注意rotation乘的順序,與變量類型有關(guān)系//差值跟隨的方法transform.position = Vector3.Lerp(transform.position, resultPos, Time.fixedDeltaTime);}
}