warp-lang 0.11.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 (170) hide show
  1. warp/__init__.py +8 -0
  2. warp/bin/warp-clang.so +0 -0
  3. warp/bin/warp.so +0 -0
  4. warp/build.py +7 -6
  5. warp/build_dll.py +70 -79
  6. warp/builtins.py +10 -6
  7. warp/codegen.py +51 -19
  8. warp/config.py +7 -8
  9. warp/constants.py +3 -0
  10. warp/context.py +948 -245
  11. warp/dlpack.py +198 -113
  12. warp/examples/assets/bunny.usd +0 -0
  13. warp/examples/assets/cartpole.urdf +110 -0
  14. warp/examples/assets/crazyflie.usd +0 -0
  15. warp/examples/assets/cube.usda +42 -0
  16. warp/examples/assets/nv_ant.xml +92 -0
  17. warp/examples/assets/nv_humanoid.xml +183 -0
  18. warp/examples/assets/quadruped.urdf +268 -0
  19. warp/examples/assets/rocks.nvdb +0 -0
  20. warp/examples/assets/rocks.usd +0 -0
  21. warp/examples/assets/sphere.usda +56 -0
  22. warp/examples/assets/torus.usda +105 -0
  23. warp/examples/benchmarks/benchmark_api.py +383 -0
  24. warp/examples/benchmarks/benchmark_cloth.py +279 -0
  25. warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -0
  26. warp/examples/benchmarks/benchmark_cloth_jax.py +100 -0
  27. warp/examples/benchmarks/benchmark_cloth_numba.py +142 -0
  28. warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -0
  29. warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -0
  30. warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -0
  31. warp/examples/benchmarks/benchmark_cloth_warp.py +146 -0
  32. warp/examples/benchmarks/benchmark_launches.py +295 -0
  33. warp/examples/core/example_dem.py +221 -0
  34. warp/examples/core/example_fluid.py +267 -0
  35. warp/examples/core/example_graph_capture.py +129 -0
  36. warp/examples/core/example_marching_cubes.py +177 -0
  37. warp/examples/core/example_mesh.py +154 -0
  38. warp/examples/core/example_mesh_intersect.py +193 -0
  39. warp/examples/core/example_nvdb.py +169 -0
  40. warp/examples/core/example_raycast.py +89 -0
  41. warp/examples/core/example_raymarch.py +178 -0
  42. warp/examples/core/example_render_opengl.py +141 -0
  43. warp/examples/core/example_sph.py +389 -0
  44. warp/examples/core/example_torch.py +181 -0
  45. warp/examples/core/example_wave.py +249 -0
  46. warp/examples/fem/bsr_utils.py +380 -0
  47. warp/examples/fem/example_apic_fluid.py +391 -0
  48. warp/examples/fem/example_convection_diffusion.py +168 -0
  49. warp/examples/fem/example_convection_diffusion_dg.py +209 -0
  50. warp/examples/fem/example_convection_diffusion_dg0.py +194 -0
  51. warp/examples/fem/example_deformed_geometry.py +159 -0
  52. warp/examples/fem/example_diffusion.py +173 -0
  53. warp/examples/fem/example_diffusion_3d.py +152 -0
  54. warp/examples/fem/example_diffusion_mgpu.py +214 -0
  55. warp/examples/fem/example_mixed_elasticity.py +222 -0
  56. warp/examples/fem/example_navier_stokes.py +243 -0
  57. warp/examples/fem/example_stokes.py +192 -0
  58. warp/examples/fem/example_stokes_transfer.py +249 -0
  59. warp/examples/fem/mesh_utils.py +109 -0
  60. warp/examples/fem/plot_utils.py +287 -0
  61. warp/examples/optim/example_bounce.py +248 -0
  62. warp/examples/optim/example_cloth_throw.py +210 -0
  63. warp/examples/optim/example_diffray.py +535 -0
  64. warp/examples/optim/example_drone.py +850 -0
  65. warp/examples/optim/example_inverse_kinematics.py +169 -0
  66. warp/examples/optim/example_inverse_kinematics_torch.py +170 -0
  67. warp/examples/optim/example_spring_cage.py +234 -0
  68. warp/examples/optim/example_trajectory.py +201 -0
  69. warp/examples/sim/example_cartpole.py +128 -0
  70. warp/examples/sim/example_cloth.py +184 -0
  71. warp/examples/sim/example_granular.py +113 -0
  72. warp/examples/sim/example_granular_collision_sdf.py +185 -0
  73. warp/examples/sim/example_jacobian_ik.py +213 -0
  74. warp/examples/sim/example_particle_chain.py +106 -0
  75. warp/examples/sim/example_quadruped.py +179 -0
  76. warp/examples/sim/example_rigid_chain.py +191 -0
  77. warp/examples/sim/example_rigid_contact.py +176 -0
  78. warp/examples/sim/example_rigid_force.py +126 -0
  79. warp/examples/sim/example_rigid_gyroscopic.py +97 -0
  80. warp/examples/sim/example_rigid_soft_contact.py +124 -0
  81. warp/examples/sim/example_soft_body.py +178 -0
  82. warp/fabric.py +29 -20
  83. warp/fem/cache.py +0 -1
  84. warp/fem/dirichlet.py +0 -2
  85. warp/fem/integrate.py +0 -1
  86. warp/jax.py +45 -0
  87. warp/jax_experimental.py +339 -0
  88. warp/native/builtin.h +12 -0
  89. warp/native/bvh.cu +18 -18
  90. warp/native/clang/clang.cpp +8 -3
  91. warp/native/cuda_util.cpp +94 -5
  92. warp/native/cuda_util.h +35 -6
  93. warp/native/cutlass_gemm.cpp +1 -1
  94. warp/native/cutlass_gemm.cu +4 -1
  95. warp/native/error.cpp +66 -0
  96. warp/native/error.h +27 -0
  97. warp/native/mesh.cu +2 -2
  98. warp/native/reduce.cu +4 -4
  99. warp/native/runlength_encode.cu +2 -2
  100. warp/native/scan.cu +2 -2
  101. warp/native/sparse.cu +0 -1
  102. warp/native/temp_buffer.h +2 -2
  103. warp/native/warp.cpp +95 -60
  104. warp/native/warp.cu +1053 -218
  105. warp/native/warp.h +49 -32
  106. warp/optim/linear.py +33 -16
  107. warp/render/render_opengl.py +202 -101
  108. warp/render/render_usd.py +82 -40
  109. warp/sim/__init__.py +13 -4
  110. warp/sim/articulation.py +4 -5
  111. warp/sim/collide.py +320 -175
  112. warp/sim/import_mjcf.py +25 -30
  113. warp/sim/import_urdf.py +94 -63
  114. warp/sim/import_usd.py +51 -36
  115. warp/sim/inertia.py +3 -2
  116. warp/sim/integrator.py +233 -0
  117. warp/sim/integrator_euler.py +447 -469
  118. warp/sim/integrator_featherstone.py +1991 -0
  119. warp/sim/integrator_xpbd.py +1420 -640
  120. warp/sim/model.py +765 -487
  121. warp/sim/particles.py +2 -1
  122. warp/sim/render.py +35 -13
  123. warp/sim/utils.py +222 -11
  124. warp/stubs.py +8 -0
  125. warp/tape.py +16 -1
  126. warp/tests/aux_test_grad_customs.py +23 -0
  127. warp/tests/test_array.py +190 -1
  128. warp/tests/test_async.py +656 -0
  129. warp/tests/test_bool.py +50 -0
  130. warp/tests/test_dlpack.py +164 -11
  131. warp/tests/test_examples.py +166 -74
  132. warp/tests/test_fem.py +8 -1
  133. warp/tests/test_generics.py +15 -5
  134. warp/tests/test_grad.py +1 -1
  135. warp/tests/test_grad_customs.py +172 -12
  136. warp/tests/test_jax.py +254 -0
  137. warp/tests/test_large.py +29 -6
  138. warp/tests/test_launch.py +25 -0
  139. warp/tests/test_linear_solvers.py +20 -3
  140. warp/tests/test_matmul.py +61 -16
  141. warp/tests/test_matmul_lite.py +13 -13
  142. warp/tests/test_mempool.py +186 -0
  143. warp/tests/test_multigpu.py +3 -0
  144. warp/tests/test_options.py +16 -2
  145. warp/tests/test_peer.py +137 -0
  146. warp/tests/test_print.py +3 -1
  147. warp/tests/test_quat.py +23 -0
  148. warp/tests/test_sim_kinematics.py +97 -0
  149. warp/tests/test_snippet.py +126 -3
  150. warp/tests/test_streams.py +108 -79
  151. warp/tests/test_torch.py +16 -8
  152. warp/tests/test_utils.py +32 -27
  153. warp/tests/test_verify_fp.py +65 -0
  154. warp/tests/test_volume.py +1 -1
  155. warp/tests/unittest_serial.py +2 -0
  156. warp/tests/unittest_suites.py +12 -0
  157. warp/tests/unittest_utils.py +14 -7
  158. warp/thirdparty/unittest_parallel.py +15 -3
  159. warp/torch.py +10 -8
  160. warp/types.py +363 -246
  161. warp/utils.py +143 -19
  162. warp_lang-1.0.0.dist-info/LICENSE.md +126 -0
  163. warp_lang-1.0.0.dist-info/METADATA +394 -0
  164. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +167 -86
  165. warp/sim/optimizer.py +0 -138
  166. warp_lang-0.11.0.dist-info/LICENSE.md +0 -36
  167. warp_lang-0.11.0.dist-info/METADATA +0 -238
  168. /warp/tests/{walkthough_debug.py → walkthrough_debug.py} +0 -0
  169. {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
  170. {warp_lang-0.11.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
1554
1571
 
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))
1572
+ @camera_pos.setter
1573
+ def camera_pos(self, value):
1574
+ self.update_view_matrix(cam_pos=value)
1557
1575
 
