305 lines
10 KiB
C#
305 lines
10 KiB
C#
// WindTurbineHeatSimulator.cs
|
||
using UnityEngine;
|
||
using System.Collections.Generic;
|
||
|
||
public class WindTurbineHeatSimulator : MonoBehaviour
|
||
{
|
||
[Header("热力图渲染组件")]
|
||
[SerializeField] private Heatmap heatmapComponent; // 引用您提供的Heatmap脚本
|
||
|
||
[Header("模拟参数")]
|
||
[SerializeField] private float ambientTemperature = 25f;
|
||
[SerializeField] private float simulationSpeed = 1.0f;
|
||
[SerializeField] private bool realTimeUpdate = true;
|
||
|
||
[Header("热点配置")]
|
||
[SerializeField] private List<SimulatedHotspot> hotspots = new List<SimulatedHotspot>();
|
||
|
||
[System.Serializable]
|
||
public class SimulatedHotspot
|
||
{
|
||
public string name = "热点";
|
||
public Transform centerTransform; // 热点中心的变换组件(可选)
|
||
public Vector3 localOffset; // 相对于模型局部坐标系的偏移
|
||
public float baseRadius = 1.0f;
|
||
public float baseIntensity = 1.0f;
|
||
public float fluctuationSpeed = 1.0f; // 波动速度
|
||
[Range(0f, 1f)] public float fluctuationAmount = 0.2f; // 波动幅度
|
||
[HideInInspector] public float phase; // 用于波动的相位
|
||
}
|
||
|
||
private float simulationTime = 0f;
|
||
private List<HeatPoint> currentHeatPoints = new List<HeatPoint>();
|
||
|
||
[Header("性能优化")]
|
||
[Tooltip("热力图数据更新的频率(秒)。降低频率可大幅提升性能。")]
|
||
[SerializeField] private float updateInterval = 0.1f; // 默认每秒更新10次,而非每帧
|
||
[Tooltip("当热点数据未发生变化时,是否跳过本次更新提交。")]
|
||
[SerializeField] private bool updateOnlyOnChange = true;
|
||
|
||
private float updateTimer = 0f;
|
||
private List<HeatPoint> previousHeatPoints = new List<HeatPoint>(); // 用于比较数据是否变化
|
||
|
||
private void Start()
|
||
{
|
||
// 自动获取Heatmap组件
|
||
if (heatmapComponent == null)
|
||
{
|
||
heatmapComponent = GetComponent<Heatmap>();
|
||
}
|
||
|
||
if (heatmapComponent == null)
|
||
{
|
||
Debug.LogError($"在{gameObject.name}上未找到Heatmap组件。请确保已将Heatmap脚本附加到风机模型上。");
|
||
return;
|
||
}
|
||
|
||
// 如果没有配置热点,创建一些基于风机典型部位的默认热点
|
||
if (hotspots.Count == 0)
|
||
{
|
||
InitializeDefaultHotspots();
|
||
}
|
||
|
||
// 初始生成一次热力点
|
||
GenerateHeatPoints();
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
/*
|
||
if (!realTimeUpdate || heatmapComponent == null) return;
|
||
|
||
simulationTime += Time.deltaTime * simulationSpeed;
|
||
GenerateHeatPoints();*/
|
||
|
||
|
||
if (!realTimeUpdate || heatmapComponent == null) return;
|
||
|
||
// 1. 基于间隔时间的更新,而非每帧
|
||
updateTimer += Time.deltaTime;
|
||
if (updateTimer < updateInterval) return;
|
||
updateTimer = 0f;
|
||
|
||
// 2. 生成新的热力点数据
|
||
GenerateHeatPoints();
|
||
|
||
// 3. (可选)仅在数据发生变化时提交更新
|
||
if (updateOnlyOnChange && !HasHeatPointsChanged())
|
||
{
|
||
return; // 数据未变化,跳过本次GPU提交
|
||
}
|
||
|
||
// 4. 提交数据到Heatmap组件
|
||
if (heatmapComponent != null && currentHeatPoints.Count > 0)
|
||
{
|
||
heatmapComponent.SetHeatPoints(currentHeatPoints);
|
||
UpdatePreviousHeatPoints(); // 记录当前数据用于下次比较
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 比较当前生成的热点数据与上一次是否相同
|
||
/// </summary>
|
||
private bool HasHeatPointsChanged()
|
||
{
|
||
if (previousHeatPoints.Count != currentHeatPoints.Count) return true;
|
||
for (int i = 0; i < currentHeatPoints.Count; i++)
|
||
{
|
||
// 简单比较位置、半径和强度。可以根据需要调整比较精度。
|
||
if (Vector3.Distance(previousHeatPoints[i].point, currentHeatPoints[i].point) > 0.001f ||
|
||
Mathf.Abs(previousHeatPoints[i].radius - currentHeatPoints[i].radius) > 0.001f ||
|
||
Mathf.Abs(previousHeatPoints[i].intensity - currentHeatPoints[i].intensity) > 0.001f)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private void UpdatePreviousHeatPoints()
|
||
{
|
||
previousHeatPoints.Clear();
|
||
// 进行深拷贝,而非引用拷贝
|
||
foreach (var point in currentHeatPoints)
|
||
{
|
||
previousHeatPoints.Add(new HeatPoint { point = point.point, radius = point.radius, intensity = point.intensity });
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成默认热点配置(基于典型风机结构)
|
||
/// </summary>
|
||
private void InitializeDefaultHotspots()
|
||
{
|
||
// 示例:创建三个代表发电机、齿轮箱和轴承的模拟热点
|
||
// 注意:这些localOffset是示例值,您需要根据风机模型的实际比例和轴心调整
|
||
hotspots.Add(new SimulatedHotspot
|
||
{
|
||
name = "发电机",
|
||
localOffset = new Vector3(0f, 0.8f, 0f), // 机舱上部
|
||
baseRadius = 1.5f,
|
||
baseIntensity = 1.2f,
|
||
fluctuationSpeed = 0.8f,
|
||
fluctuationAmount = 0.3f
|
||
});
|
||
|
||
hotspots.Add(new SimulatedHotspot
|
||
{
|
||
name = "齿轮箱",
|
||
localOffset = new Vector3(0.5f, 0.6f, 0f), // 机舱前部
|
||
baseRadius = 1.2f,
|
||
baseIntensity = 1.0f,
|
||
fluctuationSpeed = 1.2f,
|
||
fluctuationAmount = 0.25f
|
||
});
|
||
|
||
hotspots.Add(new SimulatedHotspot
|
||
{
|
||
name = "叶片根部轴承",
|
||
localOffset = new Vector3(0f, 1.0f, 1.5f), // 假设叶片沿Z轴伸出
|
||
baseRadius = 0.8f,
|
||
baseIntensity = 0.9f,
|
||
fluctuationSpeed = 2.0f, // 叶片旋转导致更快的波动
|
||
fluctuationAmount = 0.4f
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 核心方法:根据模拟参数生成热力点列表
|
||
/// </summary>
|
||
public void GenerateHeatPoints()
|
||
{
|
||
currentHeatPoints.Clear();
|
||
|
||
foreach (var config in hotspots)
|
||
{
|
||
// 计算热点在世界坐标系中的最终位置
|
||
Vector3 worldPosition = CalculateHotspotWorldPosition(config);
|
||
|
||
// 计算当前帧的强度和半径(加入波动模拟)
|
||
float currentIntensity = CalculateCurrentIntensity(config);
|
||
float currentRadius = CalculateCurrentRadius(config);
|
||
|
||
// 创建热力点数据结构
|
||
HeatPoint heatPoint = new HeatPoint
|
||
{
|
||
point = worldPosition,
|
||
radius = currentRadius,
|
||
intensity = currentIntensity
|
||
};
|
||
|
||
currentHeatPoints.Add(heatPoint);
|
||
}
|
||
|
||
// 将生成的热点数据提交给Heatmap组件进行渲染
|
||
if (heatmapComponent != null && currentHeatPoints.Count > 0)
|
||
{
|
||
heatmapComponent.SetHeatPoints(currentHeatPoints);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算热点在世界空间中的位置
|
||
/// </summary>
|
||
private Vector3 CalculateHotspotWorldPosition(SimulatedHotspot config)
|
||
{
|
||
if (config.centerTransform != null)
|
||
{
|
||
// 如果指定了具体的Transform,以其为基准
|
||
return config.centerTransform.position + config.centerTransform.TransformVector(config.localOffset);
|
||
}
|
||
else
|
||
{
|
||
// 否则,使用风机模型自身的变换,并加上局部偏移
|
||
return transform.position + transform.TransformVector(config.localOffset);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算当前帧的热点强度(带波动)
|
||
/// </summary>
|
||
private float CalculateCurrentIntensity(SimulatedHotspot config)
|
||
{
|
||
// 基础强度 + 正弦波动
|
||
float fluctuation = Mathf.Sin(simulationTime * config.fluctuationSpeed + config.phase) * config.fluctuationAmount;
|
||
return config.baseIntensity * (1 + fluctuation);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算当前帧的热点半径(可加入轻微波动,或保持恒定)
|
||
/// </summary>
|
||
private float CalculateCurrentRadius(SimulatedHotspot config)
|
||
{
|
||
// 此处示例半径保持恒定,您也可以加入波动
|
||
return config.baseRadius;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 手动触发热力图更新(例如在检查器或由外部逻辑调用)
|
||
/// </summary>
|
||
[ContextMenu("手动更新热力图")]
|
||
public void ManualUpdateHeatmap()
|
||
{
|
||
GenerateHeatPoints();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加一个运行时热点(可用于模拟故障)
|
||
/// </summary>
|
||
public void AddRuntimeHotspot(Vector3 worldPosition, float radius, float intensity, float duration = 5f)
|
||
{
|
||
// 创建一个临时热点配置
|
||
SimulatedHotspot tempHotspot = new SimulatedHotspot
|
||
{
|
||
name = "临时热点",
|
||
localOffset = transform.InverseTransformPoint(worldPosition), // 转换为局部坐标偏移
|
||
baseRadius = radius,
|
||
baseIntensity = intensity,
|
||
fluctuationSpeed = 3f,
|
||
fluctuationAmount = 0.5f
|
||
};
|
||
|
||
hotspots.Add(tempHotspot);
|
||
GenerateHeatPoints(); // 立即更新
|
||
|
||
// 可选:在指定时间后移除临时热点
|
||
if (duration > 0)
|
||
{
|
||
StartCoroutine(RemoveHotspotAfterDelay(tempHotspot, duration));
|
||
}
|
||
}
|
||
|
||
private System.Collections.IEnumerator RemoveHotspotAfterDelay(SimulatedHotspot hotspot, float delay)
|
||
{
|
||
yield return new WaitForSeconds(delay);
|
||
hotspots.Remove(hotspot);
|
||
GenerateHeatPoints();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在Scene视图中绘制Gizmos以可视化热点位置
|
||
/// </summary>
|
||
private void OnDrawGizmosSelected()
|
||
{
|
||
if (!Application.isPlaying)
|
||
{
|
||
// 在编辑模式下绘制配置的预设热点位置
|
||
Gizmos.color = Color.yellow;
|
||
foreach (var config in hotspots)
|
||
{
|
||
Vector3 pos = CalculateHotspotWorldPosition(config);
|
||
Gizmos.DrawWireSphere(pos, config.baseRadius * 0.5f); // 绘制小一些以便观察
|
||
Gizmos.DrawIcon(pos, "HeatmapIcon.png", true);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 在运行模式下绘制当前实际的热力点
|
||
Gizmos.color = Color.red;
|
||
foreach (var hp in currentHeatPoints)
|
||
{
|
||
Gizmos.DrawWireSphere(hp.point, hp.radius * 0.3f);
|
||
}
|
||
}
|
||
}
|
||
} |