MCPcopy Create free account
hub / github.com/URLab-Sim/UnrealRoboticsLab / process_xml

Function process_xml

Scripts/clean_meshes.py:293–469  ·  view source on GitHub ↗

Parse MJCF XML, convert meshes, resolve conflicts, write updated XML.

(xml_path: Path)

Source from the content-addressed store, hash-verified

291
292 print(f"\n[inline] Materializing '{name}' -> {obj_path.name} "
293 f"({n_verts} verts, {n_faces} faces)")
294
295 # Standard OBJ — vertices are 1-indexed in OBJ but 0-indexed in MuJoCo.
296 with open(obj_path, "w", encoding="utf-8") as f:
297 f.write(f"# Generated by clean_meshes.py from inline MJCF mesh '{name}'\n")
298 for i in range(n_verts):
299 f.write(f"v {verts[i*3]:.6f} {verts[i*3+1]:.6f} {verts[i*3+2]:.6f}\n")
300 for i in range(n_faces):
301 a, b, c = faces[i*3] + 1, faces[i*3+1] + 1, faces[i*3+2] + 1
302 f.write(f"f {a} {b} {c}\n")
303
304 # Rewrite the element: drop inline data, point at the new OBJ.
305 # Path is relative to meshdir (matching how file= entries already
306 # work). We preserve scale and content_type if present.
307 rel_path = obj_path.name
308 del mesh_el.attrib["vertex"]
309 del mesh_el.attrib["face"]
310 mesh_el.set("file", rel_path)
311 if "content_type" not in mesh_el.attrib:
312 mesh_el.set("content_type", "model/obj")
313 materialized += 1
314
315 return materialized
316
317
318def process_xml(xml_path: Path):
319 """Parse MJCF XML, convert meshes, resolve conflicts, write updated XML."""
320
321 if not xml_path.exists():
322 print(f"Error: XML file not found: {xml_path}")
323 return
324
325 xml_dir = xml_path.parent
326
327 print(f"XML: {xml_path}")
328 print(f"Dir: {xml_dir}")
329 print("=" * 60)
330
331 # Parse XML
332 tree = ET.parse(str(xml_path))
333 root = tree.getroot()
334
335 # Phase -1: Flatten <include> fragments (gym-aloha and friends split robots
336 # across <mujocoinclude> files, some referenced from inside <worldbody>).
337 # After this the tree is a single self-contained <mujoco> with no includes,
338 # so mesh conversion below sees every mesh and Unreal imports one flat model.
339 include_count = sum(1 for _ in root.iter("include"))
340 if include_count:
341 print(f"Flattening {include_count} <include> fragment(s)...")
342 root = flatten_includes(root, xml_dir.resolve())
343 tree = ET.ElementTree(root)
344 remaining = sum(1 for _ in root.iter("include"))
345 print(f" -> {remaining} include(s) remain after flatten")
346
347 # Find meshdir from compiler
348 meshdir = ""
349 for compiler in root.iter("compiler"):
350 md = compiler.get("meshdir", "")

Callers 1

mainFunction · 0.85

Calls 3

flatten_includesFunction · 0.85
convert_meshFunction · 0.85

Tested by

no test coverage detected