1558
- def update_model_matrix(self):
1576
+ @property
1577
+ def camera_front(self):
1578
+ return self._camera_front
1579
+
1580
+ @camera_front.setter
1581
+ def camera_front(self, value):
1582
+ self.update_view_matrix(cam_front=value)
1583
+
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
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
 
@@ -2461,18 +2553,19 @@ Instances: {len(self._instances)}"""
2461
2553
  pos: The position of the sphere
2462
2554
  radius: The radius of the sphere
2463
2555
  name: A name for the USD prim on the stage
2556
+ color: The color of the sphere
2464
2557
  """
2465
2558
  geo_hash = hash(("sphere", radius))
2466
2559
  if geo_hash in self._shape_geo_hash:
2467
2560
  shape = self._shape_geo_hash[geo_hash]
2468
- if self.update_shape_instance(name, pos, rot):
2561
+ if self.update_shape_instance(name, pos, rot, color1=color, color2=color):
2469
2562
  return shape
2470
2563
  else:
2471
2564
  vertices, indices = self._create_sphere_mesh(radius)
2472
- shape = self.register_shape(geo_hash, vertices, indices)
2565
+ shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2473
2566
  if not is_template:
2474
2567
  body = self._resolve_body_id(parent_body)
2475
- self.add_shape_instance(name, shape, body, pos, rot)
2568
+ self.add_shape_instance(name, shape, body, pos, rot, color1=color, color2=color)
2476
2569
  return shape
