warp-lang 0.15.0__py3-none-manylinux2014_x86_64.whl → 1.0.0__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (80) hide show
  1. warp/__init__.py +1 -0
  2. warp/codegen.py +7 -3
  3. warp/config.py +2 -1
  4. warp/constants.py +3 -0
  5. warp/context.py +44 -21
  6. warp/examples/assets/bunny.usd +0 -0
  7. warp/examples/assets/cartpole.urdf +110 -0
  8. warp/examples/assets/crazyflie.usd +0 -0
  9. warp/examples/assets/cube.usda +42 -0
  10. warp/examples/assets/nv_ant.xml +92 -0
  11. warp/examples/assets/nv_humanoid.xml +183 -0
  12. warp/examples/assets/quadruped.urdf +268 -0
  13. warp/examples/assets/rocks.nvdb +0 -0
  14. warp/examples/assets/rocks.usd +0 -0
  15. warp/examples/assets/sphere.usda +56 -0
  16. warp/examples/assets/torus.usda +105 -0
  17. warp/examples/core/example_dem.py +6 -6
  18. warp/examples/core/example_fluid.py +3 -3
  19. warp/examples/core/example_graph_capture.py +3 -6
  20. warp/examples/optim/example_bounce.py +9 -8
  21. warp/examples/optim/example_cloth_throw.py +12 -8
  22. warp/examples/optim/example_diffray.py +10 -12
  23. warp/examples/optim/example_drone.py +31 -14
  24. warp/examples/optim/example_spring_cage.py +10 -15
  25. warp/examples/optim/example_trajectory.py +7 -24
  26. warp/examples/sim/example_cartpole.py +3 -9
  27. warp/examples/sim/example_cloth.py +10 -10
  28. warp/examples/sim/example_granular.py +3 -3
  29. warp/examples/sim/example_granular_collision_sdf.py +9 -4
  30. warp/examples/sim/example_jacobian_ik.py +0 -10
  31. warp/examples/sim/example_particle_chain.py +4 -4
  32. warp/examples/sim/example_quadruped.py +15 -11
  33. warp/examples/sim/example_rigid_chain.py +13 -8
  34. warp/examples/sim/example_rigid_contact.py +4 -4
  35. warp/examples/sim/example_rigid_force.py +7 -7
  36. warp/examples/sim/example_rigid_soft_contact.py +4 -4
  37. warp/examples/sim/example_soft_body.py +3 -3
  38. warp/jax.py +45 -0
  39. warp/jax_experimental.py +339 -0
  40. warp/render/render_opengl.py +188 -95
  41. warp/render/render_usd.py +34 -10
  42. warp/sim/__init__.py +13 -4
  43. warp/sim/articulation.py +4 -5
  44. warp/sim/collide.py +320 -175
  45. warp/sim/import_mjcf.py +25 -30
  46. warp/sim/import_urdf.py +94 -63
  47. warp/sim/import_usd.py +51 -36
  48. warp/sim/inertia.py +3 -2
  49. warp/sim/integrator.py +233 -0
  50. warp/sim/integrator_euler.py +447 -469
  51. warp/sim/integrator_featherstone.py +1991 -0
  52. warp/sim/integrator_xpbd.py +1420 -640
  53. warp/sim/model.py +741 -487
  54. warp/sim/particles.py +2 -1
  55. warp/sim/render.py +18 -2
  56. warp/sim/utils.py +222 -11
  57. warp/stubs.py +1 -0
  58. warp/tape.py +6 -9
  59. warp/tests/test_examples.py +87 -20
  60. warp/tests/test_grad_customs.py +122 -0
  61. warp/tests/test_jax.py +254 -0
  62. warp/tests/test_options.py +13 -53
  63. warp/tests/test_quat.py +23 -0
  64. warp/tests/test_snippet.py +2 -0
  65. warp/tests/test_utils.py +31 -26
  66. warp/tests/test_verify_fp.py +65 -0
  67. warp/tests/unittest_suites.py +4 -0
  68. warp/utils.py +50 -1
  69. {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/METADATA +1 -1
  70. {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +73 -64
  71. warp/examples/env/__init__.py +0 -0
  72. warp/examples/env/env_ant.py +0 -61
  73. warp/examples/env/env_cartpole.py +0 -63
  74. warp/examples/env/env_humanoid.py +0 -65
  75. warp/examples/env/env_usd.py +0 -97
  76. warp/examples/env/environment.py +0 -526
  77. warp/sim/optimizer.py +0 -138
  78. {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/LICENSE.md +0 -0
  79. {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
  80. {warp_lang-0.15.0.dist-info → warp_lang-1.0.0.dist-info}/top_level.txt +0 -0
@@ -667,6 +667,45 @@ class ShapeInstancer:
667
667
 
668
668
  self.face_count = len(indices)
669
669
 
670
+ def update_colors(self, colors1, colors2):
671
+ from pyglet import gl
672
+
673
+ if colors1 is None:
674
+ colors1 = np.tile(self.color1, (self.num_instances, 1))
675
+ if colors2 is None:
676
+ colors2 = np.tile(self.color2, (self.num_instances, 1))
677
+ if np.shape(colors1) != (self.num_instances, 3):
678
+ colors1 = np.tile(colors1, (self.num_instances, 1))
679
+ if np.shape(colors2) != (self.num_instances, 3):
680
+ colors2 = np.tile(colors2, (self.num_instances, 1))
681
+ colors1 = np.array(colors1, dtype=np.float32)
682
+ colors2 = np.array(colors2, dtype=np.float32)
683
+
684
+ gl.glBindVertexArray(self.vao)
685
+
686
+ # create buffer for checkerboard colors
687
+ if self.instance_color1_buffer is None:
688
+ self.instance_color1_buffer = gl.GLuint()
689
+ gl.glGenBuffers(1, self.instance_color1_buffer)
690
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color1_buffer)
691
+ gl.glBufferData(gl.GL_ARRAY_BUFFER, colors1.nbytes, colors1.ctypes.data, gl.GL_STATIC_DRAW)
692
+
693
+ if self.instance_color2_buffer is None:
694
+ self.instance_color2_buffer = gl.GLuint()
695
+ gl.glGenBuffers(1, self.instance_color2_buffer)
696
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color2_buffer)
697
+ gl.glBufferData(gl.GL_ARRAY_BUFFER, colors2.nbytes, colors2.ctypes.data, gl.GL_STATIC_DRAW)
698
+
699
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color1_buffer)
700
+ gl.glVertexAttribPointer(7, 3, gl.GL_FLOAT, gl.GL_FALSE, colors1[0].nbytes, ctypes.c_void_p(0))
701
+ gl.glEnableVertexAttribArray(7)
702
+ gl.glVertexAttribDivisor(7, 1)
703
+
704
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color2_buffer)
705
+ gl.glVertexAttribPointer(8, 3, gl.GL_FLOAT, gl.GL_FALSE, colors2[0].nbytes, ctypes.c_void_p(0))
706
+ gl.glEnableVertexAttribArray(8)
707
+ gl.glVertexAttribDivisor(8, 1)
708
+
670
709
  def allocate_instances(self, positions, rotations=None, colors1=None, colors2=None, scalings=None):
