在Unity中,X、Y、Z三個坐標軸,分別代表 橫向、垂直、 前后。
在3D場景中, 我們有一個主相機, 有一個地形(Terrain), 地形的坐標為(0, 0, 0)。其中地形的角度、縮放是沒有意義的,可以無視。 主相機設置為正交模式,坐標的 X, Y, Z我們也設為0。如下圖所示。
從圖上可以看到, 這個時候, 我們的攝像機剛剛好位於地圖的左下角。
這個時候,相機 X 的移動代表水平方向, Y 軸代表的是上下移動, Z 的移動看不到效果。
實際上我們需要的不是這樣, 我們想要的是能看到地面上的東西。
經過我多次的折騰和思考,我們將相同的Rotation.X設為45度,就可以很好的看到地圖了。
從圖上可以看到,已經能顯示地圖上的東西了。但是地圖的左下角在相機的中心,我們想要的是,將地圖在相機中居中顯示,並且我們要知道,攝像機的移動邊界,不能視口超出地圖的可視區域。
地圖的大小是 80 x 80, 相機是12, 相機是角度是45度的正交相機。屏幕是1920x1080像索(長寬比為16:9)。這是我們現在的情況。
首先我們將地圖水平居中。
要讓視口在地圖的水平居中, 我們需要先計算出視口的寬度。
在這之前,我們需要先知道, 相機的大小代表的是相機的中心到縱向邊界的距離,也就是中心到上邊或下邊的距離,所以我們相機為12時,我們可以認為相機在y軸的大小為24。
相機x軸的大小 = 相機y軸的大小 * 屏幕的長寬比 = 24 * (16 / 9) = 42.6666667 個單位。
那么,
我們要讓相機在x軸上的中心點與地圖的中心點重合,可以這樣計算:
相機中心點X = (地圖的大小 - 相機X軸大小) / 2 + (相機X軸大小 / 2) = (80 - 42.666667) / 2 + 42.666667 / 2 = (18.6666665) + 21.3333335 = 39.99999985f
可以看到,在X軸上相機已經居中了, 上圖的相機x軸顯示的是40,是因為unity沒保留那么高精度。要注意的是,在上面的公式中,為什么要在后面 + 相機X軸大小 / 2? 你們可以先想想,我在后面再說。
接下來,我們需要將相機的視口對准地圖的中心。此時,我們可以在Unity中調節相機的Y坐標和Z坐標,發現在相機預覽窗口中,地圖都會上下移動。這又是為什么呢?
其實,因為我們將相機X軸旋了45度,也就是說,相機是以45度角斜着看向地圖的。這個角度,剛剛好使得我們將相機向上或向Z軸移動,在視口的Y軸上,都會有相同的位移效果。
但是需要注意的是,雖然相機Y軸的移動也可以讓地圖顯示的區域上下移動,但這樣並不好。Y軸本身上將相機上下移動,會導致相機與地圖的垂直距離變化,雖然正交相機不受距離影響產生近大遠小的效果,但在某些時候還是會有問題。比如地圖上樹、草的顯示,可能會在離相機一定的距離后不再顯示了。
所以呢,我們要地圖的顯示區域上下移動,需要通過改機相機在Z軸的位置來實現。
我們知道相機的大小是12,相機在Y軸的大小相當於是12*2=24。
當我們將Z設為0時,發現只在視口的上半部分顯示了地圖,下半部分已經超出地圖區域。這又是為什么呢?還能不能愉快的玩耍!
其實,這個原因還是因為相機X軸旋轉的45度。
我們來看看下面這張圖:
從圖上可以看到,相機的Z為0時,視圖有一半已經在地圖外面了。
我們在計算Z軸的位置時,需要先算出相機投影到地圖時,能看到多大的區域,也就是視口區域Y軸的大小。
我們可以用勾股定理來計算(a2 + b2 = c2)。由於我們相機是45度,相機與地面形成的剛好可以是等腰三角形,特性是A,B兩條邊長相等,那么我們可以通過相機的大小的平方乘以2,再來開平方根得到C邊的大小。
視口區域Y軸大小 = √(相機大小的平方 * 2) = √(24 * 24 * 2) = 33.9411255f
請看下圖:
那么, 我們就知道了, 當 相機 Y 軸為0時, Z 為 視口區域大小 / 2 = 16.97時, 剛好顯示到地圖最底邊。
那么居中的話, 可以這樣計算:
相機中心點Z = (地圖的大小 - 視口區域Y軸大小) / 2 + 視口區域Y軸大小 / 2 = (80 - 33.94) / 2 + 33.94 / 2 = 33.97
將我們計算出來的中心點設置上去,看看效果:
可以看到,機相的中心點已經和地圖的中心點重合了。 哈哈。
我們現在相機的Y坐標還是0,其實將Y坐標設置為>0更加規范一些,否則可能會看不到一些東西(當然,可以通過調節相機的Clipping Planes屬性中的Near來實現,比如我們上面是將Near設為了-50,使相機可以看到屏幕外的景物(比較奇怪的感足,是不是?嘿嘿)。那么我們要是將相機的Y設為>0,就可以不用擔心這些了, 也可以不用將Near設為負數。
比如,我們將相機的Y坐標設為30。
你會發現,我們上面計算出來的值不對了,哈哈。
改變了相機的Y軸坐標,新的中心點怎么計算呢?
我們先來看看下圖:
從圖上可以看到,相機的Z為0時,我們實際看到的地圖底邊距離邊界是13.03,這個值怎么計算呢?
大家可以參考上圖、勾股定理、以及上面的內容,認真想想吧。具體的計算方法我就不再打出來了。
下面是我寫的一個函數:
/// <summary> /// 獲取使用正交相機時,主攝像機在地圖上的移動區域。 /// 使用正交相機時,可以通過旋轉攝像機X軸來顯示地圖,此時通過Y軸控制攝像機高度,X控制水平位置,Z軸控制上下位置。 /// </summary> /// <returns>返回攝像機移動區域.</returns> /// <param name="RotationX">攝像機旋轉角度(X軸)</param> /// <param name="CameraSize">相機大小</param> /// <param name="CamersY">攝像機高度(Y軸坐標)</param> /// <param name="MapW">地圖寬度</param> /// <param name="MapH">地圖高度</param> public static Rect OrthographicCameraEdge(float RotationX, float CameraSize, float CamersY, float MapW, float MapH) { float CXSize = CameraSize * 2 * ((float) Screen.width / (float) Screen.height); float CYSize = CameraSize * 2 / Mathf.Cos ( RotationX * Mathf.Deg2Rad ); return new Rect ( CXSize / 2.0f, CYSize / 2.0f - CamersY, MapW - CXSize, MapH - CYSize);; }
上面函數返回的Rect, width / 2 + left 就是X軸的中心點, height / 2 + top 就是y軸的中心點。
至此,本文也就算完結了, 希望大家能通過此文, 對Unity3D的正交相機有一個更深的認識。
原創內容,轉載請注明出處。