@@ -92,60 +92,48 @@ def _build_newton_builder_from_mapping(
9292 quaternions = torch .zeros ((mapping .size (1 ), 4 ), device = mapping .device , dtype = torch .float32 )
9393 quaternions [:, 3 ] = 1.0
9494
95- # Main builder: loads only ground plane, lights, and scene-level prims.
96- # /World/envs (and all source asset paths) are excluded via ignore_paths.
97- #
98- # ``SolverMuJoCo.register_custom_attributes`` is intentionally NOT called on
99- # the main builder. Doing so would register the ``mujoco:*`` custom
100- # frequencies, whose traversal uses ``stage.Traverse()`` and ignores
101- # ``ignore_paths``. The traversal would find ``MjcTendon`` prims under
102- # ``/World/envs/...`` and try to resolve their joint paths against the main
103- # builder's empty ``joint_label`` (no joints loaded), emitting "unknown
104- # joint path" warnings and silently dropping every tendon.
105- main_resolvers = [SchemaResolverNewton (), SchemaResolverPhysx ()]
95+ # ``SchemaResolverMjc`` is intentionally EXCLUDED from the resolver chain:
96+ # ``MjcTendon`` prims are parsed by the ``mujoco:*`` custom frequencies
97+ # (registered via ``SolverMuJoCo.register_custom_attributes`` on each proto
98+ # below), not by the schema-resolver chain. Adding ``SchemaResolverMjc``
99+ # would change which schema wins for non-tendon properties (shape margins/
100+ # gaps, joint limit ke/kd, armature, material stiffness/damping) on MJCF-
101+ # derived USDs that also carry ``physx:``/``newton:`` authoring — those
102+ # should keep their current Newton/PhysX precedence.
103+ schema_resolvers = [SchemaResolverNewton (), SchemaResolverPhysx ()]
106104 builder = NewtonManager .create_builder (up_axis = up_axis )
107105 stage_info = builder .add_usd (
108106 stage ,
109107 ignore_paths = ["/World/envs" ] + sources ,
110- schema_resolvers = main_resolvers ,
108+ schema_resolvers = schema_resolvers ,
111109 )
112110
113- # Proto resolvers match the main builder. SchemaResolverMjc is intentionally
114- # EXCLUDED: MjcTendon prims are parsed by the ``mujoco:*`` custom frequencies
115- # (registered via ``SolverMuJoCo.register_custom_attributes`` below), not by
116- # the schema-resolver chain. Adding ``SchemaResolverMjc`` would change which
117- # schema wins for non-tendon properties (shape margins/gaps, joint limit
118- # ke/kd, armature, material stiffness/damping) on MJCF-derived USDs that
119- # also carry ``physx:``/``newton:`` authoring — those should keep their
120- # current Newton/PhysX precedence.
121- # Both resolver classes are stateless (no instance fields); sharing one set
122- # across proto builders is safe.
123- proto_resolvers = [SchemaResolverNewton (), SchemaResolverPhysx ()]
124-
125111 # The prototype is built from env_0 in absolute world coordinates.
126112 # add_builder xforms are deltas from env_0 so positions don't get double-counted.
127113 env0_pos = positions [0 ]
128114 protos : dict [str , ModelBuilder ] = {}
129115 for src_path in sources :
130- # ``register_custom_attributes`` registers the ``mujoco:*`` custom
131- # frequencies on this builder, which is what drives MjcTendon parsing
132- # (the resolver chain does not). It must run before ``add_usd`` so the
133- # custom-frequency traversal can resolve MjcTendon joint paths against
134- # this proto's fully populated joint_label.
116+ # ``register_custom_attributes`` is what drives ``MjcTendon`` parsing
117+ # (not the resolver chain). It must run before ``add_usd`` so the
118+ # custom-frequency traversal can resolve ``MjcTendon`` joint paths
119+ # against this proto's fully populated ``joint_label``. It is NOT
120+ # called on the main builder above: the traversal ignores
121+ # ``ignore_paths`` and would find ``MjcTendon`` prims under
122+ # ``/World/envs/...`` and silently drop them against the main
123+ # builder's empty ``joint_label``.
135124 p = NewtonManager .create_builder (up_axis = up_axis )
136125 solvers .SolverMuJoCo .register_custom_attributes (p )
137- # Newton's custom-frequency traversal uses stage.Traverse() unconditionally,
138- # ignoring root_path. In heterogeneous plans with multiple MJCF sources that
139- # each have tendons, proto A's traversal would also find source B's MjcTendon
140- # prims. Patch the filters to restrict them to src_path so only this proto's
141- # own tendons are resolved.
126+ # Newton's custom-frequency traversal uses ``stage.Traverse()``
127+ # unconditionally, ignoring ``root_path``. Without scoping, proto A's
128+ # traversal would also match source B's ``MjcTendon`` prims in
129+ # heterogeneous-source plans.
142130 _scope_custom_frequencies (p , src_path )
143131 p .add_usd (
144132 stage ,
145133 root_path = src_path ,
146134 load_visual_shapes = True ,
147135 skip_mesh_approximation = True ,
148- schema_resolvers = proto_resolvers ,
136+ schema_resolvers = schema_resolvers ,
149137 )
150138 if simplify_meshes :
151139 p .approximate_meshes ("convex_hull" , keep_visual_shapes = True )
0 commit comments