671
710
  from pyglet import gl
672
711
 
@@ -723,31 +762,11 @@ class ShapeInstancer:
723
762
  int(self.instance_transform_gl_buffer.value), self.device
724
763
  )
725
764
 
726
- if colors1 is None:
727
- colors1 = np.tile(self.color1, (self.num_instances, 1))
728
- if colors2 is None:
729
- colors2 = np.tile(self.color2, (self.num_instances, 1))
730
- colors1 = np.array(colors1, dtype=np.float32)
731
- colors2 = np.array(colors2, dtype=np.float32)
732
-
733
- # create buffer for checkerboard colors
734
- if self.instance_color1_buffer is None:
735
- self.instance_color1_buffer = gl.GLuint()
736
- gl.glGenBuffers(1, self.instance_color1_buffer)
737
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color1_buffer)
738
- gl.glBufferData(gl.GL_ARRAY_BUFFER, colors1.nbytes, colors1.ctypes.data, gl.GL_STATIC_DRAW)
739
-
740
- if self.instance_color2_buffer is None:
741
- self.instance_color2_buffer = gl.GLuint()
742
- gl.glGenBuffers(1, self.instance_color2_buffer)
743
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color2_buffer)
744
- gl.glBufferData(gl.GL_ARRAY_BUFFER, colors2.nbytes, colors2.ctypes.data, gl.GL_STATIC_DRAW)
765
+ self.update_colors(colors1, colors2)
745
766
 
746
767
  # Set up instance attribute pointers
747
768
  matrix_size = vbo_transforms[0].nbytes
748
769
 
749
- gl.glBindVertexArray(self.vao)
750
-
751
770
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_transform_gl_buffer)
752
771
 
753
772
  # we can only send vec4s to the shader, so we need to split the instance transforms matrix into its column vectors
@@ -758,16 +777,6 @@ class ShapeInstancer:
758
777
  gl.glEnableVertexAttribArray(3 + i)
759
778
  gl.glVertexAttribDivisor(3 + i, 1)
760
779
 
761
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color1_buffer)
762
- gl.glVertexAttribPointer(7, 3, gl.GL_FLOAT, gl.GL_FALSE, colors1[0].nbytes, ctypes.c_void_p(0))
763
- gl.glEnableVertexAttribArray(7)
764
- gl.glVertexAttribDivisor(7, 1)
765
-
766
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.instance_color2_buffer)
767
- gl.glVertexAttribPointer(8, 3, gl.GL_FLOAT, gl.GL_FALSE, colors2[0].nbytes, ctypes.c_void_p(0))
768
- gl.glEnableVertexAttribArray(8)
769
- gl.glVertexAttribDivisor(8, 1)
770
-
771
780
  gl.glBindVertexArray(0)
