【UnityEditor扩展】如何在 Unity 中创建棱柱体(用作VR安全区检测),同时在编辑器插件中实现与撤销/恢复功能
引言
在 Unity 编辑器中创建棱柱体(Prism)是一种程序化生成 Mesh 的方式,常用于自定义几何形状。例如,在 VR 项目中,棱柱体可作为安全区(Guardian 或 Boundary)的检测边界,用于检查玩家是否超出指定区域(如房间边界),防止碰撞现实物体。棱柱体通常指一个具有多边形底面的柱状体(如三角棱柱、六边形棱柱),可以通过顶点、索引和三角形数组定义 Mesh。
本教程基于 Unity 2022.3 LTS+,使用 C# 脚本实现程序化 Mesh 生成,并在编辑器扩展插件中集成创建功能。关键是支持 Unity 的 Undo/Redo 系统,确保编辑操作可回滚。生成 Mesh 后,可添加 MeshCollider 用于运行时检测(如 Physics.CheckBox 或 Raycast)。 如果需要更复杂形状,可扩展为任意多边形底面。
程序化创建棱柱体 Mesh
首先,实现一个生成棱柱体 Mesh 的脚本。假设创建一个三角棱柱(可扩展为 n 边)。Mesh 需要定义顶点(vertices)、三角形索引(triangles)和 UV(可选)。
核心脚本(PrismMeshGenerator.cs)
using UnityEngine;
[ExecuteInEditMode] // 支持编辑器模式运行
public class PrismMeshGenerator : MonoBehaviour
{
public int sides = 3; // 底面边数(3=三角棱柱,6=六边棱柱)
public float radius = 1f; // 底面半径
public float height = 2f; // 高度
private MeshFilter meshFilter;
private MeshCollider meshCollider;
void Start()
{
meshFilter = gameObject.AddComponent<MeshFilter>();
meshCollider = gameObject.AddComponent<MeshCollider>();
GeneratePrismMesh();
}
public void GeneratePrismMesh()
{
Mesh mesh = new Mesh();
mesh.name = "PrismMesh";
// 计算顶点:底面 + 顶面
Vector3[] vertices = new Vector3[sides * 2];
for (int i = 0; i < sides; i++)
{
float angle = 2 * Mathf.PI * i / sides;
vertices[i] = new Vector3(Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius); // 底面
vertices[i + sides] = new Vector3(Mathf.Cos(angle) * radius, height, Mathf.Sin(angle) * radius); // 顶面
}
// 计算三角形索引
int[] triangles = new int[sides * 6 + sides * 6]; // 底面 + 顶面 + 侧面
int triIndex = 0;
// 底面三角形
for (int i = 1; i < sides - 1; i++)
{
triangles[triIndex++] = 0;
triangles[triIndex++] = i;
triangles[triIndex++] = i + 1;
}
// 顶面三角形(反向绕序)
for (int i = 1; i < sides - 1; i++)
{
triangles[triIndex++] = sides;
triangles[triIndex++] = sides + i + 1;
triangles[triIndex++] = sides + i;
}
// 侧面三角形
for (int i = 0; i < sides; i++)
{
int bottom1 = i;
int bottom2 = (i + 1) % sides;
int top1 = i + sides;
int top2 = (i + 1) % sides + sides;
// 一个侧面两个三角形
triangles[triIndex++] = bottom1;
triangles[triIndex++] = top1;
triangles[triIndex++] = bottom2;
triangles[triIndex++] = bottom2;
triangles[triIndex++] = top1;
triangles[triIndex++] = top2;
}
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
meshFilter.sharedMesh = mesh;
meshCollider.sharedMesh = mesh; // 用于碰撞检测
}
}
- 使用:附加到空 GameObject,调整参数,Mesh 会自动生成。
- 扩展:对于自定义底面,可传入顶点数组生成。
编辑器插件实现
通过编辑器扩展插件(Editor Script)添加菜单项或自定义工具窗口,实现一键创建棱柱体,并支持参数调整。
编辑器脚本(PrismCreatorEditor.cs)
放置在 Assets/Editor 文件夹中。
using UnityEditor;
using UnityEngine;
public class PrismCreatorEditor : EditorWindow
{
private int sides = 3;
private float radius = 1f;
private float height = 2f;
[MenuItem("Tools/Create Prism for VR Safety Zone")]
private static void OpenWindow()
{
GetWindow<PrismCreatorEditor>("Prism Creator");
}
private void OnGUI()
{
GUILayout.Label("Prism Parameters", EditorStyles.boldLabel);
sides = EditorGUILayout.IntField("Sides", sides);
radius = EditorGUILayout.FloatField("Radius", radius);
height = EditorGUILayout.FloatField("Height", height);
if (GUILayout.Button("Create Prism"))
{
CreatePrism();
}
}
private void CreatePrism()
{
GameObject prismObj = new GameObject("VR_Safety_Prism");
PrismMeshGenerator generator = prismObj.AddComponent<PrismMeshGenerator>();
generator.sides = sides;
generator.radius = radius;
generator.height = height;
generator.GeneratePrismMesh();
// 支持 Undo/Redo
Undo.RegisterCreatedObjectUndo(prismObj, "Create VR Safety Prism");
Selection.activeGameObject = prismObj; // 选中新对象
}
}
- 使用:Tools > Create Prism for VR Safety Zone 打开窗口,输入参数,点击创建。
- Undo/Redo:使用
Undo.RegisterCreatedObjectUndo
,创建操作可撤销(Ctrl+Z)。对于修改(如参数变化),可在GeneratePrismMesh
中添加Undo.RecordObject(meshFilter, "Modify Prism Mesh")
。
支持撤销/恢复功能
Unity 的 Undo 系统内置支持编辑器操作:
- 创建对象:
Undo.RegisterCreatedObjectUndo(obj, "Action Name")
– 撤销时销毁对象。 - 修改对象:
Undo.RecordObject(target, "Modify Name")
– 在修改前记录状态,撤销时恢复。 - 销毁对象:
Undo.DestroyObjectImmediate(obj)
– 支持撤销。 - 组操作:
Undo.RegisterCompleteObjectUndo(obj, "Group Action")
– 记录整个对象状态(适合 Mesh 修改,避免大 Mesh 性能问题)。
在上述脚本中,已集成基本 Undo。对于 Mesh 编辑(如运行时或编辑器拖拽顶点),需在每个修改前记录:
Undo.RecordObject(meshFilter.sharedMesh, "Edit Prism Mesh");
// 修改 vertices 等
meshFilter.sharedMesh.vertices = newVertices;
meshFilter.sharedMesh.RecalculateNormals();
- 性能提示:大 Mesh 避免频繁记录整个对象,可使用自定义 Undo 栈(高级)。
VR 安全区检测应用
生成的棱柱体可用于 VR 安全区检测:
- 添加组件:在棱柱体上添加 MeshRenderer(可视化边界)和 MeshCollider(Is Trigger = true)。
- 检测脚本(VRSafetyZoneDetector.cs):
using UnityEngine;
using UnityEngine.XR; // 对于 OpenXR 等
public class VRSafetyZoneDetector : MonoBehaviour
{
public MeshCollider safetyCollider; // 棱柱体碰撞体
void Update()
{
// 获取玩家头部位置(假设 XR Rig)
Vector3 playerPos = Camera.main.transform.position;
// 检查是否在安全区内
if (!safetyCollider.bounds.Contains(playerPos))
{
Debug.Log("Player out of safety zone!");
// 触发警告:淡化屏幕、显示边界等
}
}
}
- VR 集成:使用 XR Interaction Toolkit 或 Oculus SDK 获取边界数据,动态调整棱柱体大小。
- 优化:对于复杂形状,使用 Convex MeshCollider;运行时检测使用 Physics.OverlapBoxNonAlloc 批量检查。
注意事项与扩展
- 兼容性:确保项目使用 URP/HDRP 支持 VR(Project Settings > XR Plug-in Management > OpenXR)。
- 性能:高边数棱柱体增加顶点数,优化 sides 参数。
- 自定义编辑:扩展为 Gizmos 绘制顶点拖拽,支持实时编辑(OnSceneGUI)。
- 资源:Unity Mesh API 文档;Catlike Coding 程序化 Mesh 教程。
如果需要特定边数的代码变体或完整项目示例,请提供更多细节!
“`