Unity基础射线判定以及编辑自定义模型
代码很简单没有难度,自己看一下应该就能明白。
OK 老规矩,直接上代码:
Unity射线基础解析
// 射线图层遮罩:
// LayerMask参数基础设置
// 1 << 8 打开第8的层。
// ~(1 << 8) 打开除了第8之外的层。
// ~(1 << 0) 打开所有的层。
// (1 << 10) | (1 << 8) 打开第10和第8的层。
// 也可以直接使用 LayerMask 结构体里的静态方法GetMask(),把LayerName传进去就自动转int类型图层掩码。
// 比位操作符更加简单和好理解。
// LayerMask.NameToLayer("字符串"); 对象中的内置层或用户层定义的层索引 返回 Int 类型
// LayerMask.LayerToName(10); 对象中的内置层或用户层定义的层索引 返回 String 类型
// 下面代码中都有应用根据个人需求来使用。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 射线基础解析
/// </summary>
public class Ray_ZH : MonoBehaviour
{
private void Update()
{
RayCmaera();
}
/// <summary>
/// Camera 射线 基本操作
/// </summary>
public void RayCmaera()
{
//点击鼠标左键
if (Input.GetMouseButtonDown(0))
{
//屏幕坐标转换 世界空间位置
Ray _RayCamera = Camera.main.ScreenPointToRay(Input.mousePosition);
//射线结构体 对象 包含各种信息
RaycastHit _CameraHit;
//射线布尔 判断
//参数 射线 返回结构体 最大距离 忽略层
if (Physics.Raycast(_RayCamera, out _CameraHit,1000, ~LayerMask.GetMask("Target")))
{
print("鼠标点击的位置是: " + _CameraHit.point);
}
}
}
/// <summary>
/// 自定义射线
/// </summary>
/// <param 射线原点="_Starting"></param>
/// <param 射线方向="_Direction"></param>
public void RayCustom(Vector3 _Starting ,Vector3 _Direction)
{
//创建自定义射线
Ray _RayCusetom = new Ray(_Starting, _Direction);
//返回结构体
RaycastHit _CusetomHit;
//射线布尔 判断
//参数 射线 返回结构体 最大距离 忽略层 查询报告触发次数
if (Physics.Raycast(_RayCusetom,out _CusetomHit,1000, ~(1 << LayerMask.NameToLayer("Target")), QueryTriggerInteraction.Collide))
{
print("变换的世界空间位置: " + _CusetomHit.transform.position);
print("在世界空间中射线击中对撞机的撞击点: " + _CusetomHit.point);
print("被击中的三角形的重心坐标: " + _CusetomHit.barycentricCoordinate);
print("被撞的碰撞体积: " + _CusetomHit.collider);
print("从射线的原点到撞击点的距离: " + _CusetomHit.distance);
print("在冲击点的uv光贴图坐标: " + _CusetomHit.lightmapCoord);
print("射线照射表面的法线: " + _CusetomHit.normal);
print("被撞击的碰撞器的刚体: " + _CusetomHit.rigidbody);
print("在碰撞位置的uv纹理坐标: " + _CusetomHit.textureCoord);
print("被击中的三角形的指数: " + _CusetomHit.triangleIndex);
print("被击中物体: " + _CusetomHit.transform);
}
}
}
Unity UI射线检测
UI 射线和平常的基础射线检测还是有点区别的 剩下的自己悟吧
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// UI 射线检测
/// </summary>
public class WorldEay_ZH : MonoBehaviour
{
[Header("目标世界位置")]
public Transform _WorldTarget;
[Header("UI 事件")]
public EventSystem _EventSystem;
[Header("World Canvas")]
public GraphicRaycaster _WorldCanvas;
[Header("Canvas")]
public GraphicRaycaster _Canvas;
//事件数据
private PointerEventData _PointerEventData;
//屏幕坐标
private Vector2 _CameraPos;
void Start()
{
//初始值赋予
_PointerEventData = new PointerEventData(_EventSystem);
}
void Update()
{
//自定义位置 UI 检测
if (Input.GetKeyDown(KeyCode.Q))
{
//世界转换 屏幕空间
_CameraPos = Camera.main.WorldToScreenPoint(_WorldTarget.position);
GraphicRaycaster(_CameraPos, _WorldCanvas, _EventSystem);
}
//鼠标检测
if (Input.GetMouseButtonDown(1))
{
RaycastUI(_PointerEventData,_Canvas);
}
}
/// <summary>
/// 鼠标 UI 射线检测
/// </summary>
/// <param 事件数据="_PoEvDa"></param>
/// <param 画布="_CanvasUI"></param>
public void RaycastUI(PointerEventData _PoEvDa, GraphicRaycaster _CanvasUI)
{
//事件数据 检测位置 类似于射线起始位置
_PoEvDa.position = Input.mousePosition;
//数据列表捕获
List<RaycastResult> _Results = new List<RaycastResult>();
//画布响应
_CanvasUI.Raycast(_PoEvDa, _Results);
//数据输出
foreach (RaycastResult _Eesult in _Results)
{
Debug.Log(_Eesult.gameObject.name);
}
}
/// <summary>
/// UI 射线检测
/// </summary>
/// <param 屏幕空间位置="_Pos"></param>
/// <param 画布="_Canvas"></param>
/// <param 事件系统="_EventSystem"></param>
private void GraphicRaycaster(Vector2 _Pos, GraphicRaycaster _Canvas, EventSystem _EventSystem)
{
//事件数据填充
var _PointerEventData = new PointerEventData(_EventSystem);
//触发位置赋值
_PointerEventData.position = _Pos;
//数据列表 重置
List<RaycastResult> _ResultsList = new List<RaycastResult>();
//射线检测
_Canvas.Raycast(_PointerEventData, _ResultsList);
//数据输出
for (int i = 0; i < _ResultsList.Count; i++)
{
print(_ResultsList[i].gameObject.transform.name);
}
}
}
射线判定生成自定义模型
这个是配合射线的基础应用来实现多条射线在平面上展开,并可以调节射线相隔角度来获取
碰撞点数组进行模型生成。
这个如果看的比较难受的话可以先去看看这篇文章:
链接: Unity代码编写自定义模型 修改器(可扩展)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 射线判定生成自定义模型
/// </summary>
public class CustomMesh_ZH : MonoBehaviour
{
//网格组件
private MeshFilter _MeshFilter;
//渲染组件
private MeshRenderer _MeshRender;
//碰撞组件
private MeshCollider _MeshCollider;
//顶点数据 数组
private List<Vector3> _Verts;
//渲染序列
private List<int> _Indices;
[Header("节点坐标物体")]
public List<Transform> _Vertss;
[Header("材质球")]
public Material _Material;
private Vector2[] _UV;
[Header("射线碰撞数组")]
public List<Vector3> _PointVector3;
[Header("碰撞角度")]
[Range(1, 180)]
public int _Angle;
[Header("半径")]
public int _Radius;
[Header("预制体生成存储数组")]
public List<Transform> _TransformsPro;
[Header("射线触碰位置生成预制体")]
public Transform _Pro;
public static CustomMesh_ZH _CustomMesh_ZH;
private void Awake()
{
//单列
_CustomMesh_ZH = this;
transform.eulerAngles = Vector3.right * 180;
Initialize();
}
/// <summary>
/// 数据生成
/// </summary>
public void Generate()
{
//数据清除
CleraMeshData();
//数据填充
if (_isBoom)
{
StartCoroutine(AddMeshDataOpen());
}
else
{
StartCoroutine(AddMeshData());
}
//数据传递给 Mesh 生成网格数据
//构造Mesh对象
Mesh _Mesh = new Mesh();
//顶点数据加载读取
_Mesh.vertices = _Verts.ToArray();
//渲染序列加载读取
_Mesh.triangles = _Indices.ToArray();
//UV数据加载读取
_Mesh.uv = _UV;
//从顶点重新计算网格的边界体积。
_Mesh.RecalculateNormals();
//从三角形和顶点重新计算网格的法线
_Mesh.RecalculateBounds();
//网格数据加载
_MeshFilter.mesh = _Mesh;
//碰撞体添加
_MeshCollider.sharedMesh = _Mesh;
//材质球赋予
_MeshRender.material = _Material;
transform.localPosition = Vector3.zero;
transform.localScale = Vector3.one;
}
/// <summary>
/// 数据清除
/// </summary>
private void CleraMeshData()
{
_Verts.Clear();
_Indices.Clear();
}
/// <summary>
/// 数据填充 闭环
/// </summary>
private IEnumerator AddMeshData()
{
//节点数据添加
for (int i = 0; i < _Vertss.Count; i++)
{
_Verts.Add(_Vertss[i].position);
}
//整体数组 三角构成判断
switch (_Verts.Count % 3)
{
//完美耦合状态
case 0:
//循环渲染 三角数列
for (int i = 1; i < _Verts.Count + 1; i++)
{
//三角面渲染
int _Index0 = 0;
int _Index1 = i;
int _Index2 = i + 1;
if (_Index2 >= _Verts.Count)
{
break;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
//余1状态
case 1:
//循环渲染 三角数列
for (int i = 1; i < _Verts.Count; i++)
{
//三角面渲染
int _Index0 = 0;
int _Index1 = i;
int _Index2 = i + 1;
//超出三角数列判定
if (_Index2 >= _Verts.Count)
{
break;
}
//余1状态 补充
if (i == _Verts.Count)
{
//三角面渲染
_Index0 = 0;
_Index1 = _Verts.Count - 1;
_Index2 = _Verts.Count;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
//余2状态
case 2:
//循环渲染 三角数列
for (int i = 1; i < _Verts.Count; i++)
{
//三角面渲染
int _Index0 = 0;
int _Index1 = i;
int _Index2 = i + 1;
//超出三角数列判定
if (_Index2 >= _Verts.Count)
{
break;
}
//余2状态 补充
if (i == _Verts.Count)
{
//三角面渲染
_Index0 = 0;
_Index1 = _Verts.Count;
_Index2 = _Verts.Count - 1;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
default:
break;
}
#region 循环渲染 三角数列 推演
// 基础三角数列 推演
//_Indices.Add(0); _Indices.Add(1); _Indices.Add(2);
//_Indices.Add(2); _Indices.Add(3); _Indices.Add(4);
//_Indices.Add(4); _Indices.Add(5); _Indices.Add(6);
//_Indices.Add(6); _Indices.Add(7); _Indices.Add(8);
//_Indices.Add(8); _Indices.Add(0); _Indices.Add(2);
//_Indices.Add(2); _Indices.Add(4); _Indices.Add(6);
//_Indices.Add(6); _Indices.Add(8); _Indices.Add(2);
//for (int i = 0; i < _Verts.Count; i++)
//{
// 三角面渲染
// int _Index0 = i + _Number;
// int _Index1 = i + _Number + 1;
// int _Index2 = i + _Number + 2;
// _Number++;
// if (_Index2 > _Verts.Count)
// {
// _Number = 0;
// _Reuse.Add(0);
// _TwoReuse.Add(_Reuse[0]);
// for (int j = 0; j < _Reuse.Count; j++)
// {
// print(_Reuse[j]);
// }
// break;
// }
#endregion
yield return new WaitForSeconds(0.1f);
}
/// <summary>
/// 数据填充 开环
/// </summary>
/// <returns></returns>
private IEnumerator AddMeshDataOpen()
{
//节点数据添加
for (int i = 0; i < _Vertss.Count; i++)
{
_Verts.Add(_Vertss[i].position);
}
int _Number = 0;
//整体数组 三角构成判断
switch (_Verts.Count % 3)
{
//完美耦合状态
case 0:
//循环渲染 三角数列
for (int i = 0; i < _Verts.Count; i++)
{
//三角面渲染
int _Index0 = i + _Number;
int _Index1 = i + 1 + _Number;
int _Index2 = i + 2 + _Number;
if (_Index2 >= _Verts.Count)
{
break;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
_Number++;
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
//余1状态
case 1:
//循环渲染 三角数列
for (int i = 0; i < _Verts.Count; i++)
{
//三角面渲染
int _Index0 = i + _Number;
int _Index1 = i + 1 + _Number;
int _Index2 = i + 2 + _Number;
if (_Index2 >= _Verts.Count - 1)
{
break;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
_Number++;
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
//余2状态
case 2:
//循环渲染 三角数列
for (int i = 0; i < _Verts.Count; i++)
{
//三角面渲染
int _Index0 = i + _Number;
int _Index1 = i + 1 + _Number;
int _Index2 = i + 2 + _Number;
if (_Index2 >= _Verts.Count - 2)
{
break;
}
//存储渲染序列
_Indices.Add(_Index0);
_Indices.Add(_Index1);
_Indices.Add(_Index2);
_Number++;
print(_Index0 + " " + _Index1 + " " + _Index2);
}
break;
default:
break;
}
yield return new WaitForSeconds(0.1f);
}
/// <summary>
/// 初始化
/// </summary>
private void Initialize()
{
_Verts = new List<Vector3>();
_Indices = new List<int>();
if (GetComponent<MeshFilter>() == null)
{
_MeshFilter = transform.gameObject.AddComponent<MeshFilter>();
}
else
{
_MeshFilter = GetComponent<MeshFilter>();
}
if (GetComponent<MeshRenderer>() == null)
{
_MeshRender = transform.gameObject.AddComponent<MeshRenderer>();
}
else
{
_MeshRender = GetComponent<MeshRenderer>();
}
if (GetComponent<MeshCollider>() == null)
{
_MeshCollider = transform.gameObject.AddComponent<MeshCollider>();
}
else
{
_MeshCollider = GetComponent<MeshCollider>();
}
//Generate();
}
bool _isBoom = false;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
_isBoom = !_isBoom;
}
if (Input.GetKeyDown(KeyCode.Q))
{
//碰撞数组
_PointVector3 = new List<Vector3>();
_Vertss.Clear();
for (int i = 0; i < _TransformsPro.Count; i++)
{
Destroy(_TransformsPro[i].gameObject);
}
_TransformsPro.Clear();
//角度数列
int _AngleNumber = 0;
for (int i = 0; i < 361; i++)
{
_AngleNumber += _Angle;
if (_AngleNumber > 360)
{
Generate();
return;
}
else
{
RaycastHit _Hit;
if (Physics.Raycast(transform.position,
new Vector3(transform.position.x + _Radius * Mathf.Cos(_AngleNumber * Mathf.PI / 180), transform.position.y, transform.position.z + _Radius * Mathf.Sin(_AngleNumber * Mathf.PI / 180)), out _Hit))
{
if (_Hit.collider.gameObject.layer== LayerMask.NameToLayer("Valid"))
{
_PointVector3.Add(_Hit.point);
Transform _ProT = Instantiate(_Pro,_Hit.point,Quaternion.identity,transform);
_TransformsPro.Add(_ProT);
_Vertss.Add(_ProT);
}
}
}
//Debug.Log(_AngleNumber);
}
}
}
private void OnDrawGizmos()
{
//Gizmos.DrawWireSphere(transform.position, _Radius);
//Gizmos.DrawLine(transform.position, new Vector3(_Radius * Mathf.Cos(_Angle), transform.position.y, _Radius * Mathf.Sin(_Angle)));
//角度数列
int _AngleNumber = 0;
for (int i = 0; i < 361; i++)
{
_AngleNumber += _Angle;
//_Angle = i;
Gizmos.DrawLine(transform.position, new Vector3(transform.position.x + _Radius * Mathf.Cos(_AngleNumber * Mathf.PI / 180), transform.position.y, transform.position.z + _Radius * Mathf.Sin(_AngleNumber * Mathf.PI / 180)));
if (_AngleNumber>360)
{
return;
}
}
}
}
组件搭载:
运行情况(按Q执行):
最终效果:
暂时先这样吧,如果实在看不明白就留言,看到我会回复的。
路长远兮,与君共勉。