772
781
 
773
782
  def update_instances(self, transforms: wp.array = None, scalings: wp.array = None, colors1=None, colors2=None):
@@ -808,6 +817,9 @@ class ShapeInstancer:
808
817
 
809
818
  self._instance_transform_cuda_buffer.unmap()
810
819
 
820
+ if colors1 is not None or colors2 is not None:
821
+ self.update_colors(colors1, colors2)
822
+
811
823
  def render(self):
812
824
  from pyglet import gl
813
825
 
@@ -914,9 +926,6 @@ class OpenGLRenderer:
914
926
  self.enable_mouse_interaction = enable_mouse_interaction
915
927
  self.enable_keyboard_interaction = enable_keyboard_interaction
916
928
 
917
- self._camera_pos = PyVec3(*camera_pos)
918
- self._camera_front = PyVec3(*camera_front)
919
- self._camera_up = PyVec3(*camera_up)
920
929
  self._camera_speed = 0.04
921
930
  if isinstance(up_axis, int):
922
931
  self._camera_axis = up_axis
@@ -927,12 +936,19 @@ class OpenGLRenderer:
927
936
  self._first_mouse = True
928
937
  self._left_mouse_pressed = False
929
938
  self._keys_pressed = defaultdict(bool)
939
+ self._input_processors = []
930
940
  self._key_callbacks = []
931
941
 
932
942
  self.render_2d_callbacks = []
933
943
  self.render_3d_callbacks = []
934
944
 
935
- self.update_view_matrix()
945
+ self._camera_pos = PyVec3(0.0, 0.0, 0.0)
946
+ self._camera_front = PyVec3(0.0, 0.0, -1.0)
947
+ self._camera_up = PyVec3(0.0, 1.0, 0.0)
948
+ self._scaling = scaling
949
+
950
+ self._model_matrix = self.compute_model_matrix(self._camera_axis, scaling)
951
+ self.update_view_matrix(cam_pos=camera_pos, cam_front=camera_front, cam_up=camera_up)
936
952
  self.update_projection_matrix()
937
953
 
938
954
  self._frame_dt = 1.0 / fps
@@ -1549,37 +1565,65 @@ class OpenGLRenderer:
1549
1565
  self.camera_fov, aspect_ratio, self.camera_near_plane, self.camera_far_plane
1550
1566
  )
1551
1567
 
1552
- def update_view_matrix(self):
1553
- from pyglet.math import Mat4 as PyMat4
1568
+ @property
1569
+ def camera_pos(self):
1570
+ return self._camera_pos
1571
+
1572
+ @camera_pos.setter
1573
+ def camera_pos(self, value):
1574
+ self.update_view_matrix(cam_pos=value)
1575
+
1576
+ @property
1577
+ def camera_front(self):
1578
+ return self._camera_front
1554
1579
 
1555
- cam_pos = self._camera_pos
1556
- self._view_matrix = np.array(PyMat4.look_at(cam_pos, cam_pos + self._camera_front, self._camera_up))
1580
+ @camera_front.setter
1581
+ def camera_front(self, value):
1582
+ self.update_view_matrix(cam_front=value)
1557
1583
 
1558
- def update_model_matrix(self):
1584
+ @property
1585
+ def camera_up(self):
1586
+ return self._camera_up
1587
+
1588
+ @camera_up.setter
1589
+ def camera_up(self, value):
1590
+ self.update_view_matrix(cam_up=value)
1591
+
1592
+ def update_view_matrix(self, cam_pos=None, cam_front=None, cam_up=None, stiffness=1.0):
1593
+ from pyglet.math import Vec3, Mat4
1594
+
1595
+ if cam_pos is not None:
1596
+ self._camera_pos = self._camera_pos * (1.0 - stiffness) + Vec3(*cam_pos) * stiffness
1597
+ if cam_front is not None:
1598
+ self._camera_front = self._camera_front * (1.0 - stiffness) + Vec3(*cam_front) * stiffness
1599
+ if cam_up is not None:
1600
+ self._camera_up = self._camera_up * (1.0 - stiffness) + Vec3(*cam_up) * stiffness
1601
+
1602
+ model = np.array(self._model_matrix).reshape((4, 4))
1603
+ cp = model @ np.array([*self._camera_pos / self._scaling, 1.0])
1604
+ cf = model @ np.array([*self._camera_front / self._scaling, 1.0])
1605
+ up = model @ np.array([*self._camera_up / self._scaling, 0.0])
1606
+ cp = Vec3(*cp[:3])
1607
+ cf = Vec3(*cf[:3])
1608
+ up = Vec3(*up[:3])
1609
+ self._view_matrix = np.array(Mat4.look_at(cp, cp + cf, up))
1610
+
1611
+ def compute_model_matrix(self, camera_axis: int, scaling: float):
1612
+ if camera_axis == 0:
1613
+ return np.array((0, 0, scaling, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 0, 1))
1614
+ elif camera_axis == 2:
1615
+ return np.array((-scaling, 0, 0, 0, 0, 0, scaling, 0, 0, scaling, 0, 0, 0, 0, 0, 1))
1616
+
1617
+ return np.array((scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, scaling, 0, 0, 0, 0, 1))
1618
+
1619
+ def update_model_matrix(self, model_matrix: Optional[Mat44] = None):
1559
1620
  from pyglet import gl
