// Hemisphere.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
[System.Serializable]
public struct RADAR
{
[Header("雷达参数")]
public float P_t; // 发射功率(W)
public float G; // 天线增益
public float σ; // 目标截面积(m²)
public float S_min; // 最小可检测信号功率(W)
public float f; // 频率(Hz)
public float c; // 光速
public RADAR(float pT, float g, float sigma, float sMin, float frequency, float speedOfLight)
{
P_t = pT;
G = g;
σ = sigma;
S_min = sMin;
f = frequency;
c = speedOfLight;
}
}
public class Hemisphere : MonoBehaviour
{
[Header("半球设置")]
[SerializeField] private int longitudeSegments = 20;
[SerializeField] private int latitudeSegments = 20;
public float radius;
[Header("扇形设置")]
[SerializeField] public float sectorAngle = Mathf.PI / 2; //扇形高度(弧度)
[Range(3, 30)] [SerializeField] private int sectorSegments = 8;
[SerializeField] public float rotateSpeed = 1f;
[SerializeField] [Range(0.01f, 0.5f)] private float sectorThickness = 0.1f;
[SerializeField] public float ScallopingAngleRadian = 1f; // 扇形宽度(弧度)
[SerializeField] public float initialAngleOffsetAfter = Mathf.PI / 18f; // 第二个扇形从Z轴向左偏转的角度
public float currentRotation = 0f;
private readonly float initialAngleOffset = Mathf.PI / 2f; // 从Z轴正方向开始
// 扫描完成状态标识
public bool IsSweepCompleted { get; private set; }
[Header("雷达参数")]
[SerializeField] public RADAR radarParams;
[Header("渲染设置")]
[SerializeField] private Material hemisphereMaterial;
[SerializeField] private Material sectorMaterial;
[SerializeField] private Material sectorMaterial2; // 第二个扇形的材质,可选
[SerializeField] private Material sideMaterial; // 侧面材质
[Header("碰撞体优化")]
[SerializeField] private int collisionMeshMaxVertices = 16;
// 组件引用 - 第一个扇形
private MeshFilter hemisphereMeshFilter;
private MeshRenderer hemisphereMeshRenderer;
private MeshCollider hemisphereCollider;
private GameObject sectorObject;
private MeshFilter sectorMeshFilter;
private MeshRenderer sectorMeshRenderer;
private MeshCollider sectorCollider;
// 组件引用 - 第二个扇形
private GameObject sectorObject2;
private MeshFilter sectorMeshFilter2;
private MeshRenderer sectorMeshRenderer2;
private MeshCollider sectorCollider2;
// 组件引用 - 侧面连接
private GameObject sideObject;
private MeshFilter sideMeshFilter;
private MeshRenderer sideMeshRenderer;
private MeshCollider sideCollider;
private GameObject zxSectorObject1;
private MeshFilter zxSectorMeshFilter1;
private MeshRenderer zxSectorMeshRenderer1;
private MeshCollider zxSectorCollider1;
private GameObject zxSectorObject2;
private MeshFilter zxSectorMeshFilter2;
private MeshRenderer zxSectorMeshRenderer2;
private MeshCollider zxSectorCollider2;
[Header("Z-X平面扇形Y轴偏移")]
[SerializeField] private float zxSector2YOffset = 1.0f;
// Z-X平面扇形简化碰撞网格(优化性能)
private Mesh simplifiedZxSectorMesh1;
private Mesh simplifiedZxSectorMesh2;
// 跟踪目标信息类
public class TrackedObjectInfo
{
public float lastDetectedAngle; // 最后检测到的角度
public Vector3 lastLocalPosition; // 最后检测到的本地位置
public bool detectedInCurrentSweep = false; // 当前扫描是否被检测到
public int missedSweeps = 0; //未检测到的扫描周期数
}
// 跟踪所有目标的字典
public Dictionary<GameObject, TrackedObjectInfo> trackedObjects = new Dictionary<GameObject, TrackedObjectInfo>();
private float previousRotation = 0f; // 上一帧的旋转角度,用于判断是否完成一圈
private Mesh simplifiedSectorMesh;
private Mesh simplifiedSectorMesh2;
private Mesh simplifiedSideMesh;
void Start()
{
// 初始化雷达默认参数
if (radarParams.c == 0)
{
radarParams = new RADAR(1.0f, 10.0f, 0.01f, 6.3e-9f, 2.4e9f, 3e8f);
}
// 限制参数范围
sectorSegments = Mathf.Max(3, sectorSegments);
collisionMeshMaxVertices = Mathf.Max(3, collisionMeshMaxVertices);
sectorAngle = Mathf.Max(0.01f, sectorAngle);
initialAngleOffsetAfter = Mathf.Max(0.01f, initialAngleOffsetAfter);
// 初始化组件
InitHemisphereComponents();
CreateSector();
CreateSector2(); // 创建第二个扇形
CreateSideObject(); // 创建侧面连接对象
//CreateZxSector1();
CreateZxSector2();
UpdateSector();
UpdateSector2(); // 更新第二个扇形
UpdateSideMesh(); // 更新侧面网格
// 初始化扫描状态
IsSweepCompleted = false;
}
void Update()
{
sectorAngle = Mathf.Max(0.01f, sectorAngle);
initialAngleOffsetAfter = Mathf.Max(0.01f, initialAngleOffsetAfter);
// 更新旋转和网格
previousRotation = currentRotation;
currentRotation = currentRotation - rotateSpeed * Time.deltaTime;
currentRotation = Mathf.Repeat(currentRotation, 2 * Mathf.PI);
UpdateHemisphere();
UpdateSector();
UpdateSector2(); // 更新第二个扇形
UpdateSideMesh(); // 更新侧面网格
//UpdateZxSector1();
UpdateZxSector2();
// 检测是否完成一圈扫描
IsSweepCompleted = currentRotation > previousRotation;
if (IsSweepCompleted)
{
CleanupUntrackedObjects();
}
}
/// <summary>
/// 创建第一个Z-X平面扇形(初始化GameObject与组件)
/// </summary>
public void CreateZxSector1()
{
// 1. 创建扇形GameObject,设置父物体(跟随雷达旋转)
zxSectorObject1 = new GameObject("ZxPlaneSector1");
zxSectorObject1.transform.SetParent(transform);
zxSectorObject1.transform.localPosition = Vector3.zero; // 与雷达中心对齐
// 2. 添加MeshFilter(存储网格)、MeshRenderer(渲染)、MeshCollider(碰撞)
zxSectorMeshFilter1 = zxSectorObject1.AddComponent<MeshFilter>();
zxSectorMeshRenderer1 = zxSectorObject1.AddComponent<MeshRenderer>();
zxSectorCollider1 = zxSectorObject1.AddComponent<MeshCollider>();
// 碰撞体设置:凸包(支持触发器)、启用触发器(用于目标检测)
zxSectorCollider1.convex = true;
zxSectorCollider1.isTrigger = true;
// 3. 赋值材质(优先使用原扇形材质,无则提示)
if (sectorMaterial != null)
zxSectorMeshRenderer1.material = sectorMaterial;
else
Debug.LogWarning("Z-X平面扇形1:请指定sectorMaterial材质");
}
/// <summary>
/// 创建第二个Z-X平面扇形(逻辑与第一个一致,仅角度偏移不同)
/// </summary>
public void CreateZxSector2()
{
zxSectorObject2 = new GameObject("ZxPlaneSector2");
zxSectorObject2.transform.SetParent(transform);
zxSectorObject2.transform.localPosition = Vector3.zero;
zxSectorMeshFilter2 = zxSectorObject2.AddComponent<MeshFilter>();
zxSectorMeshRenderer2 = zxSectorObject2.AddComponent<MeshRenderer>();
zxSectorCollider2 = zxSectorObject2.AddComponent<MeshCollider>();
zxSectorCollider2.convex = true;
zxSectorCollider2.isTrigger = true;
// 材质:优先使用sectorMaterial2,无则复用sectorMaterial
if (sectorMaterial2 != null)
zxSectorMeshRenderer2.material = sectorMaterial2;
else if (sectorMaterial != null)
zxSectorMeshRenderer2.material = sectorMaterial;
else
Debug.LogWarning("Z-X平面扇形2:请指定sectorMaterial或sectorMaterial2材质");
}
/// <summary>
/// 更新第一个Z-X平面扇形(旋转、半径、碰撞体)
/// </summary>
private void UpdateZxSector1()
{
if (radius < 0.1f) return;
// 关键修改:在原有旋转角度基础上,增加向右旋转的偏移(+initialAngleOffsetAfter)
// 向右旋转在数学上表现为角度值增加(Y轴正方向旋转)
float adjustedRotation = currentRotation + initialAngleOffset - initialAngleOffsetAfter;
Mesh displayMesh = GenerateZxPlaneSectorMesh(sectorSegments, radius, adjustedRotation);
zxSectorMeshFilter1.mesh = displayMesh;
Mesh cleanedMesh = CleanMeshVertices(displayMesh);
simplifiedZxSectorMesh1 = SimplifyMesh(cleanedMesh, collisionMeshMaxVertices);
Mesh finalCollisionMesh = IsValidConvexMesh(simplifiedZxSectorMesh1)
? simplifiedZxSectorMesh1
: CreateZxFallbackCollisionMesh(radius, adjustedRotation);
try
{
zxSectorCollider1.sharedMesh = finalCollisionMesh;
}
catch (System.Exception e)
{
Debug.LogWarning($"Z-X扇形1碰撞体设置失败: {e.Message},使用安全备用网格");
zxSectorCollider1.sharedMesh = CreateZxSafeFallbackMesh(radius, adjustedRotation);
}
}
/// <summary>
/// 更新第二个Z-X平面扇形(仅角度偏移不同,其余逻辑与第一个一致)
/// </summary>
private void UpdateZxSector2()
{
if (radius < 0.1f) return;
float adjustedRotation = currentRotation + initialAngleOffset - initialAngleOffsetAfter;
// 使用带Y轴偏移的网格生成函数
Mesh displayMesh = GenerateZxPlaneSector2Mesh(sectorSegments, radius, adjustedRotation);
zxSectorMeshFilter2.mesh = displayMesh;
Mesh cleanedMesh = CleanMeshVertices(displayMesh);
simplifiedZxSectorMesh2 = SimplifyMesh(cleanedMesh, collisionMeshMaxVertices);
// 使用带偏移的备用碰撞网格
Mesh finalCollisionMesh = IsValidConvexMesh(simplifiedZxSectorMesh2)
? simplifiedZxSectorMesh2
: CreateZxSector2FallbackCollisionMesh(radius, adjustedRotation);
try
{
zxSectorCollider2.sharedMesh = finalCollisionMesh;
}
catch (System.Exception e)
{
Debug.LogWarning($"带偏移的Z-X扇形2碰撞体设置失败: {e.Message},使用安全备用网格");
// 安全备用网格也需要添加Y轴偏移
zxSectorCollider2.sharedMesh = CreateZxSector2SafeFallbackMesh(radius, adjustedRotation);
}
}
private Mesh GenerateZxPlaneSector2Mesh(int segments, float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 关键修改:使用initialAngleOffsetAfter作为扇形角度
float angleRange = initialAngleOffsetAfter;
// 外边缘顶点(带Y轴偏移)
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, angleRange, (float)i / segments);
Vector3 baseVertex = new Vector3(
r * Mathf.Cos(angle), // Z坐标
zxSector2YOffset, // Y轴偏移
r * Mathf.Sin(angle) // X坐标
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
int outerVertexCount = segments + 1;
// 内边缘顶点(带Y轴偏移)
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, angleRange, (float)i / segments);
Vector3 baseVertex = new Vector3(
innerRadius * Mathf.Cos(angle),
zxSector2YOffset,
innerRadius * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 中心点(带Y轴偏移)
int centerVertexIndex = outerVertexCount * 2;
Vector3 centerWithOffset = new Vector3(0, zxSector2YOffset, 0);
vertices.Add(RotateAroundYAxis(centerWithOffset, rotationAngle));
// 生成三角形
for (int i = 0; i < segments; i++)
{
triangles.AddRange(new[] { centerVertexIndex, i, i + 1 });
int innerCurrent = outerVertexCount + i;
int innerNext = outerVertexCount + i + 1;
triangles.AddRange(new[] { centerVertexIndex, innerNext, innerCurrent });
triangles.AddRange(new[] { i, innerCurrent, i + 1 });
triangles.AddRange(new[] { i + 1, innerCurrent, innerNext });
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
// 3. 为偏移扇形创建专用备用碰撞网格
private Mesh CreateZxSector2FallbackCollisionMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
int segments = 6;
// 使用initialAngleOffsetAfter作为角度范围
float angleRange = initialAngleOffsetAfter;
float angleStep = angleRange / (segments - 1);
// 外边缘顶点(带Y轴偏移)
for (int i = 0; i < segments; i++)
{
float angle = i * angleStep;
Vector3 baseVertex = new Vector3(
r * Mathf.Cos(angle),
zxSector2YOffset, // Y轴偏移
r * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 内边缘顶点(带Y轴偏移)
int innerOffset = segments;
for (int i = 0; i < segments; i++)
{
float angle = i * angleStep;
Vector3 baseVertex = new Vector3(
innerRadius * Mathf.Cos(angle),
zxSector2YOffset,
innerRadius * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 生成三角形
for (int i = 0; i < segments - 1; i++)
{
triangles.AddRange(new[] { 0, i, i + 1 });
triangles.AddRange(new[] { innerOffset, innerOffset + i + 1, innerOffset + i });
triangles.AddRange(new[] { i, innerOffset + i, i + 1 });
triangles.AddRange(new[] { i + 1, innerOffset + i, innerOffset + i + 1 });
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
return mesh;
}
// 为偏移扇形创建安全备用网格
private Mesh CreateZxSector2SafeFallbackMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 带Y轴偏移的核心顶点
Vector3 centerWithOffset = new Vector3(0, zxSector2YOffset, 0);
vertices.Add(RotateAroundYAxis(centerWithOffset, rotationAngle)); // 中心
vertices.Add(RotateAroundYAxis(new Vector3(r, zxSector2YOffset, 0), rotationAngle)); // 外点1
vertices.Add(RotateAroundYAxis(new Vector3(
r * Mathf.Cos(sectorAngle),
zxSector2YOffset,
r * Mathf.Sin(sectorAngle)
), rotationAngle)); // 外点2
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius, zxSector2YOffset, 0), rotationAngle)); // 内点1
vertices.Add(RotateAroundYAxis(new Vector3(
innerRadius * Mathf.Cos(sectorAngle),
zxSector2YOffset,
innerRadius * Mathf.Sin(sectorAngle)
), rotationAngle)); // 内点2
// 三角形组合
int[] triangles = {
0, 1, 2, // 外扇面
0, 3, 4, // 内扇面
1, 3, 4, // 侧面1
1, 4, 2 // 侧面2
};
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
private Mesh GenerateZxPlaneSectorMesh(int segments, float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 关键修改:使用initialAngleOffsetAfter作为扇形角度,而非sectorAngle
float angleRange = initialAngleOffsetAfter;
// 外边缘顶点
for (int i = 0; i <= segments; i++)
{
// 角度范围从0到initialAngleOffsetAfter
float angle = Mathf.Lerp(0, angleRange, (float)i / segments);
Vector3 baseVertex = new Vector3(
r * Mathf.Cos(angle), // Z坐标
0, // Y坐标
r * Mathf.Sin(angle) // X坐标
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
int outerVertexCount = segments + 1;
// 内边缘顶点
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, angleRange, (float)i / segments);
Vector3 baseVertex = new Vector3(
innerRadius * Mathf.Cos(angle),
0,
innerRadius * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 中心点
int centerVertexIndex = outerVertexCount * 2;
vertices.Add(RotateAroundYAxis(Vector3.zero, rotationAngle));
// 生成三角形
for (int i = 0; i < segments; i++)
{
triangles.AddRange(new[] { centerVertexIndex, i, i + 1 });
int innerCurrent = outerVertexCount + i;
int innerNext = outerVertexCount + i + 1;
triangles.AddRange(new[] { centerVertexIndex, innerNext, innerCurrent });
triangles.AddRange(new[] { i, innerCurrent, i + 1 });
triangles.AddRange(new[] { i + 1, innerCurrent, innerNext });
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
/// <summary>
/// Z-X平面扇形备用碰撞网格(6段简化扇形)
/// </summary>
private Mesh CreateZxFallbackCollisionMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
int segments = 6;
// 使用initialAngleOffsetAfter作为角度范围
float angleRange = initialAngleOffsetAfter;
float angleStep = angleRange / (segments - 1);
// 外边缘顶点
for (int i = 0; i < segments; i++)
{
float angle = i * angleStep;
Vector3 baseVertex = new Vector3(
r * Mathf.Cos(angle),
0,
r * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 内边缘顶点
int innerOffset = segments;
for (int i = 0; i < segments; i++)
{
float angle = i * angleStep;
Vector3 baseVertex = new Vector3(
innerRadius * Mathf.Cos(angle),
0,
innerRadius * Mathf.Sin(angle)
);
vertices.Add(RotateAroundYAxis(baseVertex, rotationAngle));
}
// 生成三角形
for (int i = 0; i < segments - 1; i++)
{
triangles.AddRange(new[] { 0, i, i + 1 });
triangles.AddRange(new[] { innerOffset, innerOffset + i + 1, innerOffset + i });
triangles.AddRange(new[] { i, innerOffset + i, i + 1 });
triangles.AddRange(new[] { i + 1, innerOffset + i, innerOffset + i + 1 });
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
return mesh;
}
/// <summary>
/// Z-X平面扇形安全备用网格(四面体,极端容错)
/// </summary>
private Mesh CreateZxSafeFallbackMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 使用initialAngleOffsetAfter作为角度范围(保持之前的修改)
float angleRange = initialAngleOffsetAfter;
// 核心顶点(应用了向右旋转偏移)
vertices.Add(RotateAroundYAxis(Vector3.zero, rotationAngle)); // 中心
// 外点1(0角度位置)
vertices.Add(RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle));
// 外点2(angleRange角度位置)
vertices.Add(RotateAroundYAxis(new Vector3(
r * Mathf.Cos(angleRange),
0,
r * Mathf.Sin(angleRange)
), rotationAngle));
// 内点1(0角度位置)
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius, 0, 0), rotationAngle));
// 内点2(angleRange角度位置)
vertices.Add(RotateAroundYAxis(new Vector3(
innerRadius * Mathf.Cos(angleRange),
0,
innerRadius * Mathf.Sin(angleRange)
), rotationAngle));
// 三角形组合
int[] triangles = {
0, 1, 2, // 外扇面
0, 3, 4, // 内扇面
1, 3, 4, // 侧面1
1, 4, 2 // 侧面2
};
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
private Vector3 RotateAroundXAxis(Vector3 point, float angle)
{
float cosAngle = Mathf.Cos(angle);
float sinAngle = Mathf.Sin(angle);
// 应用X轴旋转矩阵
return new Vector3(
point.x, // X坐标不变
point.y * cosAngle - point.z * sinAngle, // Y坐标变换
point.y * sinAngle + point.z * cosAngle // Z坐标变换
);
}
private void CleanupUntrackedObjects()
{
List<GameObject> toRemove = new List<GameObject>();
foreach (var it in trackedObjects)
{
if (!it.Value.detectedInCurrentSweep)
{
it.Value.missedSweeps++;
if (it.Value.missedSweeps >= 1)
{
toRemove.Add(it.Key);
}
}
else
{
it.Value.missedSweeps = 0;
}
it.Value.detectedInCurrentSweep = false;
}
foreach (var obj in toRemove)
{
trackedObjects.Remove(obj);
}
}
// 组件初始化
private void InitHemisphereComponents()
{
hemisphereMeshFilter = GetComponent<MeshFilter>() ?? gameObject.AddComponent<MeshFilter>();
hemisphereMeshRenderer = GetComponent<MeshRenderer>() ?? gameObject.AddComponent<MeshRenderer>();
hemisphereCollider = GetComponent<MeshCollider>() ?? gameObject.AddComponent<MeshCollider>();
if (hemisphereMaterial != null)
hemisphereMeshRenderer.material = hemisphereMaterial;
else
Debug.LogWarning("请指定半球材质");
}
private void CreateSector()
{
sectorObject = new GameObject("RotatingSector");
sectorObject.transform.SetParent(transform);
sectorObject.transform.localPosition = Vector3.zero;
sectorMeshFilter = sectorObject.AddComponent<MeshFilter>();
sectorMeshRenderer = sectorObject.AddComponent<MeshRenderer>();
sectorCollider = sectorObject.AddComponent<MeshCollider>();
sectorCollider.convex = true;
sectorCollider.isTrigger = true;
if (sectorMaterial != null)
sectorMeshRenderer.material = sectorMaterial;
else
Debug.LogWarning("请指定扇形材质");
}
// 创建第二个扇形
private void CreateSector2()
{
sectorObject2 = new GameObject("RotatingSector2");
sectorObject2.transform.SetParent(transform);
sectorObject2.transform.localPosition = Vector3.zero;
sectorMeshFilter2 = sectorObject2.AddComponent<MeshFilter>();
sectorMeshRenderer2 = sectorObject2.AddComponent<MeshRenderer>();
sectorCollider2 = sectorObject2.AddComponent<MeshCollider>();
sectorCollider2.convex = true;
sectorCollider2.isTrigger = true;
// 使用指定的第二个材质或默认使用第一个材质
if (sectorMaterial2 != null)
sectorMeshRenderer2.material = sectorMaterial2;
else if (sectorMaterial != null)
sectorMeshRenderer2.material = sectorMaterial;
else
Debug.LogWarning("请指定扇形材质");
}
// 创建侧面连接对象
private void CreateSideObject()
{
sideObject = new GameObject("SideConnection");
sideObject.transform.SetParent(transform);
sideObject.transform.localPosition = Vector3.zero;
sideMeshFilter = sideObject.AddComponent<MeshFilter>();
sideMeshRenderer = sideObject.AddComponent<MeshRenderer>();
sideCollider = sideObject.AddComponent<MeshCollider>();
sideCollider.convex = true;
sideCollider.isTrigger = true;
if (sideMaterial != null)
sideMeshRenderer.material = sideMaterial;
else if (sectorMaterial != null)
sideMeshRenderer.material = sectorMaterial;
else
Debug.LogWarning("请指定侧面材质");
}
public void UpdateHemisphere()
{
radius = Mathf.Max(0.1f, RadarScanningRadius(radarParams));
Mesh mesh = GenerateHemisphereMesh(longitudeSegments, latitudeSegments, radius);
hemisphereCollider.sharedMesh = mesh;
hemisphereMeshFilter.mesh = mesh;
}
public void UpdateSector()
{
if (radius < 0.1f) return;
float adjustedRotation = currentRotation + initialAngleOffset;
Mesh displayMesh = GenerateSectorMesh(sectorSegments, radius, adjustedRotation);
sectorMeshFilter.mesh = displayMesh;
// 处理碰撞体网格
Mesh cleanedMesh = CleanMeshVertices(displayMesh);
simplifiedSectorMesh = SimplifyMesh(cleanedMesh, collisionMeshMaxVertices);
Mesh finalCollisionMesh = IsValidConvexMesh(simplifiedSectorMesh)
? simplifiedSectorMesh
: CreateFallbackCollisionMesh(radius, adjustedRotation);
try
{
sectorCollider.sharedMesh = finalCollisionMesh;
}
catch (System.Exception e)
{
Debug.LogWarning($"碰撞体设置失败: {e.Message},使用备用网格");
sectorCollider.sharedMesh = CreateSafeFallbackMesh(radius, adjustedRotation);
}
}
// 更新第二个扇形
private void UpdateSector2()
{
if (radius < 0.1f) return;
// 第二个扇形从Z轴向左偏转initialAngleOffsetAfter弧度
float adjustedRotation = currentRotation + initialAngleOffset - initialAngleOffsetAfter;
Mesh displayMesh = GenerateSectorMesh(sectorSegments, radius, adjustedRotation);
sectorMeshFilter2.mesh = displayMesh;
// 处理碰撞体网格
Mesh cleanedMesh = CleanMeshVertices(displayMesh);
simplifiedSectorMesh2 = SimplifyMesh(cleanedMesh, collisionMeshMaxVertices);
Mesh finalCollisionMesh = IsValidConvexMesh(simplifiedSectorMesh2)
? simplifiedSectorMesh2
: CreateFallbackCollisionMesh(radius, adjustedRotation);
try
{
sectorCollider2.sharedMesh = finalCollisionMesh;
}
catch (System.Exception e)
{
Debug.LogWarning($"第二个扇形碰撞体设置失败: {e.Message},使用备用网格");
sectorCollider2.sharedMesh = CreateSafeFallbackMesh(radius, adjustedRotation);
}
}
// 更新侧面连接网格
private void UpdateSideMesh()
{
if (radius < 0.1f) return;
float adjustedRotation1 = currentRotation + initialAngleOffset;
float adjustedRotation2 = currentRotation + initialAngleOffset - initialAngleOffsetAfter;
Mesh sideMesh = GenerateSideConnectionMesh(sectorSegments, radius, adjustedRotation1, adjustedRotation2);
sideMeshFilter.mesh = sideMesh;
// 处理碰撞体网格
Mesh cleanedMesh = CleanMeshVertices(sideMesh);
simplifiedSideMesh = SimplifySideMesh(cleanedMesh, collisionMeshMaxVertices);
Mesh finalCollisionMesh = IsValidConvexMesh(simplifiedSideMesh)
? simplifiedSideMesh
: CreateSideFallbackCollisionMesh(radius, adjustedRotation1, adjustedRotation2);
try
{
sideCollider.sharedMesh = finalCollisionMesh;
}
catch (System.Exception e)
{
Debug.LogWarning($"侧面碰撞体设置失败: {e.Message},使用备用网格");
sideCollider.sharedMesh = CreateSideSafeFallbackMesh(radius, adjustedRotation1, adjustedRotation2);
}
}
private Mesh GenerateHemisphereMesh(int lonSeg, int latSeg, float r)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
// 生成顶点
for (int i = 0; i <= lonSeg; i++)
{
float lonAngle = Mathf.Lerp(0, 2 * Mathf.PI, (float)i / lonSeg);
for (int j = 0; j <= latSeg; j++)
{
float latAngle = Mathf.PI / 2 * (1 - (float)j / latSeg);
vertices.Add(new Vector3(
r * Mathf.Sin(latAngle) * Mathf.Cos(lonAngle),
r * Mathf.Cos(latAngle),
r * Mathf.Sin(latAngle) * Mathf.Sin(lonAngle)
));
}
}
// 生成三角形
for (int i = 0; i < lonSeg; i++)
{
for (int j = 0; j < latSeg; j++)
{
int topLeft = i * (latSeg + 1) + j;
int topRight = (i + 1) * (latSeg + 1) + j;
int bottomLeft = i * (latSeg + 1) + (j + 1);
int bottomRight = (i + 1) * (latSeg + 1) + (j + 1);
triangles.AddRange(new[] { topLeft, bottomLeft, topRight, topRight, bottomLeft, bottomRight });
}
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
return mesh;
}
private Mesh GenerateSectorMesh(int segments, float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 外边缘顶点
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, sectorAngle, (float)i / segments);
vertices.Add(RotateAroundYAxis(new Vector3(r * Mathf.Cos(angle), r * Mathf.Sin(angle), 0), rotationAngle));
}
int outerCount = segments + 1;
// 内边缘顶点
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, sectorAngle, (float)i / segments);
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(angle), innerRadius * Mathf.Sin(angle), 0), rotationAngle));
}
// 中心点
int originIndex = outerCount * 2;
vertices.Add(RotateAroundYAxis(Vector3.zero, rotationAngle));
// 生成三角形
for (int i = 0; i < segments; i++)
{
// 外扇形面
triangles.AddRange(new[] { originIndex, i, i + 1 });
// 内扇形面
triangles.AddRange(new[] { originIndex, outerCount + i + 1, outerCount + i });
// 侧面
triangles.AddRange(new[] { i, outerCount + i, i + 1 });
triangles.AddRange(new[] { i + 1, outerCount + i, outerCount + i + 1 });
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
// 生成连接两个扇形的侧面网格
private Mesh GenerateSideConnectionMesh(int segments, float r, float rotationAngle1, float rotationAngle2)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 获取第一个扇形的顶点
List<Vector3> sector1Outer = new List<Vector3>();
List<Vector3> sector1Inner = new List<Vector3>();
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, sectorAngle, (float)i / segments);
sector1Outer.Add(RotateAroundYAxis(new Vector3(r * Mathf.Cos(angle), r * Mathf.Sin(angle), 0), rotationAngle1));
sector1Inner.Add(RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(angle), innerRadius * Mathf.Sin(angle), 0), rotationAngle1));
}
// 获取第二个扇形的顶点
List<Vector3> sector2Outer = new List<Vector3>();
List<Vector3> sector2Inner = new List<Vector3>();
for (int i = 0; i <= segments; i++)
{
float angle = Mathf.Lerp(0, sectorAngle, (float)i / segments);
sector2Outer.Add(RotateAroundYAxis(new Vector3(r * Mathf.Cos(angle), r * Mathf.Sin(angle), 0), rotationAngle2));
sector2Inner.Add(RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(angle), innerRadius * Mathf.Sin(angle), 0), rotationAngle2));
}
// 添加顶点
vertices.AddRange(sector1Outer);
vertices.AddRange(sector1Inner);
vertices.AddRange(sector2Outer);
vertices.AddRange(sector2Inner);
int sector1OuterStart = 0;
int sector1InnerStart = segments + 1;
int sector2OuterStart = (segments + 1) * 2;
int sector2InnerStart = (segments + 1) * 3;
// 生成连接两个扇形外侧的三角形
for (int i = 0; i < segments; i++)
{
triangles.Add(sector1OuterStart + i);
triangles.Add(sector2OuterStart + i);
triangles.Add(sector1OuterStart + i + 1);
triangles.Add(sector1OuterStart + i + 1);
triangles.Add(sector2OuterStart + i);
triangles.Add(sector2OuterStart + i + 1);
}
// 生成连接两个扇形内侧的三角形
for (int i = 0; i < segments; i++)
{
triangles.Add(sector1InnerStart + i);
triangles.Add(sector1InnerStart + i + 1);
triangles.Add(sector2InnerStart + i);
triangles.Add(sector1InnerStart + i + 1);
triangles.Add(sector2InnerStart + i + 1);
triangles.Add(sector2InnerStart + i);
}
// 生成连接两个扇形端面的三角形
triangles.Add(sector1OuterStart);
triangles.Add(sector1InnerStart);
triangles.Add(sector2OuterStart);
triangles.Add(sector1InnerStart);
triangles.Add(sector2InnerStart);
triangles.Add(sector2OuterStart);
triangles.Add(sector1OuterStart + segments);
triangles.Add(sector2OuterStart + segments);
triangles.Add(sector1InnerStart + segments);
triangles.Add(sector1InnerStart + segments);
triangles.Add(sector2OuterStart + segments);
triangles.Add(sector2InnerStart + segments);
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
mesh.RecalculateBounds();
return mesh;
}
private Mesh CleanMeshVertices(Mesh originalMesh)
{
Mesh cleanedMesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
Dictionary<Vector3, int> vertexMap = new Dictionary<Vector3, int>();
List<int> newTriangles = new List<int>();
// 顶点去重
foreach (Vector3 v in originalMesh.vertices)
{
Vector3 rounded = new Vector3(
Mathf.Round(v.x * 10000) / 10000,
Mathf.Round(v.y * 10000) / 10000,
Mathf.Round(v.z * 10000) / 10000
);
if (!vertexMap.ContainsKey(rounded))
{
vertexMap[rounded] = vertices.Count;
vertices.Add(rounded);
}
}
// 过滤无效三角形
int[] originalTris = originalMesh.triangles;
for (int i = 0; i < originalTris.Length; i += 3)
{
Vector3 p0 = originalMesh.vertices[originalTris[i]];
Vector3 p1 = originalMesh.vertices[originalTris[i + 1]];
Vector3 p2 = originalMesh.vertices[originalTris[i + 2]];
// 过滤面积过小的三角形
if (Vector3.Cross(p1 - p0, p2 - p0).magnitude < 0.0001f)
continue;
// 映射新顶点索引
if (TryGetMappedIndex(vertexMap, p0, out int n0) &&
TryGetMappedIndex(vertexMap, p1, out int n1) &&
TryGetMappedIndex(vertexMap, p2, out int n2))
{
newTriangles.AddRange(new[] { n0, n1, n2 });
}
}
cleanedMesh.vertices = vertices.ToArray();
cleanedMesh.triangles = newTriangles.ToArray();
cleanedMesh.RecalculateNormals();
cleanedMesh.RecalculateBounds();
return cleanedMesh;
}
private Mesh SimplifyMesh(Mesh originalMesh, int maxVertices)
{
maxVertices = Mathf.Clamp(maxVertices, 3, 30);
if (originalMesh.vertexCount <= maxVertices)
return originalMesh;
Mesh simplified = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float totalAngle = sectorAngle;
float angleStep = totalAngle / (maxVertices - 1);
int halfCount = originalMesh.vertexCount / 2;
// 采样外边缘顶点
for (int i = 0; i < maxVertices / 2; i++)
{
int index = FindClosestVertexByAngle(originalMesh.vertices, 0, halfCount, i * angleStep, currentRotation + initialAngleOffset);
vertices.Add(originalMesh.vertices[index]);
int inde1x = FindClosestVertexByAngle(originalMesh.vertices, 0, halfCount, i * angleStep, currentRotation + initialAngleOffsetAfter);
vertices.Add(originalMesh.vertices[inde1x]);
}
// 采样内边缘顶点
for (int i = 0; i < maxVertices - vertices.Count; i++)
{
int index = FindClosestVertexByAngle(originalMesh.vertices, halfCount, originalMesh.vertexCount, i * angleStep, currentRotation + initialAngleOffset);
vertices.Add(originalMesh.vertices[index]);
int inde1x = FindClosestVertexByAngle(originalMesh.vertices, halfCount, originalMesh.vertexCount, i * angleStep, currentRotation + initialAngleOffsetAfter);
vertices.Add(originalMesh.vertices[inde1x]);
}
// 确保顶点数量不超标
if (vertices.Count > maxVertices)
vertices.RemoveRange(maxVertices, vertices.Count - maxVertices);
// 按角度排序
vertices.Sort((a, b) =>
Mathf.Atan2(a.z, a.x).CompareTo(Mathf.Atan2(b.z, b.x))
);
GenerateConvexTriangles(vertices, triangles);
simplified.vertices = vertices.ToArray();
simplified.triangles = triangles.ToArray();
simplified.RecalculateNormals();
simplified.RecalculateBounds();
return simplified;
}
// 简化侧面网格
private Mesh SimplifySideMesh(Mesh originalMesh, int maxVertices)
{
maxVertices = Mathf.Clamp(maxVertices, 6, 30);
if (originalMesh.vertexCount <= maxVertices)
return originalMesh;
// 对于侧面网格,我们只需要保留关键顶点
Mesh simplified = new Mesh();
List<Vector3> vertices = new List<Vector3>();
// 获取原始网格的边界点
Bounds bounds = originalMesh.bounds;
vertices.Add(bounds.min);
vertices.Add(new Vector3(bounds.min.x, bounds.min.y, bounds.max.z));
vertices.Add(new Vector3(bounds.max.x, bounds.min.y, bounds.min.z));
vertices.Add(bounds.max);
vertices.Add(new Vector3(bounds.min.x, bounds.max.y, bounds.min.z));
vertices.Add(new Vector3(bounds.max.x, bounds.max.y, bounds.min.z));
vertices.Add(new Vector3(bounds.min.x, bounds.max.y, bounds.max.z));
vertices.Add(bounds.max);
// 生成凸包三角形
List<int> triangles = new List<int>();
GenerateConvexTriangles(vertices, triangles);
simplified.vertices = vertices.ToArray();
simplified.triangles = triangles.ToArray();
simplified.RecalculateNormals();
simplified.RecalculateBounds();
return simplified;
}
private bool IsValidConvexMesh(Mesh mesh)
{
if (!IsValidCollisionMesh(mesh)) return false;
// 检查法向量一致性
Vector3[] normals = mesh.normals;
if (normals.Length == 0) return false;
Vector3 firstNormal = normals[0];
foreach (Vector3 normal in normals)
{
if (Vector3.Dot(firstNormal, normal) < 0.9f)
return false;
}
return true;
}
private bool IsValidCollisionMesh(Mesh mesh)
{
if (mesh == null || mesh.vertexCount < 3 || mesh.triangles.Length < 3)
return false;
// 检查至少有3个不同顶点
HashSet<Vector3> uniqueVertices = new HashSet<Vector3>();
foreach (Vector3 v in mesh.vertices)
{
uniqueVertices.Add(v);
if (uniqueVertices.Count >= 3) break;
}
return uniqueVertices.Count >= 3;
}
private Mesh CreateFallbackCollisionMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
int segments = 6;
float VerticalAngleStep = sectorAngle / (segments - 1);//竖直角度步长
// 外边缘顶点
for (int i = 0; i < segments; i++)
{
float angle = i * VerticalAngleStep;
vertices.Add(RotateAroundYAxis(new Vector3(r * Mathf.Cos(angle), 0, r * Mathf.Sin(angle)), rotationAngle));
}
// 内边缘顶点
int innerOffset = segments;
for (int i = 0; i < segments; i++)
{
float angle = i * VerticalAngleStep;
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(angle), 0, innerRadius * Mathf.Sin(angle)), rotationAngle));
}
// 生成三角形
for (int i = 0; i < segments - 1; i++)
{
triangles.AddRange(new[] { 0, i, i + 1 }); // 外扇面
triangles.AddRange(new[] { innerOffset, innerOffset + i + 1, innerOffset + i }); // 内扇面
triangles.AddRange(new[] { i, innerOffset + i, i + 1 }); // 侧面1
triangles.AddRange(new[] { i + 1, innerOffset + i, innerOffset + i + 1 }); // 侧面2
}
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
return mesh;
}
private Mesh CreateSafeFallbackMesh(float r, float rotationAngle)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 核心顶点
vertices.Add(Vector3.zero); // 中心
vertices.Add(RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle)); // 外点1
vertices.Add(RotateAroundYAxis(new Vector3(r * Mathf.Cos(sectorAngle), 0, r * Mathf.Sin(sectorAngle)), rotationAngle)); // 外点2
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius, 0, 0), rotationAngle)); // 内点1
vertices.Add(RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(sectorAngle), 0, innerRadius * Mathf.Sin(sectorAngle)), rotationAngle)); // 内点2
// 简单三角形组合
int[] triangles = {
0, 1, 2, // 外扇面
0, 3, 4, // 内扇面
1, 3, 4, // 侧面1
1, 4, 2 // 侧面2
};
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
// 创建侧面备用碰撞体网格
private Mesh CreateSideFallbackCollisionMesh(float r, float rotationAngle1, float rotationAngle2)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
float innerRadius = Mathf.Max(0.1f, r * (1 - sectorThickness));
// 获取关键点
Vector3 outer1Start = RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle1);
Vector3 outer1End = RotateAroundYAxis(new Vector3(r * Mathf.Cos(sectorAngle), 0, r * Mathf.Sin(sectorAngle)), rotationAngle1);
Vector3 inner1Start = RotateAroundYAxis(new Vector3(innerRadius, 0, 0), rotationAngle1);
Vector3 inner1End = RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(sectorAngle), 0, innerRadius * Mathf.Sin(sectorAngle)), rotationAngle1);
Vector3 outer2Start = RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle2);
Vector3 outer2End = RotateAroundYAxis(new Vector3(r * Mathf.Cos(sectorAngle), 0, r * Mathf.Sin(sectorAngle)), rotationAngle2);
Vector3 inner2Start = RotateAroundYAxis(new Vector3(innerRadius, 0, 0), rotationAngle2);
Vector3 inner2End = RotateAroundYAxis(new Vector3(innerRadius * Mathf.Cos(sectorAngle), 0, innerRadius * Mathf.Sin(sectorAngle)), rotationAngle2);
// 添加顶点
vertices.Add(outer1Start);
vertices.Add(outer1End);
vertices.Add(inner1Start);
vertices.Add(inner1End);
vertices.Add(outer2Start);
vertices.Add(outer2End);
vertices.Add(inner2Start);
vertices.Add(inner2End);
// 生成连接三角形
triangles.AddRange(new[] { 0, 4, 1 }); // 外侧面1
triangles.AddRange(new[] { 1, 4, 5 }); // 外侧面2
triangles.AddRange(new[] { 2, 3, 6 }); // 内侧面1
triangles.AddRange(new[] { 3, 7, 6 }); // 内侧面2
triangles.AddRange(new[] { 0, 2, 4 }); // 起始端面1
triangles.AddRange(new[] { 2, 6, 4 }); // 起始端面2
triangles.AddRange(new[] { 1, 5, 3 }); // 结束端面1
triangles.AddRange(new[] { 3, 5, 7 }); // 结束端面2
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
return mesh;
}
private Mesh CreateSideSafeFallbackMesh(float r, float rotationAngle1, float rotationAngle2)
{
Mesh mesh = new Mesh();
List<Vector3> vertices = new List<Vector3>();
// 简单的四面体作为备用
Vector3 center = Vector3.zero;
Vector3 outer1 = RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle1);
Vector3 outer2 = RotateAroundYAxis(new Vector3(r, 0, 0), rotationAngle2);
Vector3 top = Vector3.up * r * 0.5f;
vertices.Add(center);
vertices.Add(outer1);
vertices.Add(outer2);
vertices.Add(top);
int[] triangles = {
0, 1, 2,
0, 1, 3,
0, 2, 3,
1, 2, 3
};
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
private float RadarScanningRadius(RADAR radar)
{
if (radar.f <= 0 || radar.S_min <= 0)
{
Debug.LogWarning("雷达参数错误,使用默认半径");
return 10f;
}
float wavelength = radar.c / radar.f;
float numerator = radar.P_t * Mathf.Pow(radar.G, 2) * wavelength * radar.σ;
float denominator = Mathf.Pow(4 * Mathf.PI, 3) * radar.S_min;
if (denominator <= 0 || numerator <= 0)
{
Debug.LogWarning("雷达参数无效,使用默认半径");
return 10f;
}
return Mathf.Max(0.1f, Mathf.Pow(numerator / denominator, 1f / 4f));
}
private Vector3 RotateAroundYAxis(Vector3 point, float angle)
{
float cos = Mathf.Cos(angle);
float sin = Mathf.Sin(angle);
return new Vector3(
point.x * cos - point.z * sin,
point.y,
point.x * sin + point.z * cos
);
}
private int FindClosestVertexByAngle(Vector3[] vertices, int start, int end, float targetAngle, float rotation)
{
int closestIndex = start;
float minDiff = float.MaxValue;
for (int i = start; i < end; i++)
{
Vector3 localPos = Quaternion.Inverse(Quaternion.Euler(0, rotation * Mathf.Rad2Deg, 0)) * vertices[i];
float angle = Mathf.Repeat(Mathf.Atan2(localPos.z, localPos.x), 2 * Mathf.PI);
float diff = Mathf.Abs(angle - targetAngle);
if (diff < minDiff)
{
minDiff = diff;
closestIndex = i;
}
}
return closestIndex;
}
private void GenerateConvexTriangles(List<Vector3> vertices, List<int> triangles)
{
if (vertices.Count < 3) return;
// 生成三角形扇
int center = 0;
for (int i = 1; i < vertices.Count - 1; i++)
{
triangles.AddRange(new[] { center, i, i + 1 });
}
// 闭合最后一个三角形
if (vertices.Count > 3)
triangles.AddRange(new[] { center, vertices.Count - 1, 1 });
}
private bool TryGetMappedIndex(Dictionary<Vector3, int> map, Vector3 original, out int index)
{
Vector3 rounded = new Vector3(
Mathf.Round(original.x * 10000) / 10000,
Mathf.Round(original.y * 10000) / 10000,
Mathf.Round(original.z * 10000) / 10000
);
return map.TryGetValue(rounded, out index);
}
// 第一个扇形的碰撞检测
private void OnTriggerStay(Collider other)
{
CheckAndTrackObject(other);
}
// 第二个扇形的碰撞检测
private void OnTriggerStay2(Collider other)
{
CheckAndTrackObject(other);
}
// 统一的碰撞检测和目标跟踪逻辑
private void CheckAndTrackObject(Collider other)
{
if (other is BoxCollider)
{
GameObject detectedObj = other.gameObject;
// 目标相对于雷达的本地坐标
Vector3 localPos = transform.InverseTransformPoint(detectedObj.transform.position);
float X = Mathf.Abs(localPos.x);
float Y = Mathf.Abs(localPos.y);
float Z = Mathf.Abs(localPos.z);
float projectionLength = Mathf.Sqrt(X * X + Z * Z);
float angleWithXZPlane;
if (projectionLength < Mathf.Epsilon)
{
angleWithXZPlane = Mathf.PI / 2;
}
else
{
angleWithXZPlane = Mathf.Atan2(Mathf.Abs(Y), projectionLength);
}
float targetAngle = Mathf.Atan2(localPos.z, localPos.x);
// 检查是否在第一个扇形范围内
float adjustedRotation1 = currentRotation + initialAngleOffset;
float sectorStartAngle1 = adjustedRotation1;
float sectorEndAngle1 = adjustedRotation1 + sectorAngle;
// 检查是否在第二个扇形范围内
float adjustedRotation2 = currentRotation + initialAngleOffset - initialAngleOffsetAfter;
float sectorStartAngle2 = adjustedRotation2;
float sectorEndAngle2 = adjustedRotation2 + sectorAngle;
// 限制角度0-2PI
targetAngle = Mathf.Repeat(targetAngle, 2 * Mathf.PI);
sectorStartAngle1 = Mathf.Repeat(sectorStartAngle1, 2 * Mathf.PI);
sectorEndAngle1 = Mathf.Repeat(sectorEndAngle1, 2 * Mathf.PI);
sectorStartAngle2 = Mathf.Repeat(sectorStartAngle2, 2 * Mathf.PI);
sectorEndAngle2 = Mathf.Repeat(sectorEndAngle2, 2 * Mathf.PI);
// 检查是否在任何一个扇形内
bool isInSector1 = false;
if (sectorStartAngle1 <= sectorEndAngle1)
{
isInSector1 = targetAngle >= sectorStartAngle1 && targetAngle <= sectorEndAngle1;
}
else
{
isInSector1 = targetAngle >= sectorStartAngle1 || targetAngle <= sectorEndAngle1;
}
bool isInSector2 = false;
if (sectorStartAngle2 <= sectorEndAngle2)
{
isInSector2 = targetAngle >= sectorStartAngle2 && targetAngle <= sectorEndAngle2;
}
else
{
isInSector2 = targetAngle >= sectorStartAngle2 || targetAngle <= sectorEndAngle2;
}
bool isInSector = isInSector1 || isInSector2;
bool isInRange = localPos.magnitude <= radius;
bool isradian = 0 <= angleWithXZPlane && angleWithXZPlane <= sectorAngle;
if (isInSector && isInRange && isradian)
{
if (!trackedObjects.ContainsKey(detectedObj))
{
trackedObjects[detectedObj] = new TrackedObjectInfo();
}
TrackedObjectInfo info = trackedObjects[detectedObj];
info.lastDetectedAngle = currentRotation;
info.lastLocalPosition = localPos; // 本地坐标
info.detectedInCurrentSweep = true;
info.missedSweeps = 0;
}
}
}
private void OnDestroy()
{
if (simplifiedSectorMesh != null)
Destroy(simplifiedSectorMesh);
if (simplifiedSectorMesh2 != null)
Destroy(simplifiedSectorMesh2);
if (sectorObject != null)
Destroy(sectorObject);
if (sectorObject2 != null)
Destroy(sectorObject2);
if (simplifiedZxSectorMesh1 != null) Destroy(simplifiedZxSectorMesh1);
if (simplifiedZxSectorMesh2 != null) Destroy(simplifiedZxSectorMesh2);
if (zxSectorObject1 != null) Destroy(zxSectorObject1);
if (zxSectorObject2 != null) Destroy(zxSectorObject2);
}
// 获取当前检测到的目标的本地坐标
public Dictionary<GameObject, Vector3> GetCurrentlyDetectedLocalPositions()
{
return trackedObjects.Where(it => it.Value.detectedInCurrentSweep)
.ToDictionary(it => it.Key, it => it.Value.lastLocalPosition);
}
// 获取所有跟踪目标的最后本地坐标
public Dictionary<GameObject, Vector3> GetAllTrackedLocalPositions()
{
return trackedObjects.ToDictionary(it => it.Key, it => it.Value.lastLocalPosition);
}
public float RadianTo360Degree()
{
return Mathf.Rad2Deg * currentRotation;
}
public void StartRotation()
{
currentRotation = 0; // 重置旋转角度
enabled = true;
}
}目前生成的是0-90纬度的半球,保留0-45度的部分
最新发布