unityloverz 发表于 2022-12-8 15:09

Unity中计算射线相关的程序处理

《Unity与C++网络游戏开发实战:基于VR、AI与分布式架构》以Unity图形开发和C++网络开发为主线,系统地介绍了网络仿真系统和网络游戏开发的相关知识。本书从客户端开发和服务器端开发两个方面着手,讲解了一个完整的仿真模拟系统的开发,既有详细的基础知识,也有常见的流行技术,更有完整的项目实战案例,而且还介绍了AR、人工智能和分布式架构等前沿知识在开发中的应用。本书共21章,分为4篇。第1、2篇为客户端开发,主要介绍了Unity基础与实战开发;第3、4篇为服务器端开发,主要介绍了C++网络开发基础与实战。


以下内容摘自《Unity与C++网络游戏开发实战》一书中
       在图形开发和Unity游戏开发中,射线是一个非常重要的概念。在图形应用中,正面和背面的计算、碰撞检测、人物和地面的高度计算等,都大量运用射线进行计算。射线可以看作一个原点、一个方向、无限长度的向量,本节将大量应用向量相关的线性算法进行计算。
      在Unity中Ray类和RaycastHit类是两个最常用的射线工具类,一个是射线操作的类,一个是射线检测碰撞的类。
      创建射线时需要传入两个参数,一个是origin,代表起始点;另一个是direction,决定了射线发射的方向。另外,传入的参数如果没有单位化,Unity会自动对传入的参数做一次归一化。射线Ray的构造函数为:
public Ray(Vector3 origin, Vector3 direction);
下面还有一些和射线碰撞检测相关的类和参数,如下所述。
l RaycastHit:这个类是用来检测射线和物体碰撞以后产生的结果,包括碰撞的位置点和碰撞到的物体等信息。
l distance:发射射线到的最长距离,超过最长距离就不再检测。
l normal:射线摄入平面的法线现象,法线是永远垂直于平面的。
l point:这是一个vector3的数据对象,表示射线检测到碰撞的那个点所在的位置。
l Physics.Raycast:这是一个静态函数,用来计算射线物理碰撞的方法。
下面一段代码是用来计算物体和地面的高度。从平面上很高的高度y点,垂直地向平面发射一条射线,检测射线和物体的碰撞。接着在摄像机的下面放置一个物体,并且给它添加一个碰撞体,然后检测相机下面是否有一个游戏对象。具体代码示例如下:
using UnityEngine;
using System.Collections;
public class RayDemo : MonoBehaviour
{
    void Update()
    {
      // 以摄像机所在位置为起点,创建一条向下发射的射线
      Ray ray = new Ray(transform.position, -transform.up);
      RaycastHit hit;
      if (Physics.Raycast(ray, out hit, Mathf.Infinity))
      {
            // 如果射线与平面碰撞,打印碰撞物体信息
            Debug.Log("碰撞对象: " + hit.collider.name);
            // 在场景视图中绘制射线
            Debug.DrawLine(ray.origin, hit.point, Color.red);
      }
    }
}
我们先在场景的Camera下面建立一个Cube物体,然后给Camera附加4.6节中编写的RayDemo脚本,最后运行Demo。这时摄像机会向下发射一条射线,检测下方是否有物体,如图1所示。



图1    发射射线检测物体

   接着需要了解如何从屏幕发射射线来检测物体,它能帮助用户通过屏幕单击选择物品。
      这个射线是屏幕上一点面向3D世界一个方向发射的一条射线。如果是向世界坐标系中的一个矢量方向发射射线,我们已经演示过如何实现碰撞检测。针对向屏幕上的某一点发射射线,从屏幕到世界物体的检测碰撞,Unity提供了两个函数来计算对应的碰撞检测:ScreenPointToRay和ViewportPointToRay。
public Ray ScreenPointToRay(Vector3 position);
参数说明:position是屏幕坐标系上面的一个点。
      返回值说明:从屏幕的上的一点position发射一个射线到3D世界空间,然后通过3D世界空间的摄像机作为原点进行计算,如果计算到碰撞就返回碰撞信息,如果没有计算到碰撞,就返回碰撞点为(0,0,0)。
      ScreenPointToRay方法以3D世界环境的摄像机作为原点进行模拟,取屏幕上的一点position,相对原点发射一个射线。position是用屏幕上的像素点作为坐标表示的。position z等于0,因为屏幕上是一个二维坐标。屏幕分辨率上的值,从0到最大值,在三维世界中对应着它的横坐标X和纵坐标Y。
      下面用一段程序示例说明,如何利用ScreenPointToRay发射一条射线,指向屏幕上的某点进行定向碰撞检测,具体代码示例如下:
using UnityEngine;
using System.Collections;
public class ScreenRayDemo : MonoBehaviour
{
    Ray ray;
    RaycastHit hit;
    // 创建射线到屏幕上的参考点,像素坐标
Vector3 position = new Vector3(Screen.width/2.0f,Screen.height/2.0f,0.0f);
    void Update()
    {
      // 射线沿着屏幕x轴从左向右循环扫描
      position.x = position.x >= Screen.width ? 0.0f : position.x + 1.0f;
      // 生成射线
      ray = Camera.main.ScreenPointToRay(position);
      if (Physics.Raycast(ray, out hit, 100.0f))
      {
            // 如果与物体发生碰撞,在Scene视图中绘制射线
            Debug.DrawLine(ray.origin, hit.point, Color.green);
            // 打印射线检测到的物体的名称
            Debug.Log("射线检测到的物体名称: " + hit.transform.name);
      }
    }
}
      脚本编写好以后,把这个脚本挂载到Main Camera上,然后运行这个Demo,可以看到屏幕的中心发射了射线,进行物体的扫描。这就是从屏幕向世界坐标体系发射射线检测的方法,如图2所示。



图2    Sreen发射射线扫描
页: [1]
查看完整版本: Unity中计算射线相关的程序处理