1560
1621
 
1561
1622
  # fmt: off
1562
- if self._camera_axis == 0:
1563
- self._model_matrix = np.array((
1564
- 0, 0, self._scaling, 0,
1565
- self._scaling, 0, 0, 0,
1566
- 0, self._scaling, 0, 0,
1567
- 0, 0, 0, 1
1568
- ))
1569
- elif self._camera_axis == 2:
1570
- self._model_matrix = np.array((
1571
- -self._scaling, 0, 0, 0,
1572
- 0, 0, self._scaling, 0,
1573
- 0, self._scaling, 0, 0,
1574
- 0, 0, 0, 1
1575
- ))
1623
+ if model_matrix is None:
1624
+ self._model_matrix = self.compute_model_matrix(self._camera_axis, self._scaling)
1576
1625
  else:
1577
- self._model_matrix = np.array((
1578
- self._scaling, 0, 0, 0,
1579
- 0, self._scaling, 0, 0,
1580
- 0, 0, self._scaling, 0,
1581
- 0, 0, 0, 1
1582
- ))
1626
+ self._model_matrix = np.array(model_matrix).flatten()
1583
1627
  # fmt: on
1584
1628
  ptr = arr_pointer(self._model_matrix)
1585
1629
  gl.glUseProgram(self._shape_shader.id)
@@ -1890,6 +1934,10 @@ Instances: {len(self._instances)}"""
1890
1934
  import pyglet
1891
1935
  from pyglet.math import Vec3 as PyVec3
1892
1936
 
1937
+ for cb in self._input_processors:
1938
+ if cb(self._key_handler) == pyglet.event.EVENT_HANDLED:
1939
+ return
1940
+
1893
1941
  if self._key_handler[pyglet.window.key.W] or self._key_handler[pyglet.window.key.UP]:
1894
1942
  self._camera_pos += self._camera_front * (self._camera_speed * self._frame_speed)
1895
1943
  self.update_view_matrix()
@@ -1905,12 +1953,19 @@ Instances: {len(self._instances)}"""
1905
1953
  self._camera_pos += camera_side * (self._camera_speed * self._frame_speed)
1906
1954
  self.update_view_matrix()
1907
1955
 
1956
+ def register_input_processor(self, callback):
1957
+ self._input_processors.append(callback)
1958
+
1908
1959
  def _key_press_callback(self, symbol, modifiers):
1909
1960
  import pyglet
1910
1961
 
1911
1962
  if not self.enable_keyboard_interaction:
1912
1963
  return
1913
1964
 
1965
+ for cb in self._key_callbacks:
1966
+ if cb(symbol, modifiers) == pyglet.event.EVENT_HANDLED:
1967
+ return pyglet.event.EVENT_HANDLED
1968
+
1914
1969
  if symbol == pyglet.window.key.ESCAPE:
1915
1970
  self.close()
1916
1971
  if symbol == pyglet.window.key.SPACE:
@@ -1930,9 +1985,6 @@ Instances: {len(self._instances)}"""
1930
1985
  if symbol == pyglet.window.key.B:
1931
1986
  self.enable_backface_culling = not self.enable_backface_culling
1932
1987
 
1933
- for cb in self._key_callbacks:
1934
- cb(symbol, modifiers)
1935
-
1936
1988
  def register_key_press_callback(self, callback):
1937
1989
  self._key_callbacks.append(callback)
1938
1990
 
@@ -2018,6 +2070,34 @@ Instances: {len(self._instances)}"""
2018
2070
  self._instance_count = len(self._instances)
2019
2071
  return instance
2020
2072
 
