C. Count Triangles

该问题要求计算在给定整数限制A, B, C, D之间,有多少种不同的非退化三角形(x, y, z)组合,其中A <= x <= B <= y <= C <= z <= D。输入包含四个整数A, B, C, D,输出为符合条件的三角形数量。例子展示了不同A, B, C, D值下的三角形计数情况。" 121679627,11417367,STM32移植uCOSIII到HAL库实战指南,"['STM32开发', '嵌入式系统', 'RTOS', 'HAL库', '单片机编程']

链接:https://codeforces.com/contest/1355/problem/C

Like any unknown mathematician, Yuri has favourite numbers: AA, BB, CC, and DD, where A≤B≤C≤DA≤B≤C≤D. Yuri also likes triangles and once he thought: how many non-degenerate triangles with integer sides xx, yy, and zz exist, such that A≤x≤B≤y≤C≤z≤DA≤x≤B≤y≤C≤z≤D holds?

Yuri is preparing problems for a new contest now, so he is very busy. That's why he asked you to calculate the number of triangles with described property.

The triangle is called non-degenerate if and only if its vertices are not collinear.

Input

The first line contains four integers: AA, BB, CC and DD (1≤A≤B≤C≤D≤5⋅1051≤A≤B≤C≤D≤5⋅105) — Yuri's favourite numbers.

Output

Print the number of non-degenerate triangles with integer sides xx, yy, and zz such that the inequality A≤x≤B≤y≤C≤z≤DA≤x≤B≤y≤C≤z≤D holds.

Examples

input

Copy

1 2 3 4

output

Copy

4

input

Copy

1 2 2 5

output

Copy

3

input

Copy

500000 500000 500000 500000

output

Copy

1

Note

In the first example Yuri can make up triangles with sides (1,3,3)(1,3,3), (2,2,3)(2,2,3), (2,3,3)(2,3,3) and (2,3,4)(2,3,4).

In the second example Yuri can make up triangles with sides (1,2,2)(1,2,2), (2,2,2)(2,2,2) and (2,2,3)(2,2,3).

In the third example Yuri can make up only one equilateral triangle with sides equal to 5⋅1055⋅105.

qlsNB!!!

代码:

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include<iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#define ll long long
#define rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
ll n,m,t,k,s,z,y,l,r,ans;
ll a,b,c,d;
int main()
{
	cin>>a>>b>>c>>d;
	ans=0;
	for(ll i=max(a+b,c+1);i<=b+c;i++)
	{
		l=max(a,i-c);
		r=min(b,i-b);
		if(l<=r)
		{
			ans+=(r-l+1)*(min(i-1,d)-c+1);
		}
	}
	cout<<ans;
}
 

 

