Skip to content

Feature/71 height fields #216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

vreutskyy
Copy link
Collaborator

This pull request introduces support for heightfield geometries in the collision detection system of the mujoco_warp library. The main changes include adding heightfield-specific data structures, functions, and logic to handle heightfield collisions, as well as extending the existing collision detection pipeline to integrate this new geometry type.

Heightfield Geometry Support

  • Heightfield Type Definition: Added HFIELD as a new geometry type in the GeomType enum and updated the Model and Data classes to include heightfield-specific attributes such as hfield_size, hfield_data, and hfield_nrow/ncol. (mujoco_warp/_src/types.py, [1] [2] [3] [4]
  • Heightfield Collision Handling: Introduced the HFPrism class and functions get_hfield_overlap_range and get_hfield_triangle_prism to calculate overlap regions and triangular prisms for heightfield collision detection. (mujoco_warp/_src/collision_hfield.py, mujoco_warp/_src/collision_hfield.pyR1-R159)

Collision Pipeline Enhancements

  • Support for Heightfield in _gjk_support_geom: Updated _gjk_support_geom to compute support points for heightfield geometries by iterating over the vertices of the triangular prism. (mujoco_warp/_src/collision_convex.py, mujoco_warp/_src/collision_convex.pyR108-R116)
  • Integration into Broadphase and Narrowphase: Modified _add_geom_pair to add collision pairs for all potentially colliding heightfield triangles. (mujoco_warp/_src/collision_driver.py, [1] [2] [3]

Data and Model Updates

  • Heightfield Data in Model Initialization: Updated put_model to populate heightfield-related attributes from the Mujoco model, and adjusted make_data to initialize heightfield-specific data arrays. (mujoco_warp/_src/io.py, [1] [2] [3]

General Codebase Adjustments

  • Heightfield-Specific Logic in _geom: Enhanced the _geom function to include heightfield triangle prism vertices when the geometry type is HFIELD. (mujoco_warp/_src/collision_primitive.py, [1] [2]
  • Imports and Dependencies: Added necessary imports for heightfield-related functionality in relevant modules. (mujoco_warp/_src/collision_driver.py, [1]; mujoco_warp/_src/collision_primitive.py, [2]

These changes collectively enable efficient and accurate collision detection for heightfield geometries, expanding the library's capabilities for handling complex terrain and surface interactions.

Copy link

google-cla bot commented May 5, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@Nate711
Copy link

Nate711 commented May 6, 2025

Do you have fps performance benchmarks for these hfields? I'm interested in fps for a simple robot against a plane and a simple robot against an hfield. Thanks!

@@ -350,6 +351,10 @@ class WrapType(enum.IntEnum):
# unsupported: PULLEY, SPHERE, CYLINDER


class vec4f(wp.types.vector(length=4, dtype=wp.float32)):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vec4f is natively supported, not sure that this is needed.
Using wp.vec4f directly should be possible.

@@ -786,6 +797,7 @@ class Model:
nsensordata: int
nlsp: int # warp only
npair: int
nhfield: int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't have nhfielddata?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Line 670 you mention that the size of hfield_data is (nhfielddata,).
You should probably add the nhfielddata property here, even if it is not used.

<geom type="box" size="0.1 0.1 0.1" rgba="0.8 0.2 0.2 1"/>
</body>

<!-- Boxes ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file needs some cleanup?
Or it is just temporary for your testing?
BTW, is it used in the test?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used it for development. I see other xml files also have some stuff commented out. What's wrong with mine? No, it's not used in UTs

@@ -86,8 +86,9 @@ def test_geom_type(self):

# TODO(team): sdf

with self.assertRaises(NotImplementedError):
mjwarp.put_model(mjm)
# seems to fail coz all above's implemented now
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you can probably delete the test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can. Are you sure no one will miss it?


Args:
m: Model containing geometry data
hfield_geom: Index of the height field geometry
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hfield_geom doesn't seem to be the correct name.
Maybe something like hfieldid?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some naming convention I can read?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to my knowledge.
Following the naming for similar properties is your best bet.

# Convert grid coordinates to local space x, y coordinates
x0 = wp.float32(i0) * x_scale - size[0]
y0 = wp.float32(j0) * y_scale - size[1]
x1 = wp.float32(i1) * x_scale - size[0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor:
I guess this should be more optimized
x1 = x0 + x_scale
y1 = y0 + y_scale

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the logic, but isn't it more confusing that it is now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both are equivalent to me. But if you think the original version is better, it's fine for me.

z11 = m.hfield_data[base_addr + j1 * ncol + i1]

# Scale heights to range [0, 1] and then to [z_bottom, z_top]
z_range = size[2]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure to understand this.
In hfield_data we have the raw data right?
So when do we scale to [0, 1]?

z11 = z11 * z_range

# Set bottom z-value
z_bottom = -size[3]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why minus here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other_margin = m.geom_margin[other_geom]
bound_radius = other_rbound + other_margin

# Calculate grid coordinates that bound the other geometry
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment correct?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's wrong with it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that what you calculate is the resolution of your hfield.

d.collision_pairid[pairid] = m.nxn_pairid[nxnid]
d.collision_worldid[pairid] = worldid
# For height field, add a collision pair for every
# triangle that can potentially collide
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will probably need to check performance here.

Adding a collision pair for every vertex may lead to large number of collision pairs, which would slow down the code and requires large amount of memory.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For each triangle, not each vertex. I create 2 pairs/triangles for each HF cell. If you don't have a HF with absurdly small cells, a body of an average size will collide with up to 4 cells - 8 triangles. Each pair is just 2 integers (plus I added an integer for tri index), and they are already pre-allocated, it's not like I allocate them when I add a pair. For the performance, for GPU it doesn't matter if it's 8 or 800 - they are all computed simultaneously. And, after all, what are the alternatives? Would like to hear them )

@Kenny-Vilella
Copy link
Collaborator

There are some unexpected contact points that are generated.
But it doesn't seem to be caused by the change in the PR.
I also see them when playing with a non-flat mesh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants