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
@@ -0,0 +1,154 @@
1
+ # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ ###########################################################################
9
+ # Example Mesh
10
+ #
11
+ # Shows how to implement a PBD particle simulation with collision against
12
+ # a deforming triangle mesh. The mesh collision uses wp.mesh_query_point_sign_normal()
13
+ # to compute the closest point, and wp.Mesh.refit() to update the mesh
14
+ # object after deformation.
15
+ #
16
+ ###########################################################################
17
+
18
+ import os
19
+
20
+ import numpy as np
21
+ from pxr import Usd, UsdGeom
22
+
23
+ import warp as wp
24
+ import warp.render
25
+
26
+ wp.init()
27
+
28
+
29
+ @wp.kernel
30
+ def deform(positions: wp.array(dtype=wp.vec3), t: float):
31
+ tid = wp.tid()
32
+
33
+ x = positions[tid]
34
+
35
+ offset = -wp.sin(x[0]) * 0.02
36
+ scale = wp.sin(t)
37
+
38
+ x = x + wp.vec3(0.0, offset * scale, 0.0)
39
+
40
+ positions[tid] = x
41
+
42
+
43
+ @wp.kernel
44
+ def simulate(
45
+ positions: wp.array(dtype=wp.vec3),
46
+ velocities: wp.array(dtype=wp.vec3),
47
+ mesh: wp.uint64,
48
+ margin: float,
49
+ dt: float,
50
+ ):
51
+ tid = wp.tid()
52
+
53
+ x = positions[tid]
54
+ v = velocities[tid]
55
+
56
+ v = v + wp.vec3(0.0, 0.0 - 9.8, 0.0) * dt - v * 0.1 * dt
57
+ xpred = x + v * dt
58
+
59
+ max_dist = 1.5
60
+
61
+ query = wp.mesh_query_point_sign_normal(mesh, xpred, max_dist)
62
+ if query.result:
63
+ p = wp.mesh_eval_position(mesh, query.face, query.u, query.v)
64
+
65
+ delta = xpred - p
66
+
67
+ dist = wp.length(delta) * query.sign
68
+ err = dist - margin
69
+
70
+ # mesh collision
71
+ if err < 0.0:
72
+ n = wp.normalize(delta) * query.sign
73
+ xpred = xpred - n * err
74
+
75
+ # pbd update
76
+ v = (xpred - x) * (1.0 / dt)
77
+ x = xpred
78
+
79
+ positions[tid] = x
80
+ velocities[tid] = v
81
+
82
+
83
+ class Example:
84
+ def __init__(self, stage):
85
+ rng = np.random.default_rng(42)
86
+ self.num_particles = 1000
87
+
88
+ self.sim_steps = 500
89
+ self.sim_dt = 1.0 / 60.0
90
+
91
+ self.sim_time = 0.0
92
+ self.sim_timers = {}
93
+
94
+ self.sim_margin = 0.1
95
+
96
+ usd_stage = Usd.Stage.Open(os.path.join(os.path.dirname(__file__), "../assets/bunny.usd"))
97
+ usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath("/bunny/bunny"))
98
+ usd_scale = 10.0
99
+
100
+ # create collision mesh
101
+ self.mesh = wp.Mesh(
102
+ points=wp.array(usd_geom.GetPointsAttr().Get() * usd_scale, dtype=wp.vec3),
103
+ indices=wp.array(usd_geom.GetFaceVertexIndicesAttr().Get(), dtype=int),
104
+ )
105
+
106
+ # random particles
107
+ init_pos = (rng.random((self.num_particles, 3)) - np.array([0.5, -1.5, 0.5])) * 10.0
108
+ init_vel = rng.random((self.num_particles, 3)) * 0.0
109
+
110
+ self.positions = wp.from_numpy(init_pos, dtype=wp.vec3)
111
+ self.velocities = wp.from_numpy(init_vel, dtype=wp.vec3)
112
+
113
+ # renderer
114
+ self.renderer = None
115
+ if stage:
116
+ self.renderer = wp.render.UsdRenderer(stage)
117
+
118
+ def step(self):
119
+ with wp.ScopedTimer("step", detailed=False, dict=self.sim_timers):
120
+ wp.launch(kernel=deform, dim=len(self.mesh.points), inputs=[self.mesh.points, self.sim_time])
121
+
122
+ # refit the mesh BVH to account for the deformation
123
+ self.mesh.refit()
124
+
125
+ wp.launch(
126
+ kernel=simulate,
127
+ dim=self.num_particles,
128
+ inputs=[self.positions, self.velocities, self.mesh.id, self.sim_margin, self.sim_dt],
129
+ )
130
+
131
+ self.sim_time += self.sim_dt
132
+
133
+ def render(self):
134
+ if self.renderer is None:
135
+ return
136
+
137
+ with wp.ScopedTimer("render", detailed=False):
138
+ self.renderer.begin_frame(self.sim_time)
139
+ self.renderer.render_mesh(name="mesh", points=self.mesh.points.numpy(), indices=self.mesh.indices.numpy(), colors=((0.35, 0.55, 0.9),) * len(self.mesh.points))
140
+ self.renderer.render_points(name="points", points=self.positions.numpy(), radius=self.sim_margin, colors=((0.8, 0.3, 0.2),) * len(self.mesh.points))
141
+ self.renderer.end_frame()
142
+
143
+
144
+ if __name__ == "__main__":
145
+ stage_path = os.path.join(os.path.dirname(__file__), "example_mesh.usd")
146
+
147
+ example = Example(stage_path)
148
+
149
+ for i in range(example.sim_steps):
150
+ example.step()
151
+ example.render()
152
+
153
+ if example.renderer:
154
+ example.renderer.save()
@@ -0,0 +1,193 @@
1
+ # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ #############################################################################
9
+ # Example Mesh Intersection
10
+ #
11
+ # Show how to use built-in BVH query to test if two triangle meshes intersect.
12
+ #
13
+ ##############################################################################
14
+
15
+ import os
16
+
17
+ import numpy as np
18
+ from pxr import Usd, UsdGeom
19
+
20
+ import warp as wp
21
+ import warp.render
22
+
23
+
24
+ wp.init()
25
+
26
+
27
+ @wp.func
28
+ def cw_min(a: wp.vec3, b: wp.vec3):
29
+ return wp.vec3(wp.min(a[0], b[0]), wp.min(a[1], b[1]), wp.min(a[2], b[2]))
30
+
31
+
32
+ @wp.func
33
+ def cw_max(a: wp.vec3, b: wp.vec3):
34
+ return wp.vec3(wp.max(a[0], b[0]), wp.max(a[1], b[1]), wp.max(a[2], b[2]))
35
+
36
+
37
+ @wp.kernel
38
+ def intersect(
39
+ mesh_0: wp.uint64,
40
+ mesh_1: wp.uint64,
41
+ num_faces: int,
42
+ xforms: wp.array(dtype=wp.transform),
43
+ result: wp.array(dtype=int),
44
+ ):
45
+ tid = wp.tid()
46
+
47
+ # mesh_0 is assumed to be the query mesh, we launch one thread
48
+ # for each face in mesh_0 and test it against the opposing mesh's BVH
49
+ face = tid % num_faces
50
+ batch = tid // num_faces
51
+
52
+ # transforms from mesh_0 -> mesh_1 space
53
+ xform = xforms[batch]
54
+
55
+ # load query triangles points and transform to mesh_1's space
56
+ v0 = wp.transform_point(xform, wp.mesh_eval_position(mesh_0, face, 1.0, 0.0))
57
+ v1 = wp.transform_point(xform, wp.mesh_eval_position(mesh_0, face, 0.0, 1.0))
58
+ v2 = wp.transform_point(xform, wp.mesh_eval_position(mesh_0, face, 0.0, 0.0))
59
+
60
+ # compute bounds of the query triangle
61
+ lower = cw_min(cw_min(v0, v1), v2)
62
+ upper = cw_max(cw_max(v0, v1), v2)
63
+
64
+ query = wp.mesh_query_aabb(mesh_1, lower, upper)
65
+
66
+ for f in query:
67
+ u0 = wp.mesh_eval_position(mesh_1, f, 1.0, 0.0)
68
+ u1 = wp.mesh_eval_position(mesh_1, f, 0.0, 1.0)
69
+ u2 = wp.mesh_eval_position(mesh_1, f, 0.0, 0.0)
70
+
71
+ # test for triangle intersection
72
+ i = wp.intersect_tri_tri(v0, v1, v2, u0, u1, u2)
73
+
74
+ if i > 0:
75
+ result[batch] = 1
76
+ return
77
+
78
+ # use if you want to count all intersections
79
+ # wp.atomic_add(result, batch, i)
80
+
81
+
82
+ class Example:
83
+ def __init__(self, stage):
84
+ rng = np.random.default_rng(42)
85
+
86
+ self.query_count = 1024
87
+ self.has_queried = False
88
+
89
+ self.path_0 = "../assets/cube.usda"
90
+ self.path_1 = "../assets/sphere.usda"
91
+
92
+ self.mesh_0 = self.load_mesh(self.path_0, "/Cube/Cube_001")
93
+ self.mesh_1 = self.load_mesh(self.path_1, "/Sphere/Sphere")
94
+
95
+ self.query_num_faces = int(len(self.mesh_0.indices) / 3)
96
+ self.query_num_points = len(self.mesh_0.points)
97
+
98
+ # generate random relative transforms
99
+ self.xforms = []
100
+
101
+ for i in range(self.query_count):
102
+ # random offset
103
+ p = wp.vec3(rng.random(3) * 0.5 - 0.5) * 5.0
104
+
105
+ # random orientation
106
+ axis = wp.normalize(wp.vec3(rng.random(3) * 0.5 - 0.5))
107
+ angle = float(np.random.rand(1)[0])
108
+
109
+ q = wp.quat_from_axis_angle(wp.normalize(axis), angle)
110
+
111
+ self.xforms.append(wp.transform(p, q))
112
+
113
+ self.array_result = wp.zeros(self.query_count, dtype=int)
114
+ self.array_xforms = wp.array(self.xforms, dtype=wp.transform)
115
+
116
+ # renderer
117
+ self.renderer = None
118
+ if stage is not None:
119
+ self.renderer = wp.render.UsdRenderer(stage)
120
+
121
+ def step(self):
122
+ with wp.ScopedTimer("intersect", active=True):
123
+ wp.launch(
124
+ kernel=intersect,
125
+ dim=self.query_num_faces * self.query_count,
126
+ inputs=[self.mesh_0.id, self.mesh_1.id, self.query_num_faces, self.array_xforms, self.array_result],
127
+ )
128
+
129
+ def render(self):
130
+ if self.renderer is None:
131
+ return
132
+
133
+ # bring results back to host
134
+ result = self.array_result.numpy()
135
+
136
+ with wp.ScopedTimer("render", active=True):
137
+ self.renderer.begin_frame(0.0)
138
+
139
+ for i in range(self.query_count):
140
+ spacing = 8.0
141
+ offset = i * spacing
142
+
143
+ xform = self.xforms[i]
144
+ self.renderer.render_ref(
145
+ f"mesh_{i}_0",
146
+ os.path.join(os.path.dirname(__file__), self.path_0),
147
+ pos=wp.vec3(xform.p[0] + offset, xform.p[1], xform.p[2]),
148
+ rot=xform.q,
149
+ scale=wp.vec3(1.0, 1.0, 1.0),
150
+ )
151
+ self.renderer.render_ref(
152
+ f"mesh_{i}_1",
153
+ os.path.join(os.path.dirname(__file__), self.path_1),
154
+ pos=wp.vec3(offset, 0.0, 0.0),
155
+ rot=wp.quat_identity(),
156
+ scale=wp.vec3(1.0, 1.0, 1.0),
157
+ )
158
+
159
+ # if pair intersects then draw a small box above the pair
160
+ if result[i] > 0:
161
+ self.renderer.render_box(
162
+ f"result_{i}",
163
+ pos=wp.vec3(xform.p[0] + offset, xform.p[1] + 5.0, xform.p[2]),
164
+ rot=wp.quat_identity(),
165
+ extents=(0.1, 0.1, 0.1),
166
+ )
167
+
168
+ self.renderer.end_frame()
169
+
170
+ # create collision meshes
171
+ def load_mesh(self, path, prim):
172
+ usd_path = os.path.join(os.path.dirname(__file__), path)
173
+ usd_stage = Usd.Stage.Open(usd_path)
174
+ usd_geom = UsdGeom.Mesh(usd_stage.GetPrimAtPath(prim))
175
+
176
+ mesh = wp.Mesh(
177
+ points=wp.array(usd_geom.GetPointsAttr().Get(), dtype=wp.vec3),
178
+ indices=wp.array(usd_geom.GetFaceVertexIndicesAttr().Get(), dtype=int),
179
+ )
180
+
181
+ return mesh
182
+
183
+
184
+ if __name__ == "__main__":
185
+ stage_path = os.path.join(os.path.dirname(__file__), "example_mesh_intersect.usd")
186
+
187
+ example = Example(stage_path)
188
+
189
+ example.step()
190
+ example.render()
191
+
192
+ if example.renderer:
193
+ example.renderer.save()
@@ -0,0 +1,169 @@
1
+ # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ ###########################################################################
9
+ # Example NanoVDB
10
+ #
11
+ # Shows how to implement a particle simulation with collision against
12
+ # a NanoVDB signed-distance field. In this example the NanoVDB field
13
+ # is created offline in Houdini. The particle kernel uses the Warp
14
+ # wp.volume_sample_f() method to compute the SDF and normal at a point.
15
+ #
16
+ ###########################################################################
17
+
18
+ import math
19
+ import os
20
+
21
+ import numpy as np
22
+
23
+ import warp as wp
24
+ import warp.render
25
+
26
+ wp.init()
27
+
28
+
29
+ @wp.func
30
+ def volume_grad(volume: wp.uint64, p: wp.vec3):
31
+ eps = 1.0
32
+ q = wp.volume_world_to_index(volume, p)
33
+
34
+ # compute gradient of the SDF using finite differences
35
+ dx = wp.volume_sample_f(volume, q + wp.vec3(eps, 0.0, 0.0), wp.Volume.LINEAR) - wp.volume_sample_f(
36
+ volume, q - wp.vec3(eps, 0.0, 0.0), wp.Volume.LINEAR
37
+ )
38
+ dy = wp.volume_sample_f(volume, q + wp.vec3(0.0, eps, 0.0), wp.Volume.LINEAR) - wp.volume_sample_f(
39
+ volume, q - wp.vec3(0.0, eps, 0.0), wp.Volume.LINEAR
40
+ )
41
+ dz = wp.volume_sample_f(volume, q + wp.vec3(0.0, 0.0, eps), wp.Volume.LINEAR) - wp.volume_sample_f(
42
+ volume, q - wp.vec3(0.0, 0.0, eps), wp.Volume.LINEAR
43
+ )
44
+
45
+ return wp.normalize(wp.vec3(dx, dy, dz))
46
+
47
+
48
+ @wp.kernel
49
+ def simulate(
50
+ positions: wp.array(dtype=wp.vec3),
51
+ velocities: wp.array(dtype=wp.vec3),
52
+ volume: wp.uint64,
53
+ margin: float,
54
+ dt: float,
55
+ ):
56
+ tid = wp.tid()
57
+
58
+ x = positions[tid]
59
+ v = velocities[tid]
60
+
61
+ v = v + wp.vec3(0.0, 0.0, -980.0) * dt - v * 0.1 * dt
62
+ xpred = x + v * dt
63
+ xpred_local = wp.volume_world_to_index(volume, xpred)
64
+
65
+ # d = wp.volume_sample_f(volume, xpred_local, wp.Volume.LINEAR)
66
+ n = wp.vec3()
67
+ d = wp.volume_sample_grad_f(volume, xpred_local, wp.Volume.LINEAR, n)
68
+
69
+ if d < margin:
70
+ # n = volume_grad(volume, xpred)
71
+ n = wp.normalize(n)
72
+ err = d - margin
73
+
74
+ # mesh collision
75
+ xpred = xpred - n * err
76
+
77
+ # ground collision
78
+ if xpred[2] < 0.0:
79
+ xpred = wp.vec3(xpred[0], xpred[1], 0.0)
80
+
81
+ # pbd update
82
+ v = (xpred - x) * (1.0 / dt)
83
+ x = xpred
84
+
85
+ positions[tid] = x
86
+ velocities[tid] = v
87
+
88
+
89
+ class Example:
90
+ def __init__(self, stage):
91
+ rng = np.random.default_rng(42)
92
+ self.num_particles = 10000
93
+
94
+ self.sim_steps = 1000
95
+ frame_dt = 1.0 / 60.0
96
+ self.sim_substeps = 3
97
+ self.sim_dt = frame_dt / self.sim_substeps
98
+
99
+ self.sim_time = 0.0
100
+ self.sim_timers = {}
101
+
102
+ self.sim_margin = 15.0
103
+
104
+ init_pos = 1000.0 * (rng.random((self.num_particles, 3)) * 2.0 - 1.0) + np.array((0.0, 0.0, 3000.0))
105
+ init_vel = rng.random((self.num_particles, 3))
106
+
107
+ self.positions = wp.from_numpy(init_pos.astype(np.float32), dtype=wp.vec3)
108
+ self.velocities = wp.from_numpy(init_vel.astype(np.float32), dtype=wp.vec3)
109
+
110
+ # load collision volume
111
+ file = open(os.path.join(os.path.dirname(__file__), "../assets/rocks.nvdb"), "rb")
112
+
113
+ # create Volume object
114
+ self.volume = wp.Volume.load_from_nvdb(file)
115
+
116
+ file.close()
117
+
118
+ # renderer
119
+ self.renderer = None
120
+ if stage:
121
+ self.renderer = wp.render.UsdRenderer(stage, up_axis="z")
122
+ self.renderer.render_ground(size=10000.0)
123
+
124
+ def step(self):
125
+ with wp.ScopedTimer("step", detailed=False, dict=self.sim_timers):
126
+ for _ in range(self.sim_substeps):
127
+ wp.launch(
128
+ kernel=simulate,
129
+ dim=self.num_particles,
130
+ inputs=[
131
+ self.positions,
132
+ self.velocities,
133
+ self.volume.id,
134
+ self.sim_margin,
135
+ self.sim_dt,
136
+ ],
137
+ )
138
+ self.sim_time += self.sim_dt
139
+
140
+ def render(self):
141
+ if self.renderer is None:
142
+ return
143
+
144
+ with wp.ScopedTimer("render", detailed=False):
145
+ self.renderer.begin_frame(self.sim_time)
146
+
147
+ self.renderer.render_ref(
148
+ name="collision",
149
+ path=os.path.join(os.path.dirname(__file__), "../assets/rocks.usd"),
150
+ pos=wp.vec3(0.0, 0.0, 0.0),
151
+ rot=wp.quat_from_axis_angle(wp.vec3(1.0, 0.0, 0.0), math.pi),
152
+ scale=wp.vec3(1.0, 1.0, 1.0),
153
+ )
154
+ self.renderer.render_points(name="points", points=self.positions.numpy(), radius=self.sim_margin, colors=((0.8, 0.3, 0.2),) * len(self.positions))
155
+
156
+ self.renderer.end_frame()
157
+
158
+
159
+ if __name__ == "__main__":
160
+ stage_path = os.path.join(os.path.dirname(__file__), "example_nvdb.usd")
161
+
162
+ example = Example(stage_path)
163
+
164
+ for i in range(example.sim_steps):
165
+ example.step()
166
+ example.render()
167
+
168
+ if example.renderer:
169
+ example.renderer.save()
@@ -0,0 +1,89 @@
1
+ # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ #############################################################################
9
+ # Example Ray Cast
10
+ #
11
+ # Shows how to use the built-in wp.Mesh data structure and wp.mesh_query_ray()
12
+ # function to implement a basic ray-tracer.
13
+ #
14
+ ##############################################################################
15
+
16
+ import os
17
+
18
+ import numpy as np
19
+ from pxr import Usd, UsdGeom
20
+
21
+ import warp as wp
22
+
23
+ wp.init()
24
+
25
+
26
+ @wp.kernel
27
+ def draw(mesh: wp.uint64, cam_pos: wp.vec3, width: int, height: int, pixels: wp.array(dtype=wp.vec3)):
28
+ tid = wp.tid()
29
+
30
+ x = tid % width
31
+ y = tid // width
32
+
33
+ sx = 2.0 * float(x) / float(height) - 1.0
34
+ sy = 2.0 * float(y) / float(height) - 1.0
35
+
36
+ # compute view ray
37
+ ro = cam_pos
38
+ rd = wp.normalize(wp.vec3(sx, sy, -1.0))
39
+
40
+ color = wp.vec3(0.0, 0.0, 0.0)
41
+
42
+ query = wp.mesh_query_ray(mesh, ro, rd, 1.0e6)
43
+ if query.result:
44
+ color = query.normal * 0.5 + wp.vec3(0.5, 0.5, 0.5)
45
+
46
+ pixels[tid] = color
47
+
48
+
49
+ class Example:
50
+ def __init__(self, **kwargs):
51
+ self.width = 1024
52
+ self.height = 1024
53
+ self.cam_pos = (0.0, 1.0, 2.0)
54
+
55
+ asset_stage = Usd.Stage.Open(os.path.join(os.path.dirname(__file__), "../assets/bunny.usd"))
56
+ mesh_geom = UsdGeom.Mesh(asset_stage.GetPrimAtPath("/bunny/bunny"))
57
+
58
+ points = np.array(mesh_geom.GetPointsAttr().Get())
59
+ indices = np.array(mesh_geom.GetFaceVertexIndicesAttr().Get())
60
+
61
+ self.pixels = wp.zeros(self.width * self.height, dtype=wp.vec3)
62
+
63
+ # create wp mesh
64
+ self.mesh = wp.Mesh(
65
+ points=wp.array(points, dtype=wp.vec3), velocities=None, indices=wp.array(indices, dtype=int)
66
+ )
67
+
68
+ def step(self):
69
+ pass
70
+
71
+ def render(self):
72
+ with wp.ScopedTimer("render"):
73
+ wp.launch(
74
+ kernel=draw,
75
+ dim=self.width * self.height,
76
+ inputs=[self.mesh.id, self.cam_pos, self.width, self.height, self.pixels],
77
+ )
78
+
79
+
80
+ if __name__ == "__main__":
81
+ import matplotlib.pyplot as plt
82
+
83
+ example = Example()
84
+ example.render()
85
+
86
+ plt.imshow(
87
+ example.pixels.numpy().reshape((example.height, example.width, 3)), origin="lower", interpolation="antialiased"
88
+ )
89
+ plt.show()