2018-05-07 13:22:02 qq_26270779 阅读数 309

在开发中,尤其是跟模型与交互的时候,都会用到射线检测,这篇文章给大家分享一些射线检测的方法实现。

射线:射线是3D世界中一个点向一个方向发射的一条无终点的线,在发射轨迹中与其他物体发生碰撞时,它将停止发射 。
用途:射线应用范围比较广, 多用于碰撞检测(如:子弹飞行是否击中目标)、角色移动等。

相关API:

  1、Ray Camera.main.ScreenPointToRay(Vector3 pos)   返回一条射线Ray从摄像机到屏幕指定一个点

  2、Ray Camera.main.ViewportPointToRay(Vector3 pos)  返回一条射线Ray从摄像机到视口(视口之外无效)指定一个点

  3、Ray 射线类

  4、RaycastHit 光线投射碰撞信息

  5、bool Physics.Raycast(Vector3 origin, Vector3 direction, float distance, int layerMask)

  当光线投射与任何碰撞器交叉时为真,否则为假。

  bool Physics.Raycast(Ray ray, Vector3 direction, RaycastHit out hit, float distance, int layerMask)

  在场景中投下可与所有碰撞器碰撞的一条光线,并返回碰撞的细节信息()。

  bool Physics.Raycast(Ray ray, float distance, int layerMask)

  当光线投射与任何碰撞器交叉时为真,否则为假。

  bool Physics.Raycast(Vector3 origin, Vector3 direction, RaycastHit out hit,float distance, int layerMask)

  当光线投射与任何碰撞器交叉时为真,否则为假。

  注意:如果从一个球型体的内部到外部用光线投射,返回为假。

  参数理解:

  origin : 在世界坐标中射线的起始点

  direction: 射线的方向

  distance: 射线的长度

  hit: 使用c#中out关键字传入一个空的碰撞信息类,然后碰撞后赋值。可以得到碰撞物体的transform,rigidbody,point等信息。

  layerMask: 只选定Layermask层内的碰撞器,其它层内碰撞器忽略。 选择性的碰撞

  6、RaycastHit[] RaycastAll(Ray ray, float distance, int layerMask)

  投射一条光线并返回所有碰撞,也就是投射光线并返回一个RaycastHit[]结构体。

  下面一个利用射线做的拾取的小例子(将代码直接拖拽到主相机上)

using UnityEngine;

   using System.Collections;
   public class RayTest : MonoBehaviour {

       // Use this for initialization
       void Start () {

      }

       // Update is called once per frame
       void Update ()
       {
           if(Input.GetMouseButton(0))
           {
               Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机发出到点击坐标的射线
               RaycastHit hitInfo;
              if(Physics.Raycast(ray,out hitInfo))
              {
                   Debug.DrawLine(ray.origin,hitInfo.point);//划出射线,只有在scene视图中才能看到
                   GameObject gameObj = hitInfo.collider.gameObject;
                   Debug.Log("click object name is " + gameObj.name);
                   if(gameObj.tag == "boot")//当射线碰撞目标为boot类型的物品 ,执行拾取操作
                   {
                       Debug.Log("pick up!");
                   }
               }
           }
       }
   }


2017-08-08 09:01:18 qq_33994566 阅读数 354

开发中我们经常遇到鼠标和三维物体交互的需求,要操作三维空间的物体,首先要选中这个物体,这时候就需要我们经常用到的射线检测。

一.单射线检测单个物体

代码使我们通用的射线检测代码,注释也已经标识上去了。

// Update is called once per frame
	void Update ()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机沿着屏幕鼠标位置方向发射一条射线
        RaycastHit hit; //射线检测返回的信息
        if (Physics.Raycast(ray, out hit)
        {
            if (hit.collider.CompareTag("model"))
            {
                Debug.Log("选中Tag为model的物体");
            }
        }
    }
