Skip to content

Commit e5676b8

Browse files
authored
[MIGRATION] Collider migration (Genesis-Embodied-AI#1376)
1 parent 25205d0 commit e5676b8

14 files changed

+1546
-775
lines changed

genesis/engine/solvers/avatar_solver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ def get_state(self, f):
7676

7777
def print_contact_data(self):
7878
batch_idx = 0
79-
n_contacts = self.collider.n_contacts[batch_idx]
79+
n_contacts = self.collider._collider_state.n_contacts[batch_idx]
8080
print("collision_pairs:")
8181
if n_contacts > 0:
82-
contact_data = self.collider.contact_data.to_numpy()
82+
contact_data = self.collider._collider_state.contact_data.to_numpy()
8383
links_a = contact_data["link_a"][:n_contacts, batch_idx]
8484
links_b = contact_data["link_b"][:n_contacts, batch_idx]
8585
link_pairs = np.vstack([links_a, links_b]).T

genesis/engine/solvers/rigid/array_class.py

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,140 @@
44
import taichi as ti
55

66
import genesis as gs
7+
import numpy as np
78

89
# we will use struct for DofsState and DofsInfo after Hugh adds array_struct feature to taichi
910
DofsState = ti.template()
1011
DofsInfo = ti.template()
12+
GeomsState = ti.template()
13+
GeomsInfo = ti.template()
14+
GeomsInitAABB = ti.template()
15+
LinksState = ti.template()
16+
LinksInfo = ti.template()
17+
VertsInfo = ti.template()
18+
EdgesInfo = ti.template()
1119

1220

1321
@ti.data_oriented
1422
class RigidGlobalInfo:
15-
def __init__(self, n_dofs: int, n_entities: int, n_geoms: int, f_batch: Callable):
23+
def __init__(self, n_dofs: int, n_entities: int, n_geoms: int, _B: int, f_batch: Callable):
1624
self.n_awake_dofs = ti.field(dtype=gs.ti_int, shape=f_batch())
1725
self.awake_dofs = ti.field(dtype=gs.ti_int, shape=f_batch(n_dofs))
26+
27+
28+
# =========================================== Collider ===========================================
29+
30+
31+
@ti.data_oriented
32+
class ColliderState:
33+
"""
34+
Class to store the mutable collider data, all of which type is [ti.fields].
35+
"""
36+
37+
def __init__(self, solver, n_possible_pairs, n_vert_neighbors, collider_info):
38+
"""
39+
Parameters:
40+
----------
41+
n_possible_pairs: int
42+
Maximum number of possible collision pairs based on geom configurations. For instance, when adjacent
43+
collision is disabled, adjacent geoms are not considered in counting possible pairs.
44+
n_vert_neighbors: int
45+
Size of the vertex neighbors array.
46+
"""
47+
_B = solver._B
48+
f_batch = solver._batch_shape
49+
n_geoms = solver.n_geoms_
50+
n_verts = solver.n_verts_
51+
max_collision_pairs = min(solver._max_collision_pairs, n_possible_pairs)
52+
max_contact_pairs = max_collision_pairs * collider_info.n_contacts_per_pair
53+
use_hibernation = solver._static_rigid_sim_config.use_hibernation
54+
box_box_detection = solver._static_rigid_sim_config.box_box_detection
55+
56+
############## vertex connectivity ##############
57+
self.vert_neighbors = ti.field(dtype=gs.ti_int, shape=max(1, n_vert_neighbors))
58+
self.vert_neighbor_start = ti.field(dtype=gs.ti_int, shape=n_verts)
59+
self.vert_n_neighbors = ti.field(dtype=gs.ti_int, shape=n_verts)
60+
61+
############## broad phase SAP ##############
62+
# This buffer stores the AABBs along the search axis of all geoms
63+
struct_sort_buffer = ti.types.struct(value=gs.ti_float, i_g=gs.ti_int, is_max=gs.ti_int)
64+
self.sort_buffer = struct_sort_buffer.field(shape=f_batch(2 * n_geoms), layout=ti.Layout.SOA)
65+
66+
# This buffer stores indexes of active geoms during SAP search
67+
if use_hibernation:
68+
self.active_buffer_awake = ti.field(dtype=gs.ti_int, shape=f_batch(n_geoms))
69+
self.active_buffer_hib = ti.field(dtype=gs.ti_int, shape=f_batch(n_geoms))
70+
self.active_buffer = ti.field(dtype=gs.ti_int, shape=f_batch(n_geoms))
71+
72+
# Stores the validity of the collision pairs
73+
self.collision_pair_validity = ti.field(dtype=gs.ti_int, shape=(n_geoms, n_geoms))
74+
75+
# Whether or not this is the first time to run the broad phase for each batch
76+
self.first_time = ti.field(gs.ti_int, shape=_B)
77+
78+
# Number of possible pairs of collision, store them in a field to avoid recompilation
79+
self._max_possible_pairs = ti.field(dtype=gs.ti_int, shape=())
80+
self._max_collision_pairs = ti.field(dtype=gs.ti_int, shape=())
81+
self._max_contact_pairs = ti.field(dtype=gs.ti_int, shape=())
82+
83+
# Final results of the broad phase
84+
self.n_broad_pairs = ti.field(dtype=gs.ti_int, shape=_B)
85+
self.broad_collision_pairs = ti.Vector.field(2, dtype=gs.ti_int, shape=f_batch(max(1, max_collision_pairs)))
86+
87+
############## narrow phase ##############
88+
struct_contact_data = ti.types.struct(
89+
geom_a=gs.ti_int,
90+
geom_b=gs.ti_int,
91+
penetration=gs.ti_float,
92+
normal=gs.ti_vec3,
93+
pos=gs.ti_vec3,
94+
friction=gs.ti_float,
95+
sol_params=gs.ti_vec7,
96+
force=gs.ti_vec3,
97+
link_a=gs.ti_int,
98+
link_b=gs.ti_int,
99+
)
100+
self.contact_data = struct_contact_data.field(
101+
shape=f_batch(max(1, max_contact_pairs)),
102+
layout=ti.Layout.SOA,
103+
)
104+
# total number of contacts, including hibernated contacts
105+
self.n_contacts = ti.field(gs.ti_int, shape=_B)
106+
self.n_contacts_hibernated = ti.field(gs.ti_int, shape=_B)
107+
108+
# contact caching for warmstart collision detection
109+
struct_contact_cache = ti.types.struct(
110+
# i_va_ws=gs.ti_int,
111+
# penetration=gs.ti_float,
112+
normal=gs.ti_vec3,
113+
)
114+
self.contact_cache = struct_contact_cache.field(shape=f_batch((n_geoms, n_geoms)), layout=ti.Layout.SOA)
115+
116+
########## Box-box contact detection ##########
117+
if box_box_detection:
118+
# With the existing Box-Box collision detection algorithm, it is not clear where the contact points are
119+
# located depending of the pose and size of each box. In practice, up to 11 contact points have been
120+
# observed. The theoretical worst case scenario would be 2 cubes roughly the same size and same center,
121+
# with transform RPY = (45, 45, 45), resulting in 3 contact points per faces for a total of 16 points.
122+
self.box_depth = ti.field(dtype=gs.ti_float, shape=f_batch(collider_info.box_MAXCONPAIR))
123+
self.box_points = ti.field(gs.ti_vec3, shape=f_batch(collider_info.box_MAXCONPAIR))
124+
self.box_pts = ti.field(gs.ti_vec3, shape=f_batch(6))
125+
self.box_lines = ti.field(gs.ti_vec6, shape=f_batch(4))
126+
self.box_linesu = ti.field(gs.ti_vec6, shape=f_batch(4))
127+
self.box_axi = ti.field(gs.ti_vec3, shape=f_batch(3))
128+
self.box_ppts2 = ti.field(dtype=gs.ti_float, shape=f_batch((4, 2)))
129+
self.box_pu = ti.field(gs.ti_vec3, shape=f_batch(4))
130+
131+
########## Terrain contact detection ##########
132+
if collider_info.has_terrain:
133+
links_idx = solver.geoms_info.link_idx.to_numpy()[solver.geoms_info.type.to_numpy() == gs.GEOM_TYPE.TERRAIN]
134+
entity = solver._entities[solver.links_info.entity_idx.to_numpy()[links_idx[0]]]
135+
136+
self.terrain_hf = ti.field(dtype=gs.ti_float, shape=entity.terrain_hf.shape)
137+
self.terrain_rc = ti.field(dtype=gs.ti_int, shape=2)
138+
self.terrain_scale = ti.field(dtype=gs.ti_float, shape=2)
139+
self.terrain_xyz_maxmin = ti.field(dtype=gs.ti_float, shape=6)
140+
141+
# for faster compilation
142+
self.xyz_max_min = ti.field(dtype=gs.ti_float, shape=f_batch(6))
143+
self.prism = ti.field(dtype=gs.ti_vec3, shape=f_batch(6))

0 commit comments

Comments
 (0)