Skip to content

Commit 9482229

Browse files
authored
Merge branch 'main' into yiling/250715_change_fk_position
2 parents 3b61a5e + 47bf4be commit 9482229

File tree

11 files changed

+1971
-995
lines changed

11 files changed

+1971
-995
lines changed

genesis/engine/entities/rigid_entity/rigid_entity.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,24 +127,27 @@ def _load_primitive(self, morph, surface):
127127
if isinstance(morph, gs.options.morphs.Box):
128128
extents = np.array(morph.size)
129129
tmesh = mu.create_box(extents=extents)
130+
cmesh = tmesh
130131
geom_data = extents
131132
geom_type = gs.GEOM_TYPE.BOX
132133
link_name_prefix = "box"
133134

134135
elif isinstance(morph, gs.options.morphs.Sphere):
135136
tmesh = mu.create_sphere(radius=morph.radius)
137+
cmesh = tmesh
136138
geom_data = np.array([morph.radius])
137139
geom_type = gs.GEOM_TYPE.SPHERE
138140
link_name_prefix = "sphere"
139141

140142
elif isinstance(morph, gs.options.morphs.Cylinder):
141143
tmesh = mu.create_cylinder(radius=morph.radius, height=morph.height)
144+
cmesh = tmesh
142145
geom_data = None
143146
geom_type = gs.GEOM_TYPE.MESH
144147
link_name_prefix = "cylinder"
145148