当然如果项目中有些物体因为需要发生物理碰撞必须要加上collider而又不想被射线检测到,这时候我们就可以使用layMasker来选择性射线检测。代码如下:

 private float maxDistance = 1000f;//射线的最大长度

    private LayerMask lm1=1 <<8; // 只检测到Layer层id为8的物体

    private LayerMask lm2 = ~(1 << 8);//只检测不到Layer层id为8的物体

    private LayerMask lm3 = (1 << 8) | (1 << 9);//只检测不到Layer层id为8和9的物体


    // Update is called once per frame
    void Update ()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机沿着屏幕鼠标位置方向发射一条射线
        RaycastHit hit; //射线检测返回的信息
        if (Physics.Raycast(ray, out hit, 1000, lm1))//射线只能检测到layer层id为8的物体
        {
            if (hit.collider.CompareTag("model"))
            {
                Debug.Log("选中Tag为model的物体");
            }
        }
    }
二.射线检测返回物体信息数组

获取射线检测到的所有物体。以数组的形式返回所有碰撞体信息。

private RaycastHit[] hits;

    private void Update()
    {
        Ray ray= Camera.main.ScreenPointToRay(Input.mousePosition);//从摄像机沿着屏幕鼠标位置方向发射一条射线
        hits = Physics.RaycastAll(ray);  //将所有射线检测到的物体以数组形式保存下来

        Debug.Log("改射线碰撞检测到"+hits.Length+"个物体");
    }
以上代码是我觉得我们会经常使用到的射线代码,可是满足大部分项目需求。希望对你有帮助。

好记性不如烂笔头。我觉得即使我现在了解的滚瓜烂熟,只怕时间一长还是会忘了部分细节。所以在记录下来的同时还可以给大家一个帮助。一起进步吧!



2016-05-10 18:53:40 Gary_888 阅读数 1370

Unity3D射线检测控制转向,使用Ray射线检测鼠标的位置信息,角色transform方向转向该位置。

//控制转向
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hitInfo;//碰撞信息,用来获取从raycast函数中得到的信息反馈的结构
        if (Physics.Raycast(ray, out hitInfo, 200, groundLayerIndex))//检测射线,控制转向
        {
            Vector3 target = hitInfo.point;
            target.y = transform.position.y;
            transform.LookAt(target);
        }

2015-11-03 21:13:31 VioletTD 阅读数 2318

   今天向大家介绍一下,如何初步的用Unity3D从摄像机到鼠标的射线,也就是鼠标检测到Unity3D世界中的游戏对象!

       如何才能使射线检测到游戏对象呢,只有一个条件,那就是必须添加collider组件,否则你是绝度检测不到,你想要检测的物体的!

       如果你还是检测不到Unity3D世界里的游戏对象的话! 真相只有一个"你没有在Update里调用该方法"!

       好了,到了代码的部分的,请大家指教,哈哈哈哈哈哈哈!
using UnityEngine;
using System.Collections;
/// <summary>
/// 功能:数遍检测寻找Unity3D世界里的游戏对象
/// 创建者: VioletTD
/// 创建时间:2015年11月3日 21:28
/// 感谢: Me加油!!
/// </summary>
public class RayToFindTest : MonoBehaviour {//射线查找的测试脚本

	void Update () {
		RayToFindMethod ("Player");//
	}
	void RayToFindMethod(string tags)//定义一个私有的,无返回值,有参数的方法  参数为你想找到的游戏对象的标签(Tag)
	{
		Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);//实例化从摄像机到鼠标的摄像
		RaycastHit hit;//这个为射线命中的点
		if (Physics.Raycast (ray,out hit)) {//物理静态类中的光线投射方法 ->  意义:射线投射出  "得到射线命中的点(hit)"
			if (hit.transform.CompareTag(tags)) {//如果射线命中的点的标签(Tag)值为 tags -> 即:外部传入的参数(你想要找到的游戏对象的标签)  并把hit射线命中的点的类型转换为transform类型
				Debug.Log (hit.transform.name);//为真执行输出射线命中点的名字
			}
		}
	}
}

         谢谢大家的支持和鼓励!


2018-11-04 18:59:19 qq_39097425 阅读数 1023

后面继续研究,关于layer分层检测的问题,有点头疼,有时间要继续刚

3D射线检测:

 

1.射线普通检测,如果 Ray 跟系统命名冲突,只需要在前面加上 UnityEngine. 就行了

  UnityEngine.Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray,out hit))
        {
            if (hit.collider.gameObject.name == "Cube" )
            {
                print("你检测到了一个 Cube");
            }
        }

2.射线检测多个物体

   UnityEngine.Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit[] hits = Physics.RaycastAll(ray);
        if (hits.Length > 0)
        {
            foreach (var item in hits)
            {
                print(item.collider.gameObject.name);
            }
        }

 

3.射线分层检测,丫的,这个只有第一个 bool 是成立的,能够实现分层检测,其他两个就是不能,有人知道的话告诉我 ,万分感激(丫的,同样的代码,晚上一试就都行了,我真的是日狗了)还有一个问题就是第三个 bool 从摄像机到 鼠标点画线不知道为什么方向是错的

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ray : MonoBehaviour {

    public Transform cam;
    public Transform cube;
   // Update is called once per frame
 void Update () {
        UnityEngine.Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        LayerMask mask =1 << LayerMask.NameToLayer("layer");
        RaycastHit hit;

        // bool grounded = Physics.Raycast(cam.position, transform.forward, out hit, 10000f, 1 << LayerMask.NameToLayer("layer"));
        bool grounded = Physics.Raycast(ray, out hit,10000f, mask.value);
       //  bool grounded = Physics.Raycast(cam.position,cam.position - Input.mousePosition, out hit,10000f, 1 << LayerMask.NameToLayer("layer"));

        Debug.DrawRay(ray.origin,ray.direction* 10000f, Color.red);
        if (grounded)
        {
            if (hit.collider.CompareTag("layer"))
            {
                Debug.LogError("发生了碰撞");
                Debug.LogError("距离是:" + hit.distance);
                Debug.LogError("被碰撞的物体是:" + hit.collider.gameObject.name);
            }else
            {
                Debug.LogError("This layer no this tag!");
            }

        }
        else
        {
            Debug.LogError("碰撞结束");
        }
    }
}

4. 忽略第8层的 collider ,查看layer层信息,菜单栏 Edit=> Project Settings=> Tags And Layers

Ray ray = Camera.main.ScreenPointToRay(pressGesture.ScreenPosition);
        int layerMask = 1 << 8;
        layerMask = ~layerMask;
        RaycastHit hit;
        if(Physics.Raycast(ray,out hit,1000f,layerMask))
        {
            Debug.Log(hit.collider.gameObject.tag + "  " + hit.collider.gameObject.name);
            if (hit.collider.gameObject.CompareTag("Asteroid")) {
                if(asteroid_Explosion != null) Instantiate(asteroid_Explosion, hit.point,Quaternion.identity);
                Destroy(hit.collider.gameObject);
            }
            if (hit.collider.gameObject.CompareTag("Enemy")) {

                if (enemy_Explosion != null) Instantiate(enemy_Explosion, hit.point, Quaternion.identity);
                Destroy(hit.collider.gameObject);
            }
        }
       

2D射线检测:

canvas renderMode记得改成空间模式

 摄像头-> 鼠标

RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
            if (hit.collider != null)
            {
                Debug.Log("hit.collider.gameObject.name: " + hit.collider.gameObject.name);
            }

摄像头-> 世界坐标下的对象

 RaycastHit2D hit = Physics2D.Raycast(transform.position + mMoveDirectionCell, Vector2.zero);
                if (hit.collider != null)
                {
                    Debug.Log("hit.collider.gameObject.name: " + hit.collider.gameObject.name);
                }

忽略某层写法,例如忽略 UI 层(在Edit->Project Settings->Tags and Layers中可以看到Layers的编号,UI 层编号为5)

  RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero,100f,~5);
            if (hit.collider.IsNotNull())
            {
                if (hit.collider.CompareTag("Monster"))
                {
                    // 调用 Monster 身上的显示UI方法
                    hit.collider.GetComponent<Monster>().MonsterDisplay(true);
                }
            }

 

Unity3D射线检测

阅读数 37

没有更多推荐了,返回首页