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