2477
2570
 
2478
2571
  def render_capsule(
@@ -2485,6 +2578,7 @@ Instances: {len(self._instances)}"""
2485
2578
  parent_body: str = None,
2486
2579
  is_template: bool = False,
2487
2580
  up_axis: int = 1,
2581
+ color: tuple = None,
2488
2582
  ):
2489
2583
  """Add a capsule for visualization
2490
2584
 
@@ -2494,6 +2588,7 @@ Instances: {len(self._instances)}"""
2494
2588
  half_height: The half height of the capsule
2495
2589
  name: A name for the USD prim on the stage
2496
2590
  up_axis: The axis of the capsule that points up (0: x, 1: y, 2: z)
2591
+ color: The color of the capsule
2497
2592
  """
2498
2593
  geo_hash = hash(("capsule", radius, half_height))
2499
2594
  if geo_hash in self._shape_geo_hash:
@@ -2502,7 +2597,7 @@ Instances: {len(self._instances)}"""
2502
2597
  return shape
2503
2598
  else:
2504
2599
  vertices, indices = self._create_capsule_mesh(radius, half_height, up_axis=up_axis)
2505
- shape = self.register_shape(geo_hash, vertices, indices)
2600
+ shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2506
2601
  if not is_template:
2507
2602
  body = self._resolve_body_id(parent_body)
2508
2603
  self.add_shape_instance(name, shape, body, pos, rot)
@@ -2518,6 +2613,7 @@ Instances: {len(self._instances)}"""
2518
2613
  parent_body: str = None,
2519
2614
  is_template: bool = False,
2520
2615
  up_axis: int = 1,
2616
+ color: tuple = None,
2521
2617
  ):
