【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 项目优化等内容,敬请关注!

相关推荐
_Cherry|5 小时前
unity与usb串口通信(web版)
unity·c#·游戏引擎
一杯咖啡*_*7 小时前
VSCode优雅的使用debug
ide·vscode·python·编辑器·bug
在下胡三汉11 小时前
3dmax标准材质/vr/cr材质贴图转PBR材质贴图插件,支持多维子材质转换
vr·材质·贴图
Qiao胖胖14 小时前
unity曲线射击
unity·游戏引擎
Lareina~17 小时前
【元表 vs 元方法】
unity·lua
Clank的游戏栈1 天前
Unity IL2CPP内存泄漏追踪方案(基于Memory Profiler)技术详解
unity·游戏引擎
yuren_xia1 天前
Vim 编辑器的常用快捷键介绍
linux·编辑器·vim
凯禾瑞华实训室建设1 天前
创新驱动:智慧养老综合实训室内的前沿技术应用
大数据·人工智能·科技·物联网·vr
归海_一刀1 天前
Unity跨平台输入系统
unity·游戏引擎·输入系统
向宇it1 天前
【unity游戏开发入门到精通——动画篇】Animator反向动力学(IK)
开发语言·unity·c#·编辑器·游戏引擎