Unity 相机围绕物体指定观察角度和位置

来源:互联网 发布:hbuilder 编辑器无php 编辑:程序博客网 时间:2024/05/17 06:06
问题:相机始终围绕着O观察,现在从A坐标和视角 运动旋转 到B坐标和视角。。
条件:abcd这个矩形盒差不多是物体O的顶视图尺寸,A点箭头是相机所在的起点和角度,B点为目标点需要观察的角度。

       直接直线移动相机并按照AB夹角的差去移动和扭转相机的话 镜头很容易翻转!相机不可能总是在关注O对象!难受死了!
                   

 
      我能想到的最优解决办法:
      水平围绕+position插值、angle插值!插值时使用Lerp函数,而非直接递增角度、递增位置!
我之所以最后这么“愉快”的决定实在是由于数学捉急,除非会构造一条这样优美的曲线!

       But,实际A到O的具体和B到O的具体相等的情况太特殊了,更多时候,OAB只是一条普通的任意曲线!我甚至查了贝塞尔曲线相关的东西,但是发现起讫点AB虽然确定了,但如何调整这条弧的弧度却成了问题。最终我的处理方案近乎于这样的曲线:(图中荧光黄的部分!)

      但是作为补充,为什么我要扭曲的找到这条路径去移动相机,而不直接用Slerp球形插值的函数从头到尾的移动旋转呢?Slerp函数官方手册给的那个例子有点醉,我们普通的执行一下Vector3.SLerp(startposition, endstartposition, Time.deltaTime),就会发现直接起点到终点弧形插值的话,轨迹点始终在起点终点共面的一个球面上,轨迹的扭曲可能不比Lerp好到哪里去,除非你会计算调整传入的参数,找到自己想要的优美曲线,因此这个方法由于不够直观也被我pass了。
            

       其实最终这条曲线,即图中荧光黄的部分(有事可能是左上的那条路径),也是比较接近一条圆弧的。只要∠MOB或∠NOB足够小的话(只要大于一次RotateAround时的角度即可作为阈值)

       最后附上处理过程(假定实际中∠NAO < ∠MAO) :
1.第一点也是这个问题存在的前提条件!只有镜头A到B过程会穿过O对象时才需要这么复杂的路径,如果没有穿过B,普通的直线运动插值就OK了。因此首先需要检测相机出发到目标点B是否会穿插O对象。 
由于Physics.Raycast()所检测的对象要包含Collider及子类型的组件,我给O加个BoxCollder组件包围O对象。方向direction=b.position-a.position;
然后涉嫌检测到碰撞了O的话继续2步骤,否则直接走步骤4线性插值完毕。

2. 计算A沿圆周运动的终点M或N,∠NAO < ∠MAO的情况下,目标点应该是N,表示A沿移动到离B的差距 即 NOB夹角小于一定阈值如20°时,即可停止圆周运动。
目标点N的角度即为a.angle+∠BOA-y轴20°,这个视角是俯视的话,即为A移动到和B角差距的Y小于20°时即可。

3. 使得相机从A点平滑移动旋转到N点
具体是转到M点还是N点?这个取决于A沿圆弧触发的时候,去那个点转的角度更小一点!不然相机可能要几乎转一周去想要的终点啊啊。
我在处理走弧OAM还是弧OAN的时候,这时只要直接计算向量BO和向量OA的夹角,结果小于180°的,从左上旋转 方向Vector3.up,否则从右上旋转-Vector3.up.
用沿圆周围看着O绕旋转运动的函数camera.RotateAround(o.transform.position,Vector3.up,Time.deltaTime);

4.从N点插值计算移动并旋转到B点。期间使用围绕着中心点o!
我用了Lerp线性插值计算:
camera.transform.position = Vector3.Lerp(camera.transform.position, b.transfrom.position, delta);
camera.transform.rotation = Quaternion.Lerp(camera.transform.rotation, Quaternion.Euler(b.transfrom.angle), delta);


最终,虽然线性插值表示N到B是直线移动过去的,但由于相机一直观察着o且距离较小 ,这个近似误差也不会感觉太明显,还能接受的范围。














1 0