[Unity] 关于正交相机:相机、地图、视口中心

在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的正交相机有一个更深的认识。

 

原创内容,转载请注明出处。

 

posted @ 2016-03-31 22:38  我爱我家喵喵  阅读(6511)  评论(1编辑  收藏  举报