【UnityEditor扩展】如何在 Unity 中创建棱柱体(用作VR安全区检测),同时在编辑器插件中实现与撤销/恢复功能

Unity 编辑器扩展:3D 空间中绘制安全区棱柱体(含撤销/恢复/保存/读取)

在虚拟现实(VR)和增强现实(AR)开发中,安全区 是保障用户安全的重要组成部分。通过精确控制用户活动范围,可以避免用户与虚拟环境中的物体发生碰撞,确保舒适的体验。在本篇博客中,我们将实现一个 Unity 编辑器插件 ,用来 在 3D 空间中交互式绘制安全区棱柱体,并支持撤销/恢复、保存/读取功能。

功能概述

主要功能:

  1. 在 XZ 平面中绘制闭合路径:用户通过鼠标点击在 Scene 视图中绘制安全区的边界。

  2. 设置高度范围:可以定义每个安全区的起始高度和结束高度,生成棱柱体。

  1. 撤销与恢复:支持撤销上一个绘制点,并恢复已撤销的点。

  2. 保存与加载:用户可以将绘制的数据保存为 JSON 格式,并从文件中加载。

  3. 生成 Mesh 与 Collider :通过绘制的点生成对应的 Mesh 和 MeshCollider,作为安全区的碰撞检测区域。

应用场景

  • XR 项目开发:在 VR 或 AR 环境中,安全区用于避免用户与虚拟物体发生碰撞或越界。
  • 游戏开发:某些游戏场景中需要限制玩家活动区域,例如在竞技场或战斗区域内定义活动边界。
  • 室内定位与导航:AR 导航应用中,为了确保用户的安全,通常会设置一个虚拟边界。

编辑器扩展插件实现

本教程将介绍如何使用 Unity 编辑器扩展功能,在 3D 空间中绘制一个安全区的棱柱体,并支持实时显示与编辑。

插件结构与设计

插件的核心功能是基于 EditorWindowSceneView 进行实现。我们将创建一个编辑器窗口,通过点击绘制点生成一个闭合的多边形,并根据用户设定的起始高度和结束高度生成棱柱体。

csharp 复制代码
public class LineDrawingTool : EditorWindow
{

    [MenuItem("Tools/线条绘制工具")]
    public static void ShowWindow() { ... }

    private void OnGUI() { ... } // 工具窗口 UI
    private void OnSceneGUI(SceneView sceneView) { ... } // Scene 绘制
    private void GeneratePrismMesh() { ... } // 生成 Mesh
    private void SaveData() { ... } // 保存数据
    private void LoadData() { ... } // 加载数据
}

编辑器窗口 UI

OnGUI 方法中,我们将使用 Unity 的 GUI 系统来构建一个简洁易用的界面。界面包括:

  • 开始/结束绘制:用户可以点击按钮开始绘制或结束当前绘制。
  • 撤销/恢复:支持撤销上一个点,并恢复已撤销的点。
  • 高度设置:输入框允许用户设置安全区的起始高度和结束高度。
  • 保存/加载:可以将绘制的数据保存为 JSON 文件,也可以从文件中加载数据。
  • 生成 Mesh:用户可以点击按钮生成 Mesh 和 MeshCollider。

以下是 OnGUI 方法的核心实现:

csharp 复制代码
private void OnGUI()
{
    GUILayout.Space(10);
    EditorGUILayout.LabelField("安全区棱柱绘制工具", EditorStyles.boldLabel);

    // 绘制状态控制
    if (GUILayout.Button(isDrawing ? "结束绘制" : "开始绘制", GUILayout.Height(30)))
    {
        isDrawing = !isDrawing;
        SceneView.RepaintAll();
    }

    // 撤销/恢复功能
    EditorGUILayout.BeginHorizontal();
    GUI.enabled = points.Count > 0;
    if (GUILayout.Button("撤销", GUILayout.Height(25)))
    {
        // 撤销上一个点
    }
    GUI.enabled = undoStack.Count > 0;
    if (GUILayout.Button("恢复", GUILayout.Height(25)))
    {
        // 恢复上次撤销的点
    }
    GUI.enabled = true;
    EditorGUILayout.EndHorizontal();

    // 高度设置
    EditorGUILayout.LabelField("高度范围", EditorStyles.boldLabel);
    float newStartHeight = EditorGUILayout.FloatField("起始高度", startHeight);
    float newEndHeight = EditorGUILayout.FloatField("结束高度", endHeight);
    if (!Mathf.Approximately(newStartHeight, startHeight) || !Mathf.Approximately(newEndHeight, endHeight))
    {
        startHeight = newStartHeight;
        endHeight = newEndHeight;
        SceneView.RepaintAll();
    }

    // 保存与读取
    if (GUILayout.Button("保存绘制数据"))
    {
        SaveData();
    }
    if (GUILayout.Button("读取绘制数据"))
    {
        LoadData();
    }
}