// 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度的部分
09-18
这个方法是用来处理模型互相碰撞检测的脚本,帮我修改成支持多线程运行,来提高性能: // Assets/Scripts/RuntimeInterpenetrationChecker/InterpenetrationChecker.cs using System.Collections.Generic; using UnityEngine; using Unity.Collections; using Unity.Mathematics; using float3 = Unity.Mathematics.float3; namespace RuntimeInterpenetrationChecker { public class InterpenetrationChecker : MonoBehaviour { public List<GameObject> targetModels = new List<GameObject>(); public struct DetailedResult { public GameObject sourceObject; public GameObject targetObject; public bool hasInterpenetration => sourceObject != null && targetObject != null; } // ──────────────────────────────────────── // 内部数据结构 // ──────────────────────────────────────── private class SubMeshData { public GameObject owner; public NativeArray<float3> vertices; public NativeArray<int> triangles; public bool valid => vertices.IsCreated && triangles.IsCreated; public void Dispose() { if (vertices.IsCreated) vertices.Dispose(); if (triangles.IsCreated) triangles.Dispose(); } } private class ModelData { public GameObject root; public List<SubMeshData> subMeshes = new List<SubMeshData>(); } public void CheckDetailed(System.Action<List<DetailedResult>> callback = null) { if (targetModels == null || targetModels.Count < 2) { callback?.Invoke(new List<DetailedResult>()); return; } // Step 1: 提取所有模型及其子部件 var allModels = new List<ModelData>(); foreach (var root in targetModels) { if (root != null) { allModels.Add(ExtractModel(root)); } } // Step 2: 两两模型之间进行子部件交叉检测 var results = new List<DetailedResult>(); for (int i = 0; i < allModels.Count ; i++) { for (int j = i + 1; j < allModels.Count; j++) { var modelA = allModels[i]; var modelB = allModels[j]; foreach (var subA in modelA.subMeshes) { foreach (var subB in modelB.subMeshes) { if (CheckTriangleIntersection(subA.vertices, subA.triangles, subB.vertices, subB.triangles)) { results.Add(new DetailedResult { sourceObject = subA.owner, targetObject = subB.owner }); } } } } } // Step 3: 清理 Native 内存 foreach (var model in allModels) { foreach (var sub in model.subMeshes) { sub.Dispose(); } } callback?.Invoke(results); } // ──────────────────────────────────────── // 提取一个逻辑模型下的所有有效子网格 // ──────────────────────────────────────── private ModelData ExtractModel(GameObject root) { var model = new ModelData { root = root }; var subMeshes = new List<SubMeshData>(); // 1. 静态网格:MeshRenderer + MeshFilter var meshRenderers = root.GetComponentsInChildren<MeshRenderer>(true); foreach (var mr in meshRenderers) { if (!mr.gameObject.activeInHierarchy) continue; var mf = mr.GetComponent<MeshFilter>(); if (mf == null || mf.sharedMesh == null || mf.sharedMesh.vertexCount == 0) continue; var data = CreateSubMeshData(mf.sharedMesh, mr.transform.localToWorldMatrix, mr.gameObject); if (data != null) subMeshes.Add(data); } // 2. 蒙皮网格:SkinnedMeshRenderer var skinnedRenderers = root.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (var smr in skinnedRenderers) { if (!smr.gameObject.activeInHierarchy) continue; var bakedMesh = new Mesh(); smr.BakeMesh(bakedMesh, false); // false = bind pose; true = current pose if (bakedMesh.vertexCount == 0) { Object.Destroy(bakedMesh); continue; } var data = CreateSubMeshData(bakedMesh, smr.transform.localToWorldMatrix, smr.gameObject); Object.Destroy(bakedMesh); // 立即销毁临时 mesh if (data != null) subMeshes.Add(data); } model.subMeshes = subMeshes; return model; } // ──────────────────────────────────────── // 创建单个子网格数据(带世界坐标转换) // ──────────────────────────────────────── private SubMeshData CreateSubMeshData(Mesh mesh, Matrix4x4 worldMatrix, GameObject owner) { try { var vertices = new NativeArray<float3>(mesh.vertexCount, Allocator.Persistent); var originalVerts = mesh.vertices; for (int i = 0; i < originalVerts.Length; i++) { vertices[i] = math.mul(worldMatrix, new float4(originalVerts[i], 1)).xyz; } var triangles = new NativeArray<int>(mesh.triangles, Allocator.Persistent); return new SubMeshData { owner = owner, vertices = vertices, triangles = triangles }; } catch (System.Exception ex) { Debug.LogError($"创建子网格数据失败: {ex.Message}", owner); return null; } } // ──────────────────────────────────────── // 三角形-三角形精确相交检测 // ──────────────────────────────────────── private bool CheckTriangleIntersection( NativeArray<float3> vertsA, NativeArray<int> trisA, NativeArray<float3> vertsB, NativeArray<int> trisB) { for (int i = 0; i < trisA.Length; i += 3) { float3 a0 = vertsA[trisA[i]], a1 = vertsA[trisA[i + 1]], a2 = vertsA[trisA[i + 2]]; for (int j = 0; j < trisB.Length; j += 3) { float3 b0 = vertsB[trisB[j]], b1 = vertsB[trisB[j + 1]], b2 = vertsB[trisB[j + 2]]; if (CollisionDetection.TriangleIntersection.TrianglesIntersect(a0, a1, a2, b0, b1, b2)) return true; } } return false; } } }
最新发布
11-25
public class Triangulator { private List<Vector2> m_points = new List<Vector2>(); public Triangulator(List<Vector2> points) { initTriangulator(points.ToArray()); } public Triangulator(List<Vector3> points) { m_points.Clear(); for (int i = 0; i < points.Count; i++) { m_points.Add(new Vector2(points[i].x, points[i].y)); } } public void initTriangulator(Vector2[] points) { m_points = new List<Vector2>(points); } public int[] Triangulate() { List<int> indices = new List<int>(); int n = m_points.Count; if (n < 3) return indices.ToArray(); int[] V = new int[n]; if (Area() > 0) { for (int v = 0; v < n; v++) V[v] = v; } else { for (int v = 0; v < n; v++) V[v] = (n - 1) - v; } int nv = n; int count = 2 * nv; var m = 0; for (int v = nv - 1; nv > 2;) { if ((count--) <= 0) return indices.ToArray(); int u = v; if (nv <= u) u = 0; v = u + 1; if (nv <= v) v = 0; int w = v + 1; if (nv <= w) w = 0; if (Snip(u, v, w, nv, V)) { int a, b, c, s, t; a = V[u]; b = V[v]; c = V[w]; indices.Add(a); indices.Add(b); indices.Add(c); m++; s = v; for (t = v + 1; t < nv; t++) { V[s] = V[t]; s++; } nv--; count = 2 * nv; } } indices.Reverse(); return indices.ToArray(); } private float Area() { int n = m_points.Count; float A = 0.0f; int q = 0; for (int p = n - 1; q < n; p = q++) { Vector2 pval = m_points[p]; Vector2 qval = m_points[q]; A += pval.x * qval.y - qval.x * pval.y; } return (A * 0.5f); } private bool Snip(int u, int v, int w, int n, int[] V) { int p; Vector2 A = m_points[V[u]]; Vector2 B = m_points[V[v]]; Vector2 C = m_points[V[w]]; if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x)))) return false; for (p = 0; p < n; p++) { if ((p == u) || (p == v) || (p == w)) continue; Vector2 P = m_points[V[p]]; if (InsideTriangle(A, B, C, P)) return false; } return true; } private bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P) { float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy, cCROSSap, bCROSScp, aCROSSbp; ax = C.x - B.x; ay = C.y - B.y; bx = A.x - C.x; by = A.y - C.y; cx = B.x - A.x; cy = B.y - A.y; apx = P.x - A.x; apy = P.y - A.y; bpx = P.x - B.x; bpy = P.y - B.y; cpx = P.x - C.x; cpy = P.y - C.y; aCROSSbp = ax * bpy - ay * bpx; cCROSSap = cx * apy - cy * apx; bCROSScp = bx * cpy - by * cpx; return ((aCROSSbp >= 0) && (bCROSScp >= 0) && (cCROSSap >= 0)); } }如何利用上面这段代码在unity中实现填充的多边形网格的绘制
03-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值