AI agent skill · by @AgibotTech
Material Override
Tune PBR metallic / roughness on URDF visual meshes without re-exporting DAE — author an inline `<material_override>` element inside any `<visual>`, and let the engine's URDF→USD pipeline patch the converter's defaults post-conversion. Useful for sim-to-real visual fidelity (DAE materials round-trip poorly; Isaac Sim's importer lands every embedded material at roughness=0.5, metallic=0.0 by default). Trigger: When the user asks to "tune material", "change roughness / metallic", "make the gripper shinier", "fix dull PBR", "override material", "PBR override", or any time the simulator looks washed out after a URDF→USD import.
Archived 2026-10-23 · Source updated 2026-09-07 · License: MPL-2.0. Check the original repository for the latest version.
SKILL.md instructions
## When to Use
- Robot or asset visual meshes import with washed-out / flat
shading after the URDF→USD converter runs.
- User wants to A/B PBR values without re-exporting DAE meshes from
Blender / Maya.
- Polishing a robot for sim-to-real visual transfer.
- Author of a new URDF (see `add-robot` skill) wants the meshes to
look right without round-tripping DAE materials.
Do **not** use for:
- Replacing albedo / textures → must be done in the DAE export.
- Per-prim material at runtime → that's a runtime USD edit, not the
`<material_override>` element.
- Adding a brand-new material — only patches metallic / roughness on
the embedded one.
## Critical Patterns
1. **Author inside `<visual>`, not on the link.** The override
auto-scopes to exactly the mesh it sits under. A link with N
`<visual>` elements just gets N independent overrides.
2. **`urdfdom` / RSP / MoveIt / Isaac's converter all ignore it.**
`assemble_robot.py` strips the element from the URDF it feeds the
converter, then re-applies the values to the converted USD via
`_parse_material_override_blocks` / `_apply_material_overrides`.
3. **Only `roughness` and `metallic` are exposed.** Other UsdPreviewSurface
inputs (specular, opacity, IOR) are not on the contract.
4. **Range 0..1.** Outside that range the importer warns and clamps.
5. **No attributes needed.** Scoping is positional. Don't try to
target a sibling visual by name — author one override per visual.
## Schema
```xml
<visual>
<origin xyz="0 0 0" rpy="0 0 0"/>
<geometry>
<mesh filename="package://.../base_link.dae"/>
</geometry>
<material_override>
<roughness>0.45</roughness>
<metallic>0.85</metallic>
</material_override>
</visual>
```
Either child is optional — author only what you need. Default for
an absent child is "leave as the converter wrote it" (typically
0.5 / 0.0 for DAE imports).
## PBR cheat-sheet
| Look | `roughness` | `metallic` | Notes |
|---|---|---|---|
| Brushed steel | 0.40 | 0.95 | Most arm shells |
| Anodised aluminium | 0.55 | 0.30 | UR-style structural |
| Polished chrome | 0.05 | 1.00 | Decorative trims, mirror parts |
| Matte plastic | 0.70 | 0.00 | Cable guards, end-stops |
| Rubber pads | 0.85 | 0.00 | Soft contact surfaces |
| Anodised gold (gripper bushings) | 0.30 | 0.90 | Highlights |
These are starting points; A/B against a photograph of the real
robot if you have one.
## Workflow
### Step 1 — Find the visual you want to tune
```bash
# Locate the URDF / xacro under genie_sim_robot_model
grep -nR "<visual>" source/geniesim_ros/src/ros_ws/src/genie_sim_robot_model/robots/ | head
```
### Step 2 — Add the override
Open the xacro, drop `<material_override>` into the `<visual>`
block. Existing reference: aloha arm xacro carries an override on
every visual:
```xml
<visual>
<origin xyz="0 0 0" rpy="0 0 0" />
<geometry>
<mesh filename="${mesh_dir}/base_link.dae" />
</geometry>
<material_override><roughness>0.45</roughness><metallic>0.85</metallic></material_override>
</visual>
```
### Step 3 — Rebuild the workspace
```bash
geniesim ros build dev && source devel/setup.bash
```
### Step 4 — Force a USD regenerate
The robot USD is cache-gated by `manifest.json`. Bust the cache:
```bash
rm -rf assets/scenes/<scene>/
# OR pass at launch:
ros2 launch genie_sim_bringup app.launch.py … always_regenerate_robot_usd:=true
```
### Step 5 — Launch and inspect
```bash
ros2 launch genie_sim_bringup app.launch.py \
scene:=<scene> \
launcher_config:=launcher_ovrtx_isaac_physx \
headless:=false # local workstation with a screen; flip to true on a remote/headless host
```
In the OVRtx viewport, compare against the unmodified baseline.
Iterate values, rebuild, re-launch.
### Step 6 — Verify the converted USD
```bash
grep -n "roughness\|metallic" assets/scenes/<scene>/robot/robot.usda | head
```
You should see the patched values on the relevant material prims.
## Notes
- `assemble_robot.py` walks each `<visual>` in author order; if a
visual has multiple meshes (rare in our robots), the override
applies to every embedded material of that visual.
- The override is stripped from the URDF *before* it reaches the
converter, so MoveIt / RSP / urdfdom never see it. They'll happily
consume the same xacro.
- For brand-new materials (no DAE-embedded source), prefer authoring
a real `<material>` block — material_override is patch-only.
- Material is rendered by OVRtx + Isaac Sim. The Newton GL viewer
uses simple shading and won't reflect roughness / metallic — use
OVRtx for visual QA.
## Resources
- **Engine source**: [source/geniesim_ros/src/ros_ws/src/genie_sim_engine/scripts/assemble_robot.py](../../src/ros_ws/src/genie_sim_engine/scripts/assemble_robot.py) → `_parse_material_override_blocks` / `_apply_material_overrides`
- **Reference usage**: [source/geniesim_ros/src/ros_ws/src/genie_sim_robot_model/robots/agilex/aloha/aloha.urdf.xacro](../../src/ros_ws/src/genie_sim_robot_model/robots/agilex/aloha/aloha.urdf.xacro)
- **Engine AGENTS.md** → "<material_override>": [source/geniesim_ros/src/ros_ws/src/genie_sim_engine/AGENTS.md](../../src/ros_ws/src/genie_sim_engine/AGENTS.md)
- **Related skills**: `add-robot`, `launch-scene`