2073
+ def update_instance_colors(self):
2074
+ from pyglet import gl
2075
+
2076
+ colors1, colors2 = [], []
2077
+ all_instances = list(self._instances.values())
2078
+ for shape, instances in self._shape_instances.items():
2079
+ for i in instances:
2080
+ if i >= len(all_instances):
2081
+ continue
2082
+ instance = all_instances[i]
2083
+ colors1.append(instance[5])
2084
+ colors2.append(instance[6])
2085
+ colors1 = np.array(colors1, dtype=np.float32)
2086
+ colors2 = np.array(colors2, dtype=np.float32)
2087
+
2088
+ # create buffer for checkerboard colors
2089
+ if self._instance_color1_buffer is None:
2090
+ self._instance_color1_buffer = gl.GLuint()
2091
+ gl.glGenBuffers(1, self._instance_color1_buffer)
2092
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
2093
+ gl.glBufferData(gl.GL_ARRAY_BUFFER, colors1.nbytes, colors1.ctypes.data, gl.GL_STATIC_DRAW)
2094
+
2095
+ if self._instance_color2_buffer is None:
2096
+ self._instance_color2_buffer = gl.GLuint()
2097
+ gl.glGenBuffers(1, self._instance_color2_buffer)
2098
+ gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
2099
+ gl.glBufferData(gl.GL_ARRAY_BUFFER, colors2.nbytes, colors2.ctypes.data, gl.GL_STATIC_DRAW)
2100
+
2021
2101
  def allocate_shape_instances(self):
2022
2102
  from pyglet import gl
2023
2103
 
@@ -2051,28 +2131,7 @@ Instances: {len(self._instances)}"""
2051
2131
  int(self._instance_transform_gl_buffer.value), self._device
2052
2132
  )
2053
2133
 
2054
- colors1, colors2 = [], []
2055
- all_instances = list(self._instances.values())
2056
- for shape, instances in self._shape_instances.items():
2057
- for i in instances:
2058
- if i >= len(all_instances):
2059
- continue
2060
- instance = all_instances[i]
2061
- colors1.append(instance[5])
2062
- colors2.append(instance[6])
2063
- colors1 = np.array(colors1, dtype=np.float32)
2064
- colors2 = np.array(colors2, dtype=np.float32)
2065
-
2066
- # create buffer for checkerboard colors
2067
- self._instance_color1_buffer = gl.GLuint()
2068
- gl.glGenBuffers(1, self._instance_color1_buffer)
2069
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
2070
- gl.glBufferData(gl.GL_ARRAY_BUFFER, colors1.nbytes, colors1.ctypes.data, gl.GL_STATIC_DRAW)
2071
-
2072
- self._instance_color2_buffer = gl.GLuint()
2073
- gl.glGenBuffers(1, self._instance_color2_buffer)
2074
- gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
2075
- gl.glBufferData(gl.GL_ARRAY_BUFFER, colors2.nbytes, colors2.ctypes.data, gl.GL_STATIC_DRAW)
2134
+ self.update_instance_colors()
2076
2135
 
2077
2136
  # set up instance attribute pointers
2078
2137
  matrix_size = transforms[0].nbytes
@@ -2083,6 +2142,7 @@ Instances: {len(self._instances)}"""
2083
2142
  instances = list(self._instances.values())
2084
2143
  inverse_instance_ids = {}
2085
2144
  instance_count = 0
2145
+ colors_size = np.zeros(3, dtype=np.float32).nbytes
2086
2146
  for shape, (vao, vbo, ebo, tri_count, vertex_cuda_buffer) in self._shape_gl_buffers.items():
2087
2147
  gl.glBindVertexArray(vao)
2088
2148
 
@@ -2097,12 +2157,12 @@ Instances: {len(self._instances)}"""
2097
2157
  gl.glVertexAttribDivisor(3 + i, 1)
2098
2158
 
2099
2159
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
2100
- gl.glVertexAttribPointer(7, 3, gl.GL_FLOAT, gl.GL_FALSE, colors1[0].nbytes, ctypes.c_void_p(0))
2160
+ gl.glVertexAttribPointer(7, 3, gl.GL_FLOAT, gl.GL_FALSE, colors_size, ctypes.c_void_p(0))
2101
2161
  gl.glEnableVertexAttribArray(7)
2102
2162
  gl.glVertexAttribDivisor(7, 1)
2103
2163
 
2104
2164
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
2105
- gl.glVertexAttribPointer(8, 3, gl.GL_FLOAT, gl.GL_FALSE, colors2[0].nbytes, ctypes.c_void_p(0))
2165
+ gl.glVertexAttribPointer(8, 3, gl.GL_FLOAT, gl.GL_FALSE, colors_size, ctypes.c_void_p(0))
2106
2166
  gl.glEnableVertexAttribArray(8)
2107
2167
  gl.glVertexAttribDivisor(8, 1)
2108
2168
 
@@ -2124,7 +2184,7 @@ Instances: {len(self._instances)}"""
2124
2184
 
2125
2185
  gl.glBindVertexArray(0)
2126
2186
 
2127
- def update_shape_instance(self, name, pos, rot, color1=None, color2=None, visible=None):
2187
+ def update_shape_instance(self, name, pos=None, rot=None, color1=None, color2=None, visible=None):
2128
2188
  """Update the instance transform of the shape
2129
2189
 
2130
2190
  Args:
@@ -2135,21 +2195,33 @@ Instances: {len(self._instances)}"""
2135
2195
  color2: The second color of the checker pattern
