- 最后登录
- 2018-1-5
- 注册时间
- 2012-10-11
- 阅读权限
- 30
- 积分
- 651
- 纳金币
- 0
- 精华
- 3
|
这一篇我紧接着上一篇来讨论一个我们避不开的一个问题,那就是镜头穿墙问题。其实,这个镜头穿墙问题确实是一个很棘手的问题。因为到现在都不能说100%解决,不光中国,甚至是国外也是。你也许会发现在某些游戏中,镜头也会或多或少的穿透物体或者墙壁的情形。如果是第一人称视角的话,根本不会出现这宗问题,但是如果是第三人称视角的话,我们就必须寻求一个优化这个问题的方式,这就是我今天要介绍的:利用射线作为工具来优化有关镜头穿墙方面的问题,我先将我们遇到的一个镜头穿墙的现象截一张图:
在这张图中我们可以发现我们的镜头穿透了墙壁到了墙壁外面,但还是看到了墙壁内的画面。如果是在现实中的话,那就
这次我先用这个工程:官方的ShadowDemoProject中的Apartment Scene这个场景,我们可以清清楚楚的看到,如果不对摄像机做一番处理,那么随着人物角色的旋转,摄像机穿透物体简直可以说是毫无压力,如果在游戏里面发生这样的情况,就会让玩家怀疑游戏的真实度。这是确实是我们不想看到的。那么接下来我就要对摄像机的代码做一定的修改了。
由于我个人以前用的是java,所以对C#的语法感觉似曾相识,因为java与C#确实是太相似了。这次我写了一个摄像机控制的C#脚本。然后加入了射线的碰撞检测,代码如下:
using UnityEngine;
using System.Collections;
public class GooberCamera : MonoBehaviour {
public Transform target;
public float distance = 4.0f;
public float maxDis = 4.0f;
public float smoothPosition = 5.0f;
public float smoothDis = 5.0f;
public float jd = 45f;
public float padding = 0.3f;
public Vector3 dir = new Vector3(0, 1, -1);
private LayerMask mask;
void Start () {
mask = 1<<( LayerMask.NameToLayer("MustRaycast"));//实例化mask到MustRaycast这个自定义的层级之上。
transform.eulerAngles = new Vector3(jd,0,0);//让摄像机成45°角对准视野。
if(!target){
return;
}
}
void LateUpdate () {
transform.eulerAngles = new Vector3(jd, 0, 0);//不断校正摄像机的旋转角度。
RaycastHit hit;//用于射线的碰撞检测
maxDis = Mathf.Lerp(maxDis, distance, Time.deltaTime * smoothDis);//不断让maxDis接近于distance,不然maxDis只会不断变小
if (Physics.Raycast(target.position, dir, out hit, maxDis + padding, mask))//开始射线方式的碰撞检测
{
maxDis = hit.distance - padding;//使maxDis变小,这是为了将摄像头拉近到角色。
}
transform.position = Vector3.Lerp(transform.position, target.position + transform.forward * (-maxDis), smoothPosition);
}
}
我让摄像机与的视角保持在45度,并且运用到了LayerMask这个类。我将那个房间里面的不懂的物体(不包括那些刚体)标示为静态的,然后添加了一个层,取名为:MustRaycast(如果读者对这方面还不熟悉,可以参考我上一篇文章)。然后有选择的进行碰撞检测,如果不管碰到什么东西你都检测的话,会出现大量的问题,比如如果角色与摄像机从一开始两者连线之间就有障碍物,那么就会发生摄像机一开始就会迅速靠近角色。角色的话我用了官方CharacterAnimation这个工程里面的goober。下面我们运行一下:
这是开始时摄像机没有检测到碰撞时Scene视图下的情形:
这是开始时摄像机检测到碰撞时Scene视图下的情形:
此时Game视图下是这样的:
很明显,摄像头被角色遮挡了,所以视野一片黑暗。
可是,这个代码也只是对镜头穿墙做了一定的处理,并没有完全解决问题,因此还是会有一定的穿墙情况发生。但是这个射线发射与LayerMask的应用确实给我们提供了一个很好的方式来解决特定事件。最后我还介绍一下有关LayerMask的实例化:
比如一个特定的layer,假设其名字为:layer1,则可以这样创建LayerMask类型变量:
LayerMask layerMask = 1<<LayerMask.NameToLayer( "layer1" );
如果要是这个layerMask包含层layer2,那么可以用“|”,即逻辑“或”来做运算:
layerMask |=1<< LayerMask.NameToLayer( "layer2" )。
那么既然可以用或运算,那么就可以用非运算。比如,如果我们的layerMask是除layer1与layer2的其他层的集合,那么我们可以这样来做:
LayerMask layerMask =1<< LayerMask.NameToLayer( "layer1" );//理解不了的可以看我的上一篇帖子。下一行代码也是一样的。
layerMask |=1<< LayerMask.NameToLayer( "layer2" );
layerMask = ~layerMask。//对layerMask取反,就是得到除layer1与layer2之外的其他层级的集合。
这样一来,我们就可以控制射线检测碰撞的范围了,这简直太棒了。
至此有关LayerMask配合射线碰撞的讲解也算是到了一定程度了。好了,今天放假,有点困了,晚安。
|
|