有啥办法可以阻止光线投射穿过物体?

Posted

技术标签:

【中文标题】有啥办法可以阻止光线投射穿过物体?【英文标题】:Is there any way to stop raycasts from going through objects?有什么办法可以阻止光线投射穿过物体? 【发布时间】:2022-01-20 09:06:25 【问题描述】:

我正在制作一把抓枪,如果图层为LightWeight,则将对象拉向玩家,如果图层为Ground,则将玩家拉向对象

            int groundLayer_mask = LayerMask.GetMask("Ground");
            int lightWeightLayer_mask = LayerMask.GetMask("LightWeight");

            //Shoots a raycast, and only works if layer is Ground
            if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, groundLayer_mask))
            
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 0;

                state = State.HookShotThrown;
            
            //Shoots a raycast, and only works if layer is LightWeight
            else if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, lightWeightLayer_mask))
            
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 1;

                state = State.HookShotThrown;
            

但是,如果我朝具有Ground 层的对象的方向看,即使有一个具有LightWeight 层的对象比具有Ground 的对象更接近,它也适用于具有Ground 的对象,因为我先有它的if语句。有什么方法可以让它不通过前面的对象只是因为第一个如果正在寻找后面的对象,或者让它优先考虑前面的对象?

【问题讨论】:

【参考方案1】:

除了layerHit 的值之外,您的两个 raycast 案例基本上都做同样的事情。所以无论哪种方式都是浪费资源;)

因此,为了提高效率并实现您想要的效果,只需在图层蒙版中包含两个图层,并对两个图层只进行一次光线投射 -> 它将使用从给定图层中首先命中的任何内容。

然后您仍然可以检查您在if 块中实际击中的层。

所以我会公开该字段以在 Inspector 中进行配置

// Configure this via the Inspector
// it will be a drop-down from which you can select multiple entries
public LayerMask layers;

private void Awake ()

    // if you really want to keep getting these by code
    layers = LayerMask.GetMask("Ground", "LightWeight");

而且通常我也会使用enum 来获得一些有意义的名称,例如

public enum HitType

    None = -1,
    Ground,
    Lightweight

然后像这样使用单个射线投射

int groundLayer_mask = LayerMask.NameToLayer("Ground");
int lightWeightLayer_mask = LayerMask.NameToLayer("LightWeight");

var hitType = HitType.None;

if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, layers))

    //Hit Something
    debugHitpointTransform.position = raycastHit.point;
    hookshotPosition = raycastHit.point;
    hookShotSize = 0f;
    HookShotTransform.gameObject.SetActive(true);
    HookShotTransform.localScale = Vector3.zero;

    if(raycastHit.collider.gameObject.layer == groundLayer_mask) hitType = HitType.Ground;
    else if(raycastHit.collider.gameObject.layer == lightWeightLayer_mask) hitType = HitType.Lightweight;

    state = State.HookShotThrown;

【讨论】:

@Brain_Grunt 是的,完全一样。基本上enum 仍然是int 底层(默认情况下.. 您甚至可以将底层类型更改为例如byteuint 等).. 但是这样您就可以为您的值指定一个特定的名称并且不要不必一直记住01 究竟代表什么。由于这些是编译时间常数,尽管您可以再次使用 switch 这会更有效 @Brain_Grunt 在哪里,您究竟想如何使用它?目前它只存在于进行光线投射的方法中......除非你为它创建一个类字段而不是使用var @Brain_Grunt 是的,在这种情况下,要么将其作为参数传递给您的方法,要么将其存储在某个类字段中 一般来说,在 Unity 中你想使用 Debug.Log 而不是 Console.WriteLine ;) 在带有 3 个立方体的新场景中使用 void Update()Vector3 dir;if (Input.GetMouseButtonDown(0)) dir = Vector3.forward;else if (Input.GetMouseButtonDown(1)) dir = Vector3.right;else return;int gm = LayerMask.NameToLayer("Default");int lwm = LayerMask.NameToLayer("Water");int layers = 1 << gm | 1 << lwm;if (Physics.Raycast(transform.position, dir, out RaycastHit raycastHit, float.PositiveInfinity, layers))if (raycastHit.collider.gameObject.layer == gm) Debug.Log("ground"); else if (raycastHit.collider.gameObject.layer == lwm) Debug.Log("lightweight"); 为我工作。

以上是关于有啥办法可以阻止光线投射穿过物体?的主要内容,如果未能解决你的问题,请参考以下文章

使用光线投射防止破折号穿过墙壁

VRay材质基础

光线追踪、光线投射、光线行进和路径追踪有啥区别?

光线投射算法(如何计算一个坐标点是不是在一个多边形内)

Unity3D 5.x 交互功能 - 光线投射碰撞设置

允许点击或光线投射到某些项目