2136
2196
  visible: Whether the shape is visible
2137
2197
  """
2198
+ from pyglet import gl
2199
+
2138
2200
  if name in self._instances:
2139
- i, body, shape, _, scale, old_color1, old_color2, v = self._instances[name]
2201
+ i, body, shape, tf, scale, old_color1, old_color2, v = self._instances[name]
2140
2202
  if visible is None:
2141
2203
  visible = v
2204
+ new_tf = np.copy(tf)
2205
+ if pos is not None:
2206
+ new_tf[:3] = pos
2207
+ if rot is not None:
2208
+ new_tf[3:] = rot
2142
2209
  self._instances[name] = (
2143
2210
  i,
2144
2211
  body,
2145
2212
  shape,
2146
- [*pos, *rot],
2213
+ new_tf,
2147
2214
  scale,
2148
2215
  color1 or old_color1,
2149
2216
  color2 or old_color2,
2150
2217
  visible,
2151
2218
  )
2152
2219
  self._update_shape_instances = True
2220
+ if color1 is not None or color2 is not None:
2221
+ vao, vbo, ebo, tri_count, vertex_cuda_buffer = self._shape_gl_buffers[shape]
2222
+ gl.glBindVertexArray(vao)
2223
+ self.update_instance_colors()
2224
+ gl.glBindVertexArray(0)
2153
2225
  return True
2154
2226
  return False
2155
2227
 
@@ -2425,7 +2497,7 @@ Instances: {len(self._instances)}"""
2425
2497
  self.add_shape_instance(name, shape, body, pos, rot)
2426
2498
  return shape
2427
2499
 
2428
- def render_ground(self, size: float = 100.0):
2500
+ def render_ground(self, size: float = 1000.0, plane=None):
2429
2501
  """Add a ground plane for visualization
2430
2502
 
2431
2503
  Args:
@@ -2440,9 +2512,22 @@ Instances: {len(self._instances)}"""
2440
2512
  q = (0.0, 0.0, 0.0, 1.0)
2441
2513
  elif self._camera_axis == 2:
2442
2514
  q = (sqh, 0.0, 0.0, sqh)
2515
+ pos = (0.0, 0.0, 0.0)
2516
+ if plane is not None:
2517
+ normal = np.array(plane[:3])
2518
+ normal /= np.linalg.norm(normal)
2519
+ pos = plane[3] * normal
2520
+ if np.allclose(normal, (0.0, 1.0, 0.0)):
2521
+ # no rotation necessary
2522
+ q = (0.0, 0.0, 0.0, 1.0)
2523
+ else:
2524
+ c = np.cross(normal, (0.0, 1.0, 0.0))
2525
+ angle = np.arcsin(np.linalg.norm(c))
2526
+ axis = np.abs(c) / np.linalg.norm(c)
2527
+ q = wp.quat_from_axis_angle(axis, angle)
2443
2528
  return self.render_plane(
2444
2529
  "ground",
2445
- (0.0, 0.0, 0.0),
2530
+ pos,
2446
2531
  q,
2447
2532
  size,
2448
2533
  size,
@@ -2453,7 +2538,14 @@ Instances: {len(self._instances)}"""
2453
2538
  )
2454
2539
 
2455
2540
  def render_sphere(
2456
- self, name: str, pos: tuple, rot: tuple, radius: float, parent_body: str = None, is_template: bool = False, color: tuple = None
2541
+ self,
2542
+ name: str,
2543
+ pos: tuple,
2544
+ rot: tuple,
2545
+ radius: float,
2546
+ parent_body: str = None,
2547
+ is_template: bool = False,
2548
+ color=None,
2457
2549
  ):
2458
2550
  """Add a sphere for visualization
2459
2551
 
@@ -2466,14 +2558,14 @@ Instances: {len(self._instances)}"""
2466
2558
  geo_hash = hash(("sphere", radius))
2467
2559
  if geo_hash in self._shape_geo_hash:
2468
2560
  shape = self._shape_geo_hash[geo_hash]
2469
- if self.update_shape_instance(name, pos, rot):
2561
+ if self.update_shape_instance(name, pos, rot, color1=color, color2=color):
2470
2562
  return shape
2471
2563
  else:
2472
2564
  vertices, indices = self._create_sphere_mesh(radius)
2473
2565
  shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2474
2566
  if not is_template:
2475
2567
  body = self._resolve_body_id(parent_body)
2476
- self.add_shape_instance(name, shape, body, pos, rot)
2568
+ self.add_shape_instance(name, shape, body, pos, rot, color1=color, color2=color)
2477
2569
  return shape
2478
2570
 
2479
2571
  def render_capsule(
@@ -2800,6 +2892,7 @@ Instances: {len(self._instances)}"""
2800
2892
  instancer = self._shape_instancers[name]
2801
2893
  if len(lines) != instancer.num_instances:
2802
2894
  instancer.allocate_instances(np.zeros((len(lines), 3)))
2895
+ instancer.update_colors(color, color)
2803
2896
 
2804
2897
  lines_wp = wp.array(lines, dtype=wp.vec3, ndim=2, device=self._device)
2805
2898
  with instancer:
warp/render/render_usd.py CHANGED
@@ -28,9 +28,12 @@ def _usd_set_xform(xform, pos: tuple, rot: tuple, scale: tuple, time):
28
28
 
29
29
  xform_ops = xform.GetOrderedXformOps()
30
30
 
31
- xform_ops[0].Set(Gf.Vec3d(float(pos[0]), float(pos[1]), float(pos[2])), time)
32
- xform_ops[1].Set(Gf.Quatf(float(rot[3]), float(rot[0]), float(rot[1]), float(rot[2])), time)
33
- xform_ops[2].Set(Gf.Vec3d(float(scale[0]), float(scale[1]), float(scale[2])), time)
31
+ if pos is not None:
32
+ xform_ops[0].Set(Gf.Vec3d(float(pos[0]), float(pos[1]), float(pos[2])), time)
33
+ if rot is not None:
34
+ xform_ops[1].Set(Gf.Quatf(float(rot[3]), float(rot[0]), float(rot[1]), float(rot[2])), time)
35
+ if scale is not None:
36
+ xform_ops[2].Set(Gf.Vec3d(float(scale[0]), float(scale[1]), float(scale[2])), time)
34
37
 
35
38
 
36
39
  # transforms a cylinder such that it connects the two points pos0, pos1
@@ -151,7 +154,11 @@ class UsdRenderer:
151
154
  rot: tuple,
152
155
  scale: tuple = (1.0, 1.0, 1.0),
153
156
  color: tuple = (1.0, 1.0, 1.0),
157
+ custom_index: int = -1,
158
+ visible: bool = True,
154
159
  ):
