Skip to content

fix(import): geom default resolution, GLB normals, degenerate-transform guards - #77

Merged
jonathanembleyriches merged 3 commits into
mainfrom
fix/geom-scale-and-mesh-normals
Jul 21, 2026
Merged

fix(import): geom default resolution, GLB normals, degenerate-transform guards#77
jonathanembleyriches merged 3 commits into
mainfrom
fix/geom-scale-and-mesh-normals

Conversation

@jonathanembleyriches

Copy link
Copy Markdown
Contributor

Problem

Three related import/render defects, surfaced by issue #76 and by re-importing the G1:

  1. A geom with no type attribute imports as the base UMjGeom (no renderer) instead of MJCF's global default, sphere. plane, ellipsoid and sdf were never mapped to their component classes. The G1's foot-contact geoms are all typeless.
  2. Primitive importers compute RelativeScale3D from size with a zero fallback, so a geom whose size is inherited from a <default> class bakes scale (0,0,0) into the Blueprint template. This is the source of the Scale3D is (nearly) zero physics warnings in [Bug] MjPDController attached to G1 articulation but robot remains fully unresponsive #76 and of InverseFast NIL matrix render spam once snapshot-driven transforms re-dirty the primitive every frame.
  3. clean_meshes.py exported GLBs without a NORMAL accessor, and fix_normals() silently degraded when networkx was missing (networkx was never in the plugin's Python dependency list). Every mesh then imported with degenerate tangent bases / nearly zero normals / Bad MeshDescription. Before the June 13 guard (b7a683b) the missing dep crashed the conversion, so imports fell back to the raw source mesh and looked clean, which is why this appeared to be a recent regression.

Changes

  • Parser: typeless geoms default to sphere (exempt inside <default> blocks, where forcing a type would clobber inheritance); plane/ellipsoid/sdf mapped; size resolved through the default-class chain for the editor visual while bOverride_size stays false so compile-time inheritance is untouched.
  • Primitives: new SyncEditorScaleFromSize() on sphere/cylinder/capsule/box; never writes a non-positive scale.
  • Render: MjBody::ApplyRenderState, MjGeom::UpdateGlobalTransform and MjQuickConvertComponent skip zero/NaN snapshot rows and warn once naming the component, instead of flooding the renderer anonymously.
  • Mesh pipeline: GLB export passes include_normals=True; networkx added to the dependency check/install; a failed conversion removes its stale GLB (the importer prefers .glb over the source mesh); GLBs older than the script regenerate, so previously broken GLBs self-heal on the next import.

Testing

=== URLab build+test summary ===
Timestamp : 2026-07-16 20:18:49 UTC
Git HEAD : ffffebc6 (fix/geom-scale-and-mesh-normals)
Engine : UE_5.7
Deps : mj=67a1ea6 coacd=c7436bf zmq=7d95ac0
Build : Succeeded
Tests : 269 / 269 passed (0 failed) [269 tests performed]
Log sha256: 77384db7db6ada17
================================

3 new importer tests (typeless geom is a sphere, class-inherited size keeps a non-zero editor scale with no explicit override, plane maps to UMjPlane). Verified live: G1 re-import produces no Bad MeshDescription or zero-normal warnings and PIE runs without InverseFast errors; the companion bridge fix (URLab-Sim/URLab_Bridge#3) was validated end to end against this branch with BeyondMimic on the G1.

…llipsoid/sdf
Typeless geoms default to sphere (MJCF's global default) instead of the
base UMjGeom; primitives never bake a zero RelativeScale3D when size is
class-inherited (new SyncEditorScaleFromSize, size resolved through the
default-class chain without setting bOverride_size).
A zero or non-finite snapshot row applied via SetWorldLocationAndRotation
NaN-floods the renderer (InverseFast NIL matrix in the distance-field
pass) with nothing naming the offender. Skip the frame and warn once
with the component name.
trimesh omits the NORMAL accessor unless include_normals is passed, and
fix_normals needs networkx, which the dependency installer never listed.
Missing networkx now fails the conversion (source-mesh fallback) instead
of writing a normal-less GLB; failed/stale GLBs are removed and GLBs
older than the script regenerate.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant

@jonathanembleyriches