|
4 | 4 | import taichi as ti |
5 | 5 |
|
6 | 6 | import genesis as gs |
| 7 | +import numpy as np |
7 | 8 |
|
8 | 9 | # we will use struct for DofsState and DofsInfo after Hugh adds array_struct feature to taichi |
9 | 10 | DofsState = ti.template() |
10 | 11 | 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() |
11 | 19 |
|
12 | 20 |
|
13 | 21 | @ti.data_oriented |
14 | 22 | 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): |
16 | 24 | self.n_awake_dofs = ti.field(dtype=gs.ti_int, shape=f_batch()) |
17 | 25 | 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