160
+ if not visible:
161
+ return
155
162
  sdf_path = self._resolve_path(name, body)
156
163
  instance = self._shape_constructors[shape.name].Define(self.stage, sdf_path)
157
164
  instance.GetPrim().GetReferences().AddInternalReference(shape)
@@ -224,7 +231,7 @@ class UsdRenderer:
224
231
 
225
232
  return prim_path
226
233
 
227
- def render_ground(self, size: float = 100.0):
234
+ def render_ground(self, size: float = 100.0, plane=None):
228
235
  from pxr import UsdGeom
229
236
 
230
237
  mesh = UsdGeom.Mesh.Define(self.stage, self.root.GetPath().AppendChild("ground"))
@@ -239,6 +246,23 @@ class UsdRenderer:
239
246
  elif self.up_axis == "Z":
240
247
  points = ((-size, -size, 0.0), (size, -size, 0.0), (size, size, 0.0), (-size, size, 0.0))
241
248
  normals = ((0.0, 0.0, 1.0), (0.0, 0.0, 1.0), (0.0, 0.0, 1.0), (0.0, 0.0, 1.0))
249
+ if plane is not None:
250
+ normal = np.array(plane[:3])
251
+ normal /= np.linalg.norm(normal)
252
+ pos = plane[3] * normal
253
+ axis_up = [0.0, 0.0, 0.0]
254
+ axis_up["XYZ".index(self.up_axis)] = 1.0
255
+ if np.allclose(normal, axis_up):
256
+ # no rotation necessary
257
+ q = (0.0, 0.0, 0.0, 1.0)
258
+ else:
259
+ c = np.cross(normal, axis_up)
260
+ angle = np.arcsin(np.linalg.norm(c))
261
+ axis = np.abs(c) / np.linalg.norm(c)
262
+ q = wp.quat_from_axis_angle(axis, angle)
263
+ tf = wp.transform(pos, q)
264
+ points = [wp.transform_point(tf, p) for p in points]
265
+ normals = [wp.transform_vector(tf, n) for n in normals]
242
266
  counts = (4,)
243
267
  indices = [0, 1, 2, 3]
244
268
 
@@ -339,7 +363,7 @@ class UsdRenderer:
339
363
  self._shape_constructors[name] = UsdGeom.Capsule
340
364
 
341
365
  if not is_template:
342
- _usd_set_xform(capsule, pos, rot, (1.0, 1.0, 1.0), 0.0)
366
+ _usd_set_xform(capsule, pos, rot, (1.0, 1.0, 1.0), self.time)
343
367
 
344
368
  return prim_path
345
369
 
@@ -393,7 +417,7 @@ class UsdRenderer:
393
417
  self._shape_constructors[name] = UsdGeom.Cylinder
394
418
 
395
419
  if not is_template:
396
- _usd_set_xform(cylinder, pos, rot, (1.0, 1.0, 1.0), 0.0)
420
+ _usd_set_xform(cylinder, pos, rot, (1.0, 1.0, 1.0), self.time)
397
421
 
