ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MuJoCo Unity 插件深度指南:从 MJCF 导入、坐标系对齐到场景重建机制

MuJoCo Unity 插件深度指南:从 MJCF 导入、坐标系对齐到场景重建机制 MuJoCo Unity 插件深度指南从 MJCF 导入、坐标系对齐到场景重建机制【免费下载链接】mujocoMulti-Joint dynamics with Contact. A general purpose physics simulator.项目地址: https://gitcode.com/GitHub_Trending/mu/mujocoMuJoCo 官方提供的 Unity 插件让 Unity Editor 与运行时可以直接使用 MuJoCo 物理引擎你可以把 MJCF 模型导入 Unity 场景、在 Editor 中编辑再由 MuJoCo 决定物体的运动。本文基于仓库中 doc/unity.rst 的官方文档结合unity/目录下的 C# 源码完整覆盖插件的安装、使用方法、设计原则与实现细节读完后你可以独立完成“MJCF 模型导入 Unity — 运行 MuJoCo 仿真 — 读取传感器数据”的全链路开发。插件定位谁负责什么插件的分工非常明确见 unity/README.mdUnity 负责资源管理网格、材质、纹理、游戏逻辑、仿真时间Fixed Timestep、渲染MuJoCo 负责物理——物体如何运动、接触如何求解设计师因此可以使用 MuJoCo 的完整 C APImjModel/mjData/mj_step等。仓库中还维护了一个独立的入门教程项目mj-unity-tutorial其中包含一组演示该插件用法的示例工程适合作为上手材料。安装与配置插件源码位于仓库的 unity/ 目录其结构分为三部分目录内容unity/Editor/Editor 侧功能导入器窗口、上下文菜单、鼠标弹簧、Gizmo 编辑器unity/Runtime/运行时组件MjScene、各类MjComponent、MjBindings原生库 P/Invoke 封装unity/Tests/Editor 与 Runtime 的自动化测试通过 Package Manager 导入插件目录包含 package.json。Unity 的 Package Manager 识别该文件后会把插件的 C# 代码库导入你的项目。此外 Unity 还需要原生 MuJoCo 动态库它发布在对应平台的 MuJoCo release 归档包中。版本匹配原则如果你只是使用插件而不参与插件开发应使用仓库中标记了 git tag 的版本稳定提交例如git checkout 3.X.Y其中 X、Y 指定引擎版本。直接跟踪main分支的代码可能与最新发布的 MuJoCo 二进制库不兼容。原生库的放置方式适用于 Unity 2020.2 及以后Package Manager 在导入包时会主动查找原生库文件并将其复制到包目录。你也可以手动把原生库复制到包目录并按平台重命名或复制到项目Assets目录下的任意位置macOS需要先把 MuJoCo 应用至少运行一次让系统把该库登记为受信任的二进制文件。然后从MuJoCo.app中可浏览 app 内容定位复制/Applications/MuJoCo.app/Contents/Frameworks/mujoco.framework/Versions/Current/libmujoco.3.13.1.dylib 并重命名为mujoco.dylib。Linux把tar.gz归档解压到~/.mujoco复制~/.mujoco/mujoco-3.13.1/lib/libmujoco.so.3.13.1并重命名为libmujoco.so。Windows把zip归档解压到用户目录下一个名为MuJoCo的目录复制其中的MuJoCo\bin\mujoco.dll无需重命名。以上路径以文档给出的 3.13.1 版本为例实际版本号请以你所下载的 release 为准。使用插件导入 MJCF 模型Importer导入入口是 Editor 的Asset菜单中的 “Import MuJoCo Scene”选一个 MJCF 的 XML 文件即可完成导入。对应源码在 MjImporterEditorWindow.cspublic class MjImporterEditorWindow : EditorWindow { [MenuItem(Assets/Import MuJoCo Scene)] public static void Apply() { string path EditorUtility.OpenFilePanel(Select an MJCF model, , xml); if (!string.IsNullOrEmpty(path)) { var importer new MjImporterWithAssets(); importer.ImportFile(path); } } }从源码可以看出菜单项注册为Assets/Import MuJoCo Scene实际工作由MjImporterWithAssets完成该类是MjcfImporter的子类见 MjImporterWithAssets.cs。右键上下文菜单MjGeomEditor.cs 注册了三条右键菜单右键一个MjGeom组件有两个选项“Add mesh renderer”为同一个 GameObject 添加渲染该 geom 的组件——一个标准MeshRenderer加一个MjMeshFilter。MjMeshFilter会创建过程化网格procedural mesh并且会在 geom 形状属性变化时重建网格“Convert to free object”创建两个新的 GameObject——一个带MjBody组件的父对象和一个带MjFreeJoint组件的兄弟对象。这使原本静止的 geom 可以在场景中自由运动。该操作仅适用于 “world” geom即当前没有MjBody祖先的 geom。右键一个 Unity Collider可选择 “Add a matching MuJoCo geom”在同一个 GameObject 上添加匹配的 MuJoCo geom。注意这不构成完整的物理转换——Rigidbody、ArticulationBody 与 Joint 配置仍需手动重建。鼠标弹簧Mouse spring当选中的 GameObject 带有MjBody组件时可以在 Scene 视图中通过按住 Ctrl 并拖拽鼠标对该刚体施加指向鼠标光标的弹簧力。实现见 MjMouseSpring.cs。其力学细节弹簧力作用点的 3D 位置由鼠标位置投影到一个平面得到该平面由相机 X 方向与世界 Y 方向张成按住 Shift 键时投影平面切换为与世界 X、Z 轴平行的平面方便在水平面内拖动物体。给 Unity 用户的三条实战建议开启 “Error Pause”一旦遇到编译或运行时错误系统状态未定义建议在 Console 窗口打开 “Error Pause”让执行停在出错点便于定位。PhysX 与 MuJoCo 的自由度模型差异在 PhysX 中每个Rigidbody都是 “自由体”而 MuJoCo 需要显式声明关节才能获得自由度。插件为此提供了上文 “freeing” 一个 world geom 的上下文菜单添加父级MjBody 兄弟级MjFreeJoint。没有 Trigger 概念插件不支持没有物理存在的碰撞检测因此没有内置的 trigger 碰撞器。需要感知“接触与否”时添加一个touch 传感器并读取其SensorReading值——该值对应法向接触力详见 XML 参考 中 touch sensor 一节。设计原则MJCF 元素与 Unity 组件的一一映射插件的核心设计是MJCF 元素与 Unity 组件之间的一一对应。当用户在 Editor 中点击 “Play” 时插件模拟 Unity 场景的流程是扫描场景中所有 MuJoCo 组件MjComponent实例生成一段 MJCF 描述并交给 MuJoCo 编译器通过 MuJoCo 数据结构中的对应索引把每个组件绑定到 MuJoCo 运行时。这个索引在仿真期间用于更新 Unity 的 Transform。这一原则带来若干重要推论组件字段基本对应 MJCF 属性因此组件各取值的语义可以直接查 XML 参考MuJoCo 组件在 GameObject 层级中的布局决定了生成模型的布局所以设计规则是每个 GameObject 最多挂一个 MuJoCo 组件坐标系需要 swizzle分量交换Unity 使用左手坐标系、Y 为竖直轴MuJoCo 使用右手坐标系、Z 为竖直轴。这一点在源码中有直接证据——MjEngineTool.cs 中的转换函数// Converts a Unity Vector3 to a Mujoco vector. public static Vector3 MjVector3(Vector3 unityVec) { return new Vector3(unityVec.x, unityVec.z, unityVec.y); } // Converts a Unity Quaternion to a Mujoco Quaternion public static Quaternion MjQuaternion(Quaternion unityQuat) { return new Quaternion(w:-unityQuat.w, x:unityQuat.x, y:unityQuat.z, z:unityQuat.y); }即向量的 y/z 分量互换四元数则同时做 w 取负与轴重排——这是左右手坐标系转换的典型形式缩放会引入几何畸变Unity 的 Transform 缩放影响整个子树的位移、姿态与尺度但 MuJoCo 不支持被 skew斜切/非均匀缩放的圆柱与胶囊体碰撞skew 的球体可以通过椭球原语支持。geom 与 site 的编辑 gizmo 会忽略这种 skew与 PhysX 碰撞器类似始终显示物理侧“看到”的原始基元形状运行时改字段不会立即生效运行时修改组件字段不会触发场景重建因此对物理没有即时影响新值会在下一次场景重建时加载。在“Unity 化”方面插件尽量跟随 Unity 的惯例重力从 Unity 的物理设置读取仿真步长取自 Unity Time Manager 的Fixed Timestep对应MjScene在FixedUpdate()中步进见 MjScene.cs所有外观相关网格、材质、纹理交给 Unity 的 Asset ManagerRGBA 通过材质资源指定。实现细节导入器工作流用户选中一个 MJCF 文件后导入器先用 MuJoCo 加载该文件保存到临时位置再处理生成的保存文件。这样有三个好处校验 MJCF保证保存下来的 MJCF 一定符合 MJCF schema校验并导入资源材质、网格、纹理等资产会被导入 Unity同时为 geom 的 RGBA 规格创建新的材质资源无需复刻 MuJoCo 的文件系统工作流即可处理include元素XML 参考。Unity 中没有与 MJCF “级联”的default子句对应的机制。因此导入后Unity 组件反映的是所有相关 default class 应用完成之后的元素状态原始 MJCF 中的 class 结构会被丢弃。MuJoCo Scene场景的创建、步进与绑定MjScene.cs 是这一机制的核心。MjScene组件首先扫描场景中所有MjComponent实例每个组件用自己的GenerateMjcf()生成一个 MJCF 元素用 Unity 场景的空间结构描述模型的初始参考位姿即 MuJoCo 的qpos0。MjScene再按各组件所属 GameObject 的层级把这些 XML 元素组合成一份完整的 MJCF 物理模型描述然后创建mjModel与mjData运行时结构体通过唯一索引把每个组件绑定到运行时private unsafe void CompileScene(XmlDocument mjcf, IEnumerableMjComponent components) { Model MjEngineTool.LoadModelFromString(mjcf.OuterXml); ... Data MujocoLib.mj_makeData(Model); ... // Bind the components to their Mujoco counterparts. foreach (var component in components) { component.BindToRuntime(Model, Data); } }运行期MjScene.FixedUpdate()调用mj_step若注册了ctrlCallback则拆分为mj_step1 控制回调 mj_step2见 MjScene.cs随后按绑定时的索引MjComponent.MujocoId同步每个 GameObject 的状态。只要场景中出现了任何 MuJoCo 组件应用启动例如用户点击 “play”时就会自动添加一个MjScene组件。如果你的应用初始化阶段会在边添加 GameObject/组件的同时推进物理可以在初始化阶段结束后显式调用MjScene.CreateScene()。场景重建如何保持物理状态连续运行时增删 MuJoCo 组件会触发完整的场景重建。为避免状态跳变MjScene.cs 的 RecreateScene() 按四步保证连续性缓存关节的位置与速度源码中按关节类型区分处理——HINGE/SLIDE 各缓存 1 个位置 1 个速度分量BALL 缓存 4 个位置四元数 3 个速度FREE 缓存 7 个位置 6 个速度重置 MuJoCo 状态到qpos0并同步 Unity Transformmj_resetDatamj_kinematics重新生成 XML 并创建新模型使那些“幸存”关节拥有与旧模型相同的qpos0从缓存恢复幸存关节的 MuJoCo 状态再次同步 Unity Transform。需要知道的一个限制MuJoCo 本身支持通过 mjSpec 做动态场景编辑但 Unity 插件目前尚未支持该路径——增删 MuJoCo 组件一律走完整重建。对大模型或频繁增删的场景这可能开销较大官方表示计划在后续版本中解除这一性能限制。Global Settings 组件“一个元素对应一个组件”的例外是Global Settings组件它负责所有 MJCF 中固定大小、单例全局元素的配置项。目前它承载 XML 参考 中option与size元素对应的信息将来如果compiler元素中有对 Unity 插件相关的字段也会由它承载。对应源码为 MjGlobalSettings.cs。在运行时调用导入器导入器由MjImporterWithAssetsMjcfImporter的子类实现。父类 MjcfImporter 接收一段 MJCF 字符串并生成组件层级public GameObject ImportString(string mjcfString, string name null) { var mjcfXml new XmlDocument(); mjcfXml.LoadXml(mjcfString); return ImportXml(mjcfXml, name); }它可以在play 阶段调用不涉及任何 Editor 功能也不调用 MuJoCo 库的任何函数——适合程序化生成 MuJoCo 模型例如某种演化过程产生模型或把 MJCF 导入后仅做格式转换如转成 PhysX 或 URDF的场景。由于无法与 Unity 的AssetManagerEditor 功能交互该类的功能有限制忽略所有资产含碰撞网格忽略所有视觉含 RGBA 规格。传感器组件的类层次MuJoCo 定义了非常多的传感器。为每个传感器单独建一个MjComponent子类会造成大量代码重复因此插件按被测对象的类型actuator / body / geom / joint / site与数据形态标量 / 向量 / 四元数来组织类。对应实现位于 unity/Runtime/Components/Sensors/如MjSiteScalarSensor.cs、MjJointScalarSensor.cs、MjBodyVectorSensor.cs等。对象类型 × 数据类型 → 传感器名MuJoCo 对象类型数据类型传感器名ActuatorScalaractuatorpos、actuatorvel、actuatorfrcBodyVectorsubtreecom、subtreelinvel、subtreeangmom、framepos、framexaxis、frameyaxis、framezaxis、framelinvel、frameangvel、framelinacc、frameangaccBodyQuaternionframequatGeomVectorframepos、framexaxis、frameyaxis、framezaxis、framelinvel、frameangvel、framelinacc、frameangaccGeomQuaternionframequatJointScalarjointpos、jointvel、jointlimitpos、jointlimitvel、jointlimitfrcSiteScalartouch、rangefinderSiteVectoraccelerometer、velocimeter、force、torque、gyro、magnetometer、framepos、framexaxis、frameyaxis、framezaxis、framelinvel、frameangvel、framelinacc、frameangaccSiteQuaternionframequat反向映射传感器名 → 插件类传感器名插件类accelerometerSiteVectoractuatorfrcActuatorScalaractuatorposActuatorScalaractuatorvelActuatorScalarforceSiteVectorframeangacc*Vector取决于 frame 类型frameangvel*Vector取决于 frame 类型framelinacc*Vector取决于 frame 类型framelinvel*Vector取决于 frame 类型framepos*Vector取决于 frame 类型framequat*Quaternion取决于 frame 类型framexaxis*Vector取决于 frame 类型frameyaxis*Vector取决于 frame 类型framezaxis*Vector取决于 frame 类型gyroSiteVectorjointlimitfrcJointScalarjointlimitposJointScalarjointlimitvelJointScalarjointposJointScalarjointvelJointScalarmagnetometerSiteVectorsubtreeangmomBodyVectorsubtreecomBodyVectorsubtreelinvelBodyVectortorqueSiteVectortouchSiteScalarvelocimeterSiteVector其中\*表示 Body/Geom/Site 三种前缀之一由传感器的 frame 目标决定。以下传感器尚未实现tendonpos、tendonvel、ballquat、ballangvel、tendonlimitpos、tendonlimitvel、tendonlimitfrc、user。网格形状、高度场与插件加载Mesh 碰撞插件允许使用任意 Unity 网格做 MuJoCo 碰撞。模型编译时 MuJoCo 会调用 qhull 对网格求凸包并用凸包做碰撞。目前计算出的凸包在 Unity 中不可见官方计划在未来版本中暴露它。高度场hfieldMuJoCo hfield 在 Unity 中通过terrain GameObject表示因此可以直接使用 Unity 的地形编辑工具生成碰撞形状。在 geom 组件中选择 hfield 类型后右键上下文菜单提供把对应 Unity terrain 加入场景的工具地形数据会与仿真动态保持同步。MuJoCo 插件C 侧 extension当前 Unity 包不支持加载使用 MuJoCo 插件机制如 elasticity 插件的 MJCF 场景官方表示基础支持将随后续版本提供。与外部进程协作另一种常见的 Unity MuJoCo 组合如 Roboti 的 MuJoCo Unity 插件是在外部 Python 进程中步进仿真Unity 只负责渲染官方插件则相反由 Unity 负责步进仿真。不过这并不妨碍外部进程来“驱动”仿真例如外部进程设置qpos、调用mj_kinematics、同步 Transform再由 Unity 渲染或计算游戏逻辑。要与外部进程建立通信可以使用 Unity 的ML-Agents包。测试佐证插件的每个组件在仓库中都有对应的测试可用于验证本文描述的行为Editor 侧导入/生成测试MjImporterTests.cs、MjcfImporterTests.cs、MjSceneTests.csRuntime 侧 play 模式测试覆盖场景创建、步进与传感器读数MjScenePlayTests.cs、MjSensorPlayTests.cs、MjMeshFilterTests.cs关节与形状组件的数值测试MjJointTests.cs、MjBallJointTests.cs 等。小结MuJoCo 的 Unity 插件以“MJCF 元素 ↔ Unity 组件一一对应”为核心设计导入端用 MuJoCo 先编译再落盘的方式保证 MJCF 合法性与资源完整性运行端由MjScene扫描组件、动态生成 MJCF、编译出mjModel/mjData并按索引绑定每帧FixedUpdate中调用mj_step并回写 Unity Transform场景重建通过缓存关节状态 恢复的方式保持物理连续性。使用时的关键注意点包括按 git tag 对齐插件代码与二进制库版本、平台特定的原生库命名规则、每个 GameObject 至多一个 MuJoCo 组件、左右手坐标系 swizzle 由MjEngineTool统一处理、以及暂无 trigger 与 MuJoCo C 插件支持这两项能力边界。【免费下载链接】mujocoMulti-Joint dynamics with Contact. A general purpose physics simulator.项目地址: https://gitcode.com/GitHub_Trending/mu/mujoco创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表