绘制与生成 Mesh

绘制路径的过程中,我们使用了 SceneView 中的 OnSceneGUI 方法实时监听鼠标输入,并在视图中绘制路径线条和当前点。

在用户设置好高度后,我们将顶面和底面按顶点生成三角形,侧面通过连接相邻的顶点来构建。

csharp 复制代码
private void GeneratePrismMesh()
{
    // 使用顶点生成顶面、底面和侧面
    Mesh mesh = new Mesh();
    mesh.vertices = vertices.ToArray();
    mesh.triangles = triangles.ToArray();
    mesh.RecalculateNormals();

    // 创建 GameObject 和 MeshCollider
    GameObject prism = new GameObject("SafeZone_Prism");
    prism.AddComponent<MeshFilter>().sharedMesh = mesh;
    prism.AddComponent<MeshRenderer>().sharedMaterial = ...;
    prism.AddComponent<MeshCollider>().sharedMesh = mesh;
}

数据保存与加载

为了持久化绘制的数据,我们将其保存为 JSON 格式。这使得用户可以方便地保存并恢复绘制的安全区。

csharp 复制代码
private void SaveData()
{
    LineDrawingData data = new LineDrawingData { points = points, startHeight = startHeight, endHeight = endHeight };
    string json = JsonUtility.ToJson(data, true);
    File.WriteAllText(path, json);
}

private void LoadData()
{
    string json = File.ReadAllText(path);
    LineDrawingData data = JsonUtility.FromJson<LineDrawingData>(json);
    points = data.points;
    startHeight = data.startHeight;
    endHeight = data.endHeight;
    SceneView.RepaintAll();
}

可扩展性与优化建议

这个插件提供了一个基础的框架,可以根据具体需求进一步扩展与优化:

  • 支持多区域绘制:可以支持多个安全区的绘制与管理。
  • 实时网格更新:在编辑过程中实时更新 Mesh 的预览。
  • 吸附网格与参考线:为绘制提供网格对齐和参考辅助线。
  • 导出为 ScriptableObject:将绘制的安全区作为资源保存,便于复用。

结论

通过本教程,你已经掌握了如何在 Unity 编辑器中创建一个交互式的安全区棱柱体绘制工具,并能够实现撤销、恢复、保存与读取功能。这个插件不仅可以帮助开发者快速创建安全区,还能方便地管理和重用已有的区域设置。

希望这篇博客能帮助你提高开发效率。如果你有其他问题或改进建议,欢迎在评论区留言交流!


源码与示例项目

项目源码可以通过以下链接获取(或留言):源码地址

后续还会分享更多关于 Unity 编辑器工具开发、XR 项目优化等内容,敬请关注!

相关推荐
xhyyvr2 天前
“电”击预警!VR跨步电压安全体验系统
vr·vr公共安全·vr公共安全体验馆
在路上看风景2 天前
1.2 Unity资源分类
unity·游戏引擎
one named slash2 天前
BMFont在Unity中生成艺术字
unity·游戏引擎
微醺的老虎2 天前
【工具】vscode格式化json文件
ide·vscode·编辑器
乔宕一2 天前
vscode 设置每次调试 powershell 脚本都使用临时的 powershell 终端
ide·vscode·编辑器
Axis tech2 天前
TechViz VR解决方案:增强沉浸式设计评审与演示的技术革新
vr
郝学胜-神的一滴2 天前
图形学中的纹理映射问题:摩尔纹与毛刺的深度解析
c++·程序人生·unity·游戏引擎·图形渲染·unreal engine
在路上看风景2 天前
10. CPU-GPU协作渲染
unity
程序员agions2 天前
Unity 游戏开发邪修秘籍:从入门到被策划追杀的艺术
unity·cocoa·lucene
JIes__2 天前
Unity(一)——场景切换、退出游戏、鼠标隐藏锁定...
unity·游戏引擎