398
422
  return prim_path
399
423
 
@@ -447,7 +471,7 @@ class UsdRenderer:
447
471
  self._shape_constructors[name] = UsdGeom.Cone
448
472
 
449
473
  if not is_template:
450
- _usd_set_xform(cone, pos, rot, (1.0, 1.0, 1.0), 0.0)
474
+ _usd_set_xform(cone, pos, rot, (1.0, 1.0, 1.0), self.time)
451
475
 
452
476
  return prim_path
453
477
 
@@ -488,7 +512,7 @@ class UsdRenderer:
488
512
  self._shape_custom_scale[name] = extents
489
513
 
490
514
  if not is_template:
491
- _usd_set_xform(cube, pos, rot, extents, 0.0)
515
+ _usd_set_xform(cube, pos, rot, extents, self.time)
492
516
 
493
517
  return prim_path
494
518
 
@@ -712,6 +736,6 @@ class UsdRenderer:
712
736
  try:
713
737
  self.stage.Save()
714
738
  return True
715
- except:
716
- print("Failed to save USD stage")
739
+ except Exception as e:
740
+ print("Failed to save USD stage:", e)
717
741
  return False
warp/sim/__init__.py CHANGED
@@ -6,7 +6,7 @@
6
6
  # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
7
 
8
8
 
9
- from .model import State, Model, ModelBuilder, Mesh, SDF
9
+ from .model import State, Control, Model, ModelBuilder, Mesh, SDF
10
10
 
11
11
  from .model import GEO_SPHERE
12
12
  from .model import GEO_BOX
@@ -17,13 +17,13 @@ from .model import GEO_MESH
17
17
  from .model import GEO_SDF
18
18
  from .model import GEO_PLANE
19
19
  from .model import GEO_NONE
20
- from .model import ModelShapeGeometry
21
20
 
22
- from .model import JOINT_MODE_LIMIT
21
+ from .model import JOINT_MODE_FORCE
23
22
  from .model import JOINT_MODE_TARGET_POSITION
24
23
  from .model import JOINT_MODE_TARGET_VELOCITY
25
24
 
26
25
  from .model import JointAxis
26
+ from .model import ModelShapeGeometry
27
27
  from .model import ModelShapeMaterials
28
28
 
29
29
  from .model import JOINT_PRISMATIC
@@ -36,8 +36,10 @@ from .model import JOINT_UNIVERSAL
36
36
  from .model import JOINT_DISTANCE
37
37
  from .model import JOINT_D6
38
38
 
39
+ from .integrator import Integrator, integrate_particles, integrate_bodies
39
40
  from .integrator_euler import SemiImplicitIntegrator
40
- from .integrator_euler import VariationalImplicitIntegrator
41
+
42
+ from .integrator_featherstone import FeatherstoneIntegrator
41
43
 
42
44
  from .integrator_xpbd import XPBDIntegrator
43
45
 
@@ -48,3 +50,10 @@ from .import_mjcf import parse_mjcf
48
50
  from .import_urdf import parse_urdf
49
51
  from .import_snu import parse_snu
50
52
  from .import_usd import parse_usd, resolve_usd_from_url
53
+
54
+ from .utils import velocity_at_point
55
+ from .utils import quat_from_euler
56
+ from .utils import quat_to_euler
57
+ from .utils import load_mesh
58
+
59
+ from .inertia import transform_inertia
warp/sim/articulation.py CHANGED
@@ -105,7 +105,7 @@ def compute_3d_rotational_dofs(
105
105
  local_1 = wp.quat_rotate(q_off, wp.vec3(0.0, 1.0, 0.0))
106
106
  local_2 = wp.quat_rotate(q_off, wp.vec3(0.0, 0.0, 1.0))
107
107
 
108
- # reconstruct rotation axes, todo: can probably use fact that rz'*ry'*rx' == rx*ry*rz to avoid some work here
108
+ # reconstruct rotation axes
109
109
  axis_0 = local_0
110
110
  q_0 = wp.quat_from_axis_angle(axis_0, q0)
111
111
 
@@ -331,10 +331,9 @@ def eval_articulation_fk(
331
331
  iq = q_start + lin_axis_count
332
332
  iqd = qd_start + lin_axis_count
333
333
  if ang_axis_count == 1:
334
- axis = joint_axis[axis_start + lin_axis_count + 0]
335
- qi = wp.quat_from_axis_angle(axis, joint_q[q_start + lin_axis_count + 0])
336
- rot = qi * rot
337
- vel_w = joint_qd[qd_start + lin_axis_count + 0] * axis
334
+ axis = joint_axis[ia]
335
+ rot = wp.quat_from_axis_angle(axis, joint_q[iq])
336
+ vel_w = joint_qd[iqd] * axis
338
337
  if ang_axis_count == 2:
339
338
  rot, vel_w = compute_2d_rotational_dofs(
340
339
  joint_axis[ia + 0],