146149
elif isinstance(morph, gs.options.morphs.Plane):
147-
tmesh = mu.create_plane(normal=morph.normal)
150+
tmesh, cmesh = mu.create_plane(normal=morph.normal)
148151
geom_data = np.array(morph.normal)
149152
geom_type = gs.GEOM_TYPE.PLANE
150153
link_name_prefix = "plane"
@@ -167,7 +170,7 @@ def _load_primitive(self, morph, surface):
167170
dict(
168171
contype=1,
169172
conaffinity=1,
170-
mesh=gs.Mesh.from_trimesh(tmesh, surface=gs.surfaces.Collision()),
173+
mesh=gs.Mesh.from_trimesh(cmesh, surface=gs.surfaces.Collision()),
171174
type=geom_type,
172175
data=geom_data,
173176
sol_params=gu.default_solver_params(),

genesis/engine/solvers/rigid/array_class.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,165 @@ def __init__(self, f_batch):
212212
self.simplex_size = ti.field(gs.ti_int, shape=f_batch())
213213

214214

215+
# =========================================== GJK ===========================================
216+
@ti.data_oriented
217+
class GJKState:
218+
def __init__(self, solver, static_rigid_sim_config, gjk_static_config):
219+
_B = solver._B
220+
polytope_max_faces = gjk_static_config.polytope_max_faces
221+
max_contacts_per_pair = gjk_static_config.max_contacts_per_pair
222+
max_contact_polygon_verts = gjk_static_config.max_contact_polygon_verts
223+
224+
# Cache to store the previous support points for support mesh function.
225+
self.support_mesh_prev_vertex_id = ti.field(dtype=gs.ti_int, shape=(_B, 2))
226+
227+
### GJK simplex
228+
struct_simplex_vertex = ti.types.struct(
229+
# Support points on the two objects
230+
obj1=gs.ti_vec3,
231+
obj2=gs.ti_vec3,
232+
# Support point IDs on the two objects
233+
id1=gs.ti_int,
234+
id2=gs.ti_int,
235+
# Vertex on Minkowski difference
236+
mink=gs.ti_vec3,
237+
)
238+
struct_simplex = ti.types.struct(
239+
# Number of vertices in the simplex
240+
nverts=gs.ti_int,
241+
# Distance from the origin to the simplex
242+
dist=gs.ti_float,
243+
)
244+
struct_simplex_buffer = ti.types.struct(
245+
# Normals of the simplex faces
246+
normal=gs.ti_vec3,
247+
# Signed distances of the simplex faces from the origin
248+
sdist=gs.ti_float,
249+
)
250+
self.simplex_vertex = struct_simplex_vertex.field(shape=(_B, 4))
251+
self.simplex_buffer = struct_simplex_buffer.field(shape=(_B, 4))
252+
self.simplex = struct_simplex.field(shape=(_B,))
253+
254+
# Only when we enable MuJoCo compatibility, we use the simplex vertex and buffer for intersection checks.
255+
if static_rigid_sim_config.enable_mujoco_compatibility:
256+
self.simplex_vertex_intersect = struct_simplex_vertex.field(shape=(_B, 4))
257+
self.simplex_buffer_intersect = struct_simplex_buffer.field(shape=(_B, 4))
258+
self.nsimplex = ti.field(dtype=gs.ti_int, shape=(_B,))
259+
260+
# In safe GJK, if the initial simplex is degenerate and the geometries are discrete, we go through vertices
261+
# on the Minkowski difference to find a vertex that would make a valid simplex. To prevent iterating through
262+
# the same vertices again during initial simplex construction, we keep the vertex ID of the last vertex that
263+
# we searched, so that we can start searching from the next vertex.
264+
self.last_searched_simplex_vertex_id = ti.field(dtype=gs.ti_int, shape=(_B,))
265+
266+
### EPA polytope
267+
struct_polytope_vertex = struct_simplex_vertex
268+
struct_polytope_face = ti.types.struct(
269+
# Indices of the vertices forming the face on the polytope
270+
verts_idx=gs.ti_ivec3,
271+
# Indices of adjacent faces, one for each edge: [v1,v2], [v2,v3], [v3,v1]
272+
adj_idx=gs.ti_ivec3,
273+
# Projection of the origin onto the face, can be used as face normal
274+
normal=gs.ti_vec3,
275+
# Square of 2-norm of the normal vector, negative means deleted face
276+
dist2=gs.ti_float,
277+
# Index of the face in the polytope map, -1 for not in the map, -2 for deleted
278+
map_idx=gs.ti_int,
279+
)
280+
# Horizon is used for representing the faces to delete when the polytope is expanded by inserting a new vertex.
281+
struct_polytope_horizon_data = ti.types.struct(
282+
# Indices of faces on horizon
283+
face_idx=gs.ti_int,
284+
# Corresponding edge of each face on the horizon
285+
edge_idx=gs.ti_int,
286+
)
287+
struct_polytope = ti.types.struct(
288+
# Number of vertices in the polytope
289+
nverts=gs.ti_int,
290+
# Number of faces in the polytope (it could include deleted faces)
291+
nfaces=gs.ti_int,
292+
# Number of faces in the polytope map (only valid faces on polytope)
293+
nfaces_map=gs.ti_int,
294+
# Number of edges in the horizon
295+
horizon_nedges=gs.ti_int,
296+
# Support point on the Minkowski difference where the horizon is created
297+
horizon_w=gs.ti_vec3,
298+
)
299+
300+
self.polytope = struct_polytope.field(shape=(_B,))
301+
self.polytope_verts = struct_polytope_vertex.field(shape=(_B, 5 + gjk_static_config.epa_max_iterations))
302+
self.polytope_faces = struct_polytope_face.field(shape=(_B, polytope_max_faces))
303+
self.polytope_horizon_data = struct_polytope_horizon_data.field(
304+
shape=(_B, 6 + gjk_static_config.epa_max_iterations)
305+
)
306+
307+
# Face indices that form the polytope. The first [nfaces_map] indices are the faces that form the polytope.
308+
self.polytope_faces_map = ti.Vector.field(n=polytope_max_faces, dtype=gs.ti_int, shape=(_B,))
309+
310+
# Stack to use for visiting faces during the horizon construction. The size is (# max faces * 3),
311+
# because a face has 3 edges.
312+
self.polytope_horizon_stack = struct_polytope_horizon_data.field(shape=(_B, polytope_max_faces * 3))
313+
314+
# Data structures for multi-contact detection based on MuJoCo's implementation.
315+
if gjk_static_config.enable_mujoco_multi_contact:
316+
struct_contact_face = ti.types.struct(
317+
# Vertices from the two colliding faces
318+
vert1=gs.ti_vec3,
319+
vert2=gs.ti_vec3,
320+
endverts=gs.ti_vec3,
321+
# Normals of the two colliding faces
322+
normal1=gs.ti_vec3,
323+
normal2=gs.ti_vec3,
324+
# Face ID of the two colliding faces
325+
id1=gs.ti_int,
326+
id2=gs.ti_int,
327+
)
328+
# Struct for storing temp. contact normals
329+
struct_contact_normal = ti.types.struct(
330+
endverts=gs.ti_vec3,
331+
# Normal vector of the contact point
332+
normal=gs.ti_vec3,
333+
# Face ID
334+
id=gs.ti_int,
335+
)
336+
struct_contact_halfspace = ti.types.struct(
337+
# Halfspace normal
338+
normal=gs.ti_vec3,
339+
# Halfspace distance from the origin
340+
dist=gs.ti_float,
341+
)
342+
self.contact_faces = struct_contact_face.field(shape=(_B, max_contact_polygon_verts))
343+
self.contact_normals = struct_contact_normal.field(shape=(_B, max_contact_polygon_verts))
344+
self.contact_halfspaces = struct_contact_halfspace.field(shape=(_B, max_contact_polygon_verts))
345+
self.contact_clipped_polygons = gs.ti_vec3.field(shape=(_B, 2, max_contact_polygon_verts))
346+
347+
# Whether or not the MuJoCo's contact manifold detection algorithm was used for the current pair.
348+
self.multi_contact_flag = ti.field(dtype=gs.ti_int, shape=(_B,))
349+
350+
### Final results
351+
# Witness information
352+
struct_witness = ti.types.struct(
353+
# Witness points on the two objects
354+
point_obj1=gs.ti_vec3,
355+
point_obj2=gs.ti_vec3,
356+
)
357+
self.witness = struct_witness.field(shape=(_B, max_contacts_per_pair))
358+
self.n_witness = ti.field(dtype=gs.ti_int, shape=(_B,))
359+
360+
# Contact information, the namings are the same as those from the calling function. Even if they could be
361+
# redundant, we keep them for easier use from the calling function.
362+
self.n_contacts = ti.field(dtype=gs.ti_int, shape=(_B,))
363+
self.contact_pos = gs.ti_vec3.field(shape=(_B, max_contacts_per_pair))
364+
self.normal = gs.ti_vec3.field(shape=(_B, max_contacts_per_pair))
365+
self.is_col = ti.field(dtype=gs.ti_int, shape=(_B,))
366+
self.penetration = ti.field(dtype=gs.ti_float, shape=(_B,))
367+
368+
# Distance between the two objects.
369+
# If the objects are separated, the distance is positive.
370+
# If the objects are intersecting, the distance is negative (depth).
371+
self.distance = ti.field(dtype=gs.ti_float, shape=(_B,))
372+
373+
215374
# =========================================== SupportField ===========================================
216375
@ti.data_oriented
217376
class SupportFieldInfo:

genesis/engine/solvers/rigid/collider_decomp.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -367,13 +367,16 @@ def detection(self) -> None:
367367
self._solver.geoms_info,
368368
self._solver.geoms_init_AABB,
369369
self._solver.verts_info,
370+
self._solver.faces_info,
370371
self._solver._rigid_global_info,
371372
self._solver._static_rigid_sim_config,
372373
self._collider_state,
373374
self._collider_info,
374375
self._collider_static_config,
375376
self._mpr._mpr_state,
376377
self._mpr._mpr_static_config,
378+
self._gjk._gjk_state if self._gjk is not None else None,
379+
self._gjk._gjk_static_config if self._gjk is not None else None,
377380
self._support_field._support_field_info,
378381
self._support_field._support_field_static_config,
379382
self._mpr,
@@ -1171,13 +1174,16 @@ def _func_narrow_phase_convex_vs_convex(
11711174
geoms_info: array_class.GeomsInfo,
11721175
geoms_init_AABB: array_class.GeomsInitAABB,
11731176
verts_info: array_class.VertsInfo,
1177+
faces_info: array_class.FacesInfo,
11741178
rigid_global_info: ti.template(),
11751179
static_rigid_sim_config: ti.template(),
11761180
collider_state: ti.template(),
11771181
collider_info: ti.template(),
11781182
collider_static_config: ti.template(),
11791183
mpr_state: ti.template(),
11801184
mpr_static_config: ti.template(),
1185+
gjk_state: ti.template(),
1186+
gjk_static_config: ti.template(),
11811187
support_field_info: ti.template(),
11821188
support_field_static_config: ti.template(),
11831189
# FIXME: We need mpr, gjk, sdf, and support_field for now to call their class functions. After migration is
@@ -1224,13 +1230,16 @@ def _func_narrow_phase_convex_vs_convex(
12241230
geoms_info,
12251231
geoms_init_AABB,
12261232
verts_info,
1233+
faces_info,
12271234
rigid_global_info,
12281235
static_rigid_sim_config,
12291236
collider_state,
12301237
collider_info,
12311238
collider_static_config,
12321239
mpr_state,
12331240
mpr_static_config,
1241+
gjk_state,
1242+
gjk_static_config,
12341243
support_field_info,
12351244
support_field_static_config,
12361245
mpr,
@@ -1252,13 +1261,16 @@ def _func_narrow_phase_convex_vs_convex(
12521261
geoms_info,
12531262
geoms_init_AABB,
12541263
verts_info,
1264+
faces_info,
12551265
rigid_global_info,
12561266
static_rigid_sim_config,
12571267
collider_state,
12581268
collider_info,
12591269
collider_static_config,
12601270
mpr_state,
12611271
mpr_static_config,
1272+
gjk_state,
1273+
gjk_static_config,
12621274
support_field_info,
12631275
support_field_static_config,
12641276
mpr,
@@ -1768,13 +1780,16 @@ def _func_convex_convex_contact(
17681780
geoms_info: array_class.GeomsInfo,
17691781
geoms_init_AABB: array_class.GeomsInitAABB,
17701782
verts_info: array_class.VertsInfo,
1783+
faces_info: array_class.FacesInfo,
17711784
rigid_global_info: ti.template(),
17721785
static_rigid_sim_config: ti.template(),
17731786
collider_state: ti.template(),
17741787
collider_info: ti.template(),
17751788
collider_static_config: ti.template(),
17761789
mpr_state: ti.template(),
17771790
mpr_static_config: ti.template(),
1791+
gjk_state: ti.template(),
1792+
gjk_static_config: ti.template(),
17781793
support_field_info: ti.template(),
17791794
support_field_static_config: ti.template(),
17801795
mpr: ti.template(),
@@ -1933,21 +1948,37 @@ def _func_convex_convex_contact(
19331948
elif ti.static(
19341949
collider_static_config.ccd_algorithm in (CCD_ALGORITHM_CODE.GJK, CCD_ALGORITHM_CODE.MJ_GJK)
19351950
):
1936-
gjk.func_gjk_contact(i_ga, i_gb, i_b)
1951+
gjk.func_gjk_contact(
1952+
geoms_state,
1953+
geoms_info,
1954+
verts_info,
1955+
faces_info,
1956+
static_rigid_sim_config,
1957+
collider_state,
1958+
collider_static_config,
1959+
gjk_state,
1960+
gjk_static_config,
1961+
support_field_info,
1962+
support_field_static_config,
1963+
support_field,
1964+
i_ga,
1965+
i_gb,
1966+
i_b,
1967+
)
19371968

1938-
is_col = gjk.is_col[i_b] == 1
1939-
penetration = gjk.penetration[i_b]
1940-
n_contacts = gjk.n_contacts[i_b]
1969+
is_col = gjk_state.is_col[i_b] == 1
1970+
penetration = gjk_state.penetration[i_b]
1971+
n_contacts = gjk_state.n_contacts[i_b]
19411972

19421973
if is_col:
1943-
if gjk.multi_contact_flag[i_b]:
1974+
if gjk_state.multi_contact_flag[i_b]:
19441975
# Used MuJoCo's multi-contact algorithm to find multiple contact points. Therefore,
19451976
# add the discovered contact points and stop multi-contact search.
19461977
for i_c in range(n_contacts):
19471978
# Ignore contact points if the number of contacts exceeds the limit.
19481979
if i_c < ti.static(collider_static_config.n_contacts_per_pair):
1949-
contact_pos = gjk.contact_pos[i_b, i_c]
1950-
normal = gjk.normal[i_b, i_c]
1980+
contact_pos = gjk_state.contact_pos[i_b, i_c]
1981+
normal = gjk_state.normal[i_b, i_c]
19511982
self_unused._func_add_contact(
19521983
geoms_state,
19531984
geoms_info,
@@ -1963,8 +1994,8 @@ def _func_convex_convex_contact(
19631994

19641995
break
19651996
else:
1966-
contact_pos = gjk.contact_pos[i_b, 0]
1967-
normal = gjk.normal[i_b, 0]
1997+
contact_pos = gjk_state.contact_pos[i_b, 0]
1998+
normal = gjk_state.normal[i_b, 0]
19681999

19692000
if ti.static(collider_static_config.ccd_algorithm == CCD_ALGORITHM_CODE.MPR):
19702001
if try_sdf:

0 commit comments

Comments
 (0)