2222from .math import closest_segment_to_segment_points
2323from .math import normalize_with_norm
2424from .support import group_key
25- from .support import mat33_from_cols
2625
2726
2827@wp .struct
@@ -279,7 +278,8 @@ def plane_capsule(
279278 else :
280279 b = wp .vec3 (0.0 , 0.0 , 1.0 )
281280
282- frame = mat33_from_cols (n , b , wp .cross (n , b ))
281+ c = wp .cross (n , b )
282+ frame = wp .mat33 (n [0 ], n [1 ], n [2 ], b [0 ], b [1 ], b [2 ], c [0 ], c [1 ], c [2 ])
283283 segment = axis * cap .halfsize
284284
285285 dist1 , pos1 = _plane_sphere (n , plane .pos , cap .pos + segment , cap .radius )
@@ -289,13 +289,6 @@ def plane_capsule(
289289 write_contact (d , dist2 , pos2 , frame , margin , geom_indices , worldid )
290290
291291
292- @wp .func
293- def distance_point_plane (plane_normal : wp .vec3 , plane_pos : wp .vec3 , point : wp .vec3 ):
294- plane_normal = wp .normalize (plane_normal )
295- dist = wp .dot (point - plane_pos , plane_normal )
296- return dist , plane_pos - plane_normal * dist
297-
298-
299292@wp .func
300293def plane_box (
301294 plane : GeomPlane ,
@@ -305,29 +298,31 @@ def plane_box(
305298 margin : float ,
306299 geom_indices : wp .vec2i ,
307300):
308- contact_count = int (0 )
301+ count = int (0 )
302+ corner = wp .vec3 ()
303+ dist = wp .dot (box .pos - plane .pos , plane .normal )
309304
310- # Check all 8 corners of the box
305+ # test all corners, pick bottom 4
311306 for i in range (8 ):
312- corner = wp . vec3 ( box . size . x * 0.5 , box . size . y * 0.5 , box . size . z * 0.5 )
313- if i % 2 == 0 :
314- corner .x = - corner . x
315- if (i // 2 ) % 2 == 0 :
316- corner . y = - corner . y
317- if i < 4 :
318- corner . z = - corner . z
319-
320- corner_world = box . rot * ( corner ) + box . pos
321-
322- dist , pos = distance_point_plane ( plane . normal , plane . pos , corner_world )
323-
324- if dist < 0.0 :
325- write_contact (
326- d , dist , pos , make_frame (plane .normal ), margin , geom_indices , worldid
327- )
328- contact_count += 1
329-
330- if contact_count >= 4 :
307+ # get corner in local coordinates
308+ corner . x = wp . select ( i & 1 , - box . size . x , box . size . x )
309+ corner .y = wp . select ( i & 2 , - box . size . y , box . size . y )
310+ corner . z = wp . select (i & 4 , - box . size . z , box . size . z )
311+
312+ # get corner in global coordinates relative to box center
313+ corner = box . rot * corner
314+
315+ # compute distance to plane, skip if too far or pointing up
316+ ldist = wp . dot ( plane . normal , corner )
317+ if dist + ldist > margin or ldist > 0 :
318+ continue
319+
320+ cdist = dist + ldist
321+ frame = make_frame (plane .normal )
322+ pos = corner + box . pos + ( plane . normal * cdist / - 2.0 )
323+ write_contact ( d , cdist , pos , frame , margin , geom_indices , worldid )
324+ count += 1
325+ if count >= 4 :
331326 break
332327
333328
0 commit comments