2522
2618
  """Add a cylinder for visualization
2523
2619
 
@@ -2527,6 +2623,7 @@ Instances: {len(self._instances)}"""
2527
2623
  half_height: The half height of the cylinder
2528
2624
  name: A name for the USD prim on the stage
2529
2625
  up_axis: The axis of the cylinder that points up (0: x, 1: y, 2: z)
2626
+ color: The color of the capsule
2530
2627
  """
2531
2628
  geo_hash = hash(("cylinder", radius, half_height))
2532
2629
  if geo_hash in self._shape_geo_hash:
@@ -2535,7 +2632,7 @@ Instances: {len(self._instances)}"""
2535
2632
  return shape
2536
2633
  else:
2537
2634
  vertices, indices = self._create_cylinder_mesh(radius, half_height, up_axis=up_axis)
2538
- shape = self.register_shape(geo_hash, vertices, indices)
2635
+ shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2539
2636
  if not is_template:
2540
2637
  body = self._resolve_body_id(parent_body)
2541
2638
  self.add_shape_instance(name, shape, body, pos, rot)
@@ -2551,6 +2648,7 @@ Instances: {len(self._instances)}"""
2551
2648
  parent_body: str = None,
2552
2649
  is_template: bool = False,
2553
2650
  up_axis: int = 1,
2651
+ color: tuple = None,
2554
2652
  ):
2555
2653
  """Add a cone for visualization
2556
2654
 
@@ -2560,6 +2658,7 @@ Instances: {len(self._instances)}"""
2560
2658
  half_height: The half height of the cone
2561
2659
  name: A name for the USD prim on the stage
2562
2660
  up_axis: The axis of the cone that points up (0: x, 1: y, 2: z)
2661
+ color: The color of the cone
2563
2662
  """
2564
2663
  geo_hash = hash(("cone", radius, half_height))
2565
2664
  if geo_hash in self._shape_geo_hash:
@@ -2568,14 +2667,14 @@ Instances: {len(self._instances)}"""
2568
2667
  return shape
2569
2668
  else:
2570
2669
  vertices, indices = self._create_cone_mesh(radius, half_height, up_axis=up_axis)
2571
- shape = self.register_shape(geo_hash, vertices, indices)
2670
+ shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2572
2671
  if not is_template:
2573
2672
  body = self._resolve_body_id(parent_body)
2574
2673
  self.add_shape_instance(name, shape, body, pos, rot)
2575
2674
  return shape
2576
2675
 
2577
2676
  def render_box(
2578
- self, name: str, pos: tuple, rot: tuple, extents: tuple, parent_body: str = None, is_template: bool = False
2677
+ self, name: str, pos: tuple, rot: tuple, extents: tuple, parent_body: str = None, is_template: bool = False, color: tuple = None
2579
2678
  ):
2580
2679
  """Add a box for visualization
2581
2680
 
@@ -2583,6 +2682,7 @@ Instances: {len(self._instances)}"""
2583
2682
  pos: The position of the box
2584
2683
  extents: The extents of the box
2585
2684
  name: A name for the USD prim on the stage
2685
+ color: The color of the box
2586
2686
  """
2587
2687
  geo_hash = hash(("box", tuple(extents)))
2588
2688
  if geo_hash in self._shape_geo_hash:
@@ -2591,7 +2691,7 @@ Instances: {len(self._instances)}"""
2591
2691
  return shape
2592
2692
  else:
2593
2693
  vertices, indices = self._create_box_mesh(extents)
2594
- shape = self.register_shape(geo_hash, vertices, indices)
2694
+ shape = self.register_shape(geo_hash, vertices, indices, color1=color, color2=color)
2595
2695
  if not is_template:
2596
2696
  body = self._resolve_body_id(parent_body)
2597
2697
  self.add_shape_instance(name, shape, body, pos, rot)
@@ -2792,6 +2892,7 @@ Instances: {len(self._instances)}"""
2792
2892
  instancer = self._shape_instancers[name]
2793
2893
  if len(lines) != instancer.num_instances:
2794
2894
  instancer.allocate_instances(np.zeros((len(lines), 3)))
2895
+ instancer.update_colors(color, color)
2795
2896
 
2796
2897
  lines_wp = wp.array(lines, dtype=wp.vec3, ndim=2, device=self._device)
2797
2898
  with instancer: