- Unity frontend with ROS-TCP-Connector for ROS2 communication - Docker-based ROS2 Jazzy backend with MoveIt2 integration - Support for 1-9 DOF manipulators - UR5 robot configuration and URDF files - Assembly task feasibility analysis tools - Comprehensive documentation and deployment guides 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
336 lines
11 KiB
C#
336 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace UnityMoveIt2.Core
|
|
{
|
|
/// <summary>
|
|
/// 可视化引擎 - 碰撞可视化部分 / Visualization Engine - Collision Visualization Part
|
|
/// </summary>
|
|
public partial class VisualizationEngine
|
|
{
|
|
#region Collision Fields
|
|
|
|
[Header("碰撞可视化设置 / Collision Visualization Settings")]
|
|
[SerializeField]
|
|
private Color collisionColor = Color.red;
|
|
|
|
[SerializeField]
|
|
private Color warningColor = Color.yellow;
|
|
|
|
[SerializeField]
|
|
[Tooltip("碰撞透明度 / Collision Transparency")]
|
|
private float collisionTransparency = 0.5f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("警告距离(米) / Warning Distance (m)")]
|
|
private float warningDistance = 0.1f;
|
|
|
|
[SerializeField]
|
|
[Tooltip("显示碰撞边界 / Show Collision Bounds")]
|
|
private bool showCollisionBounds = true;
|
|
|
|
private Dictionary<string, GameObject> collisionHighlights;
|
|
private List<CollisionPair> activeCollisions;
|
|
private Material collisionMaterial;
|
|
private Material warningMaterial;
|
|
|
|
#endregion
|
|
|
|
#region Collision Initialization
|
|
|
|
private void InitializeCollisionVisualization()
|
|
{
|
|
collisionHighlights = new Dictionary<string, GameObject>();
|
|
activeCollisions = new List<CollisionPair>();
|
|
|
|
// 创建碰撞材质 / Create collision materials
|
|
collisionMaterial = CreateTransparentMaterial(collisionColor, collisionTransparency);
|
|
warningMaterial = CreateTransparentMaterial(warningColor, collisionTransparency);
|
|
|
|
Debug.Log("[VisualizationEngine] 碰撞可视化已初始化 / Collision visualization initialized");
|
|
}
|
|
|
|
private Material CreateTransparentMaterial(Color color, float transparency)
|
|
{
|
|
Material mat = new Material(Shader.Find("Standard"));
|
|
mat.SetFloat("_Mode", 3); // Transparent mode
|
|
mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
|
|
mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
|
|
mat.SetInt("_ZWrite", 0);
|
|
mat.DisableKeyword("_ALPHATEST_ON");
|
|
mat.EnableKeyword("_ALPHABLEND_ON");
|
|
mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
|
mat.renderQueue = 3000;
|
|
mat.color = new Color(color.r, color.g, color.b, transparency);
|
|
return mat;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Collision Update
|
|
|
|
private void UpdateCollisionVisualization()
|
|
{
|
|
// 更新碰撞高亮 / Update collision highlights
|
|
UpdateActiveCollisionHighlights();
|
|
|
|
// 清理过期的碰撞高亮 / Clean up expired collision highlights
|
|
CleanupInactiveCollisions();
|
|
}
|
|
|
|
private void UpdateActiveCollisionHighlights()
|
|
{
|
|
foreach (var collision in activeCollisions)
|
|
{
|
|
if (!collisionHighlights.ContainsKey(collision.objectName))
|
|
{
|
|
CreateCollisionHighlight(collision);
|
|
}
|
|
|
|
UpdateCollisionHighlight(collision);
|
|
}
|
|
}
|
|
|
|
private void CreateCollisionHighlight(CollisionPair collision)
|
|
{
|
|
GameObject target = GameObject.Find(collision.objectName);
|
|
if (target == null)
|
|
return;
|
|
|
|
GameObject highlight = new GameObject($"CollisionHighlight_{collision.objectName}");
|
|
highlight.transform.SetParent(collisionContainer.transform);
|
|
|
|
// 复制目标的网格 / Copy target's mesh
|
|
MeshFilter meshFilter = target.GetComponent<MeshFilter>();
|
|
if (meshFilter != null)
|
|
{
|
|
MeshFilter highlightMesh = highlight.AddComponent<MeshFilter>();
|
|
highlightMesh.mesh = meshFilter.mesh;
|
|
|
|
MeshRenderer renderer = highlight.AddComponent<MeshRenderer>();
|
|
renderer.material = collision.isWarning ? warningMaterial : collisionMaterial;
|
|
}
|
|
|
|
// 同步位置和旋转 / Sync position and rotation
|
|
highlight.transform.position = target.transform.position;
|
|
highlight.transform.rotation = target.transform.rotation;
|
|
highlight.transform.localScale = target.transform.localScale;
|
|
|
|
collisionHighlights[collision.objectName] = highlight;
|
|
}
|
|
|
|
private void UpdateCollisionHighlight(CollisionPair collision)
|
|
{
|
|
if (!collisionHighlights.ContainsKey(collision.objectName))
|
|
return;
|
|
|
|
GameObject highlight = collisionHighlights[collision.objectName];
|
|
GameObject target = GameObject.Find(collision.objectName);
|
|
|
|
if (target != null && highlight != null)
|
|
{
|
|
// 更新位置和旋转 / Update position and rotation
|
|
highlight.transform.position = target.transform.position;
|
|
highlight.transform.rotation = target.transform.rotation;
|
|
highlight.transform.localScale = target.transform.localScale;
|
|
|
|
// 更新材质 / Update material
|
|
MeshRenderer renderer = highlight.GetComponent<MeshRenderer>();
|
|
if (renderer != null)
|
|
{
|
|
renderer.material = collision.isWarning ? warningMaterial : collisionMaterial;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CleanupInactiveCollisions()
|
|
{
|
|
List<string> toRemove = new List<string>();
|
|
|
|
foreach (var kvp in collisionHighlights)
|
|
{
|
|
bool isActive = false;
|
|
foreach (var collision in activeCollisions)
|
|
{
|
|
if (collision.objectName == kvp.Key)
|
|
{
|
|
isActive = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!isActive)
|
|
{
|
|
toRemove.Add(kvp.Key);
|
|
}
|
|
}
|
|
|
|
foreach (var key in toRemove)
|
|
{
|
|
if (collisionHighlights[key] != null)
|
|
{
|
|
Destroy(collisionHighlights[key]);
|
|
}
|
|
collisionHighlights.Remove(key);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public Collision Methods
|
|
|
|
/// <summary>
|
|
/// 高亮显示碰撞对象 / Highlight Collision Objects
|
|
/// </summary>
|
|
public void HighlightCollisions(List<string> objectNames)
|
|
{
|
|
activeCollisions.Clear();
|
|
|
|
foreach (var name in objectNames)
|
|
{
|
|
activeCollisions.Add(new CollisionPair
|
|
{
|
|
objectName = name,
|
|
isWarning = false,
|
|
distance = 0f
|
|
});
|
|
}
|
|
|
|
UpdateCollisionVisualization();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 显示碰撞警告 / Show Collision Warnings
|
|
/// </summary>
|
|
public void ShowCollisionWarnings(List<ProximityInfo> proximities)
|
|
{
|
|
foreach (var proximity in proximities)
|
|
{
|
|
if (proximity.distance < warningDistance)
|
|
{
|
|
bool found = false;
|
|
foreach (var collision in activeCollisions)
|
|
{
|
|
if (collision.objectName == proximity.objectName)
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
activeCollisions.Add(new CollisionPair
|
|
{
|
|
objectName = proximity.objectName,
|
|
isWarning = true,
|
|
distance = proximity.distance
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdateCollisionVisualization();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清除碰撞可视化 / Clear Collision Visualization
|
|
/// </summary>
|
|
public void ClearCollisionVisualization()
|
|
{
|
|
activeCollisions.Clear();
|
|
|
|
foreach (var kvp in collisionHighlights)
|
|
{
|
|
if (kvp.Value != null)
|
|
{
|
|
Destroy(kvp.Value);
|
|
}
|
|
}
|
|
|
|
collisionHighlights.Clear();
|
|
|
|
Debug.Log("[VisualizationEngine] 已清除碰撞可视化 / Cleared collision visualization");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置碰撞对象列表 / Set Collision Objects List
|
|
/// </summary>
|
|
public void SetCollisionObjects(List<CollisionPair> collisions)
|
|
{
|
|
activeCollisions = new List<CollisionPair>(collisions);
|
|
UpdateCollisionVisualization();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Collision Gizmos
|
|
|
|
private void DrawCollisionGizmos()
|
|
{
|
|
if (!showCollisionBounds)
|
|
return;
|
|
|
|
Gizmos.color = collisionColor;
|
|
|
|
foreach (var collision in activeCollisions)
|
|
{
|
|
GameObject obj = GameObject.Find(collision.objectName);
|
|
if (obj != null)
|
|
{
|
|
Bounds bounds = GetObjectBounds(obj);
|
|
if (bounds.size != Vector3.zero)
|
|
{
|
|
Gizmos.DrawWireCube(bounds.center, bounds.size);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Bounds GetObjectBounds(GameObject obj)
|
|
{
|
|
Renderer renderer = obj.GetComponent<Renderer>();
|
|
if (renderer != null)
|
|
{
|
|
return renderer.bounds;
|
|
}
|
|
|
|
Collider collider = obj.GetComponent<Collider>();
|
|
if (collider != null)
|
|
{
|
|
return collider.bounds;
|
|
}
|
|
|
|
return new Bounds(obj.transform.position, Vector3.zero);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Collision Data Structures
|
|
|
|
/// <summary>
|
|
/// 碰撞对信息 / Collision Pair Information
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public class CollisionPair
|
|
{
|
|
public string objectName;
|
|
public bool isWarning;
|
|
public float distance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 接近度信息 / Proximity Information
|
|
/// </summary>
|
|
[System.Serializable]
|
|
public class ProximityInfo
|
|
{
|
|
public string objectName;
|
|
public float distance;
|
|
public Vector3 closestPoint;
|
|
}
|
|
|
|
#endregion
|
|
}
|