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,267 @@
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 Fluid
10
+ #
11
+ # Shows how to implement a simple 2D Stable Fluids solver using
12
+ # multidimensional arrays and launches.
13
+ #
14
+ ###########################################################################
15
+
16
+ import math
17
+
18
+ import warp as wp
19
+ import warp.render
20
+
21
+ wp.init()
22
+
23
+ grid_width = wp.constant(256)
24
+ grid_height = wp.constant(128)
25
+
26
+
27
+ @wp.func
28
+ def lookup_float(f: wp.array2d(dtype=float), x: int, y: int):
29
+ x = wp.clamp(x, 0, grid_width - 1)
30
+ y = wp.clamp(y, 0, grid_height - 1)
31
+
32
+ return f[x, y]
33
+
34
+
35
+ @wp.func
36
+ def sample_float(f: wp.array2d(dtype=float), x: float, y: float):
37
+ lx = int(wp.floor(x))
38
+ ly = int(wp.floor(y))
39
+
40
+ tx = x - float(lx)
41
+ ty = y - float(ly)
42
+
43
+ s0 = wp.lerp(lookup_float(f, lx, ly), lookup_float(f, lx + 1, ly), tx)
44
+ s1 = wp.lerp(lookup_float(f, lx, ly + 1), lookup_float(f, lx + 1, ly + 1), tx)
45
+
46
+ s = wp.lerp(s0, s1, ty)
47
+ return s
48
+
49
+
50
+ @wp.func
51
+ def lookup_vel(f: wp.array2d(dtype=wp.vec2), x: int, y: int):
52
+ if x < 0 or x >= grid_width:
53
+ return wp.vec2()
54
+ if y < 0 or y >= grid_height:
55
+ return wp.vec2()
56
+
57
+ return f[x, y]
58
+
59
+
60
+ @wp.func
61
+ def sample_vel(f: wp.array2d(dtype=wp.vec2), x: float, y: float):
62
+ lx = int(wp.floor(x))
63
+ ly = int(wp.floor(y))
64
+
65
+ tx = x - float(lx)
66
+ ty = y - float(ly)
67
+
68
+ s0 = wp.lerp(lookup_vel(f, lx, ly), lookup_vel(f, lx + 1, ly), tx)
69
+ s1 = wp.lerp(lookup_vel(f, lx, ly + 1), lookup_vel(f, lx + 1, ly + 1), tx)
70
+
71
+ s = wp.lerp(s0, s1, ty)
72
+ return s
73
+
74
+
75
+ @wp.kernel
76
+ def advect(
77
+ u0: wp.array2d(dtype=wp.vec2),
78
+ u1: wp.array2d(dtype=wp.vec2),
79
+ rho0: wp.array2d(dtype=float),
80
+ rho1: wp.array2d(dtype=float),
81
+ dt: float,
82
+ ):
83
+ i, j = wp.tid()
84
+
85
+ u = u0[i, j]
86
+
87
+ # trace backward
88
+ p = wp.vec2(float(i), float(j))
89
+ p = p - u * dt
90
+
91
+ # advect
92
+ u1[i, j] = sample_vel(u0, p[0], p[1])
93
+ rho1[i, j] = sample_float(rho0, p[0], p[1])
94
+
95
+
96
+ @wp.kernel
97
+ def divergence(u: wp.array2d(dtype=wp.vec2), div: wp.array2d(dtype=float)):
98
+ i, j = wp.tid()
99
+
100
+ if i == grid_width - 1:
101
+ return
102
+ if j == grid_height - 1:
103
+ return
104
+
105
+ dx = (u[i + 1, j][0] - u[i, j][0]) * 0.5
106
+ dy = (u[i, j + 1][1] - u[i, j][1]) * 0.5
107
+
108
+ div[i, j] = dx + dy
109
+
110
+
111
+ @wp.kernel
112
+ def pressure_solve(p0: wp.array2d(dtype=float), p1: wp.array2d(dtype=float), div: wp.array2d(dtype=float)):
113
+ i, j = wp.tid()
114
+
115
+ s1 = lookup_float(p0, i - 1, j)
116
+ s2 = lookup_float(p0, i + 1, j)
117
+ s3 = lookup_float(p0, i, j - 1)
118
+ s4 = lookup_float(p0, i, j + 1)
119
+
120
+ # Jacobi update
121
+ err = s1 + s2 + s3 + s4 - div[i, j]
122
+
123
+ p1[i, j] = err * 0.25
124
+
125
+
126
+ @wp.kernel
127
+ def pressure_apply(p: wp.array2d(dtype=float), u: wp.array2d(dtype=wp.vec2)):
128
+ i, j = wp.tid()
129
+
130
+ if i == 0 or i == grid_width - 1:
131
+ return
132
+ if j == 0 or j == grid_height - 1:
133
+ return
134
+
135
+ # pressure gradient
136
+ f_p = wp.vec2(p[i + 1, j] - p[i - 1, j], p[i, j + 1] - p[i, j - 1]) * 0.5
137
+
138
+ u[i, j] = u[i, j] - f_p
139
+
140
+
141
+ @wp.kernel
142
+ def integrate(u: wp.array2d(dtype=wp.vec2), rho: wp.array2d(dtype=float), dt: float):
143
+ i, j = wp.tid()
144
+
145
+ # gravity
146
+ f_g = wp.vec2(-90.8, 0.0) * rho[i, j]
147
+
148
+ # integrate
149
+ u[i, j] = u[i, j] + dt * f_g
150
+
151
+ # fade
152
+ rho[i, j] = rho[i, j] * (1.0 - 0.1 * dt)
153
+
154
+
155
+ @wp.kernel
156
+ def init(rho: wp.array2d(dtype=float), u: wp.array2d(dtype=wp.vec2), radius: int, dir: wp.vec2):
157
+ i, j = wp.tid()
158
+
159
+ d = wp.length(wp.vec2(float(i - grid_width / 2), float(j - grid_height / 2)))
160
+
161
+ if d < radius:
162
+ rho[i, j] = 1.0
163
+ u[i, j] = dir
164
+
165
+
166
+ class Example:
167
+ def __init__(self, **kwargs):
168
+
169
+ self.sim_fps = 60.0
170
+ self.sim_substeps = 2
171
+ self.iterations = 100
172
+ self.sim_dt = (1.0 / self.sim_fps) / self.sim_substeps
173
+ self.sim_time = 0.0
174
+
175
+ shape = (grid_width, grid_height)
176
+
177
+ self.u0 = wp.zeros(shape, dtype=wp.vec2)
178
+ self.u1 = wp.zeros(shape, dtype=wp.vec2)
179
+
180
+ self.rho0 = wp.zeros(shape, dtype=float)
181
+ self.rho1 = wp.zeros(shape, dtype=float)
182
+
183
+ self.p0 = wp.zeros(shape, dtype=float)
184
+ self.p1 = wp.zeros(shape, dtype=float)
185
+ self.div = wp.zeros(shape, dtype=float)
186
+
187
+ # capture pressure solve as a CUDA graph
188
+ self.use_graph = wp.get_device().is_cuda
189
+ if self.use_graph:
190
+ with wp.ScopedCapture() as capture:
191
+ self.pressure_iterations()
192
+ self.graph = capture.graph
193
+
194
+ def step(self):
195
+ with wp.ScopedTimer("step"):
196
+ for _ in range(self.sim_substeps):
197
+ shape = (grid_width, grid_height)
198
+ dt = self.sim_dt
199
+
200
+ speed = 400.0
201
+ angle = math.sin(self.sim_time * 4.0) * 1.5
202
+ vel = wp.vec2(math.cos(angle) * speed, math.sin(angle) * speed)
203
+
204
+ # update emitters
205
+ wp.launch(init, dim=shape, inputs=[self.rho0, self.u0, 5, vel])
206
+
207
+ # force integrate
208
+ wp.launch(integrate, dim=shape, inputs=[self.u0, self.rho0, dt])
209
+ wp.launch(divergence, dim=shape, inputs=[self.u0, self.div])
210
+
211
+ # pressure solve
212
+ self.p0.zero_()
213
+ self.p1.zero_()
214
+
215
+ if self.use_graph:
216
+ wp.capture_launch(self.graph)
217
+ else:
218
+ self.pressure_iterations()
219
+
220
+ # velocity update
221
+ wp.launch(pressure_apply, dim=shape, inputs=[self.p0, self.u0])
222
+
223
+ # semi-Lagrangian advection
224
+ wp.launch(advect, dim=shape, inputs=[self.u0, self.u1, self.rho0, self.rho1, dt])
225
+
226
+ # swap buffers
227
+ (self.u0, self.u1) = (self.u1, self.u0)
228
+ (self.rho0, self.rho1) = (self.rho1, self.rho0)
229
+
230
+ self.sim_time += dt
231
+
232
+ def render(self):
233
+ pass
234
+
235
+ def pressure_iterations(self):
236
+ for _ in range(self.iterations):
237
+ wp.launch(pressure_solve, dim=self.p0.shape, inputs=[self.p0, self.p1, self.div])
238
+
239
+ # swap pressure fields
240
+ (self.p0, self.p1) = (self.p1, self.p0)
241
+
242
+ def step_and_render_frame(self, frame_num=None, img=None):
243
+ self.step()
244
+
245
+ with wp.ScopedTimer("render"):
246
+ if img:
247
+ img.set_array(self.rho0.numpy())
248
+
249
+ return (img,)
250
+
251
+
252
+ if __name__ == "__main__":
253
+ import matplotlib
254
+ import matplotlib.animation as anim
255
+ import matplotlib.pyplot as plt
256
+
257
+ example = Example()
258
+
259
+ fig = plt.figure()
260
+
261
+ img = plt.imshow(example.rho0.numpy(), origin="lower", animated=True, interpolation="antialiased")
262
+ img.set_norm(matplotlib.colors.Normalize(0.0, 1.0))
263
+ seq = anim.FuncAnimation(
264
+ fig, example.step_and_render_frame, fargs=(img,), frames=100000, blit=True, interval=8, repeat=False
265
+ )
266
+
267
+ plt.show()
@@ -0,0 +1,129 @@
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 Graph Capture
10
+ #
11
+ # Shows how to implement CUDA graph capture using Python's try-finally
12
+ # pattern. The finally block ensures wp.capture_end() gets called, even
13
+ # if an exception occurs during capture, which would otherwise
14
+ # trap the stream in a capturing state.
15
+ #
16
+ ###########################################################################
17
+
18
+ import warp as wp
19
+ import numpy as np
20
+ import matplotlib.pyplot as plt
21
+ import matplotlib.colors
22
+ from matplotlib.animation import FuncAnimation
23
+
24
+ wp.init()
25
+
26
+
27
+ @wp.kernel
28
+ def fbm(
29
+ kernel_seed: int,
30
+ frequency: float,
31
+ amplitude: float,
32
+ x: wp.array(dtype=float),
33
+ y: wp.array(dtype=float),
34
+ z: wp.array2d(dtype=float),
35
+ ):
36
+ i, j = wp.tid()
37
+ state = wp.rand_init(kernel_seed)
38
+
39
+ p = frequency * wp.vec2(x[j], y[i])
40
+ n = amplitude * wp.noise(state, p)
41
+
42
+ z[i, j] += n
43
+
44
+
45
+ @wp.kernel
46
+ def slide(x: wp.array(dtype=float), shift: float):
47
+ tid = wp.tid()
48
+ x[tid] += shift
49
+
50
+
51
+ class Example:
52
+ def __init__(self):
53
+ self.W = 128
54
+ self.H = 128
55
+ min_x, max_x = 0.0, 2.0
56
+ min_y, max_y = 0.0, 2.0
57
+
58
+ # create a grid of pixels
59
+ x = np.linspace(min_x, max_x, self.W)
60
+ y = np.linspace(min_y, max_y, self.H)
61
+
62
+ self.x = wp.array(x, dtype=float)
63
+ self.y = wp.array(y, dtype=float)
64
+ self.pixel_values = wp.zeros((self.W, self.H), dtype=float)
65
+
66
+ self.seed = 42
67
+ self.shift = 2e-2
68
+ self.frequency = 1.0
69
+ self.amplitude = 1.0
70
+
71
+ # use graph capture if launching from a CUDA-capable device
72
+ self.use_graph = wp.get_device().is_cuda
73
+ if self.use_graph:
74
+ # record launches
75
+ with wp.ScopedCapture() as capture:
76
+ self.fbm()
77
+ self.graph = capture.graph
78
+
79
+ def fbm(self):
80
+ for _ in range(16):
81
+ wp.launch(
82
+ kernel=fbm,
83
+ dim=(self.H, self.W),
84
+ inputs=[self.seed, self.frequency, self.amplitude, self.x, self.y],
85
+ outputs=[self.pixel_values],
86
+ )
87
+ self.frequency *= 2.0
88
+ self.amplitude *= 0.5
89
+
90
+ def step(self):
91
+ self.pixel_values.zero_()
92
+ self.frequency = 1.0
93
+ self.amplitude = 1.0
94
+
95
+ with wp.ScopedTimer("step", active=True):
96
+ wp.launch(kernel=slide, dim=self.W, inputs=[self.x, self.shift])
97
+
98
+ if self.use_graph:
99
+ wp.capture_launch(self.graph)
100
+ else: # cpu path
101
+ self.fbm()
102
+
103
+ def render(self):
104
+ pass
105
+
106
+ def step_and_render(self, frame_num=None, img=None):
107
+ self.step()
108
+
109
+ with wp.ScopedTimer("render"):
110
+ if img:
111
+ pixels = self.pixel_values.numpy()
112
+ pixels = (pixels + 1.0) / 2.0
113
+ img.set_array(pixels)
114
+
115
+ return (img,)
116
+
117
+
118
+ if __name__ == "__main__":
119
+ example = Example()
120
+
121
+ # Create the animation
122
+ fig = plt.figure()
123
+ img = plt.imshow(example.pixel_values.numpy(), "gray", origin="lower", animated=True)
124
+ img.set_norm(matplotlib.colors.Normalize(0.0, 1.0))
125
+
126
+ ani = FuncAnimation(fig, example.step_and_render, fargs=(img,), frames=1000, interval=30)
127
+
128
+ # Display the animation
129
+ plt.show()
@@ -0,0 +1,177 @@
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 Marching Cubes
10
+ #
11
+ # Shows how use the built-in marching cubes functionality to extract
12
+ # the iso-surface from a density field.
13
+ #
14
+ # Note: requires a CUDA-capable device
15
+ ###########################################################################
16
+
17
+
18
+ import os
19
+ from typing import Optional
20
+
21
+ import warp as wp
22
+ import warp.render
23
+
24
+ wp.init()
25
+
26
+
27
+ @wp.func
28
+ def sdf_create_box(pos: wp.vec3, size: wp.vec3):
29
+ """Creates a SDF box primitive."""
30
+ # https://iquilezles.org/articles/distfunctions
31
+ q = wp.vec3(
32
+ wp.abs(pos[0]) - size[0],
33
+ wp.abs(pos[1]) - size[1],
34
+ wp.abs(pos[2]) - size[2],
35
+ )
36
+ qp = wp.vec3(wp.max(q[0], 0.0), wp.max(q[1], 0.0), wp.max(q[2], 0.0))
37
+ return wp.length(qp) + wp.min(wp.max(q[0], wp.max(q[1], q[2])), 0.0)
38
+
39
+
40
+ @wp.func
41
+ def sdf_create_torus(pos: wp.vec3, major_radius: float, minor_radius: float):
42
+ """Creates a SDF torus primitive."""
43
+ # https://iquilezles.org/articles/distfunctions
44
+ q = wp.vec2(wp.length(wp.vec2(pos[0], pos[2])) - major_radius, pos[1])
45
+ return wp.length(q) - minor_radius
46
+
47
+
48
+ @wp.func
49
+ def sdf_translate(pos: wp.vec3, offset: wp.vec3):
50
+ """Translates a SDF position vector with an offset."""
51
+ return pos - offset
52
+
53
+
54
+ @wp.func
55
+ def sdf_rotate(pos: wp.vec3, angles: wp.vec3):
56
+ """Rotates a SDF position vector using Euler angles."""
57
+ rot = wp.quat_rpy(
58
+ wp.radians(angles[0]),
59
+ wp.radians(angles[1]),
60
+ wp.radians(angles[2]),
61
+ )
62
+ return wp.quat_rotate_inv(rot, pos)
63
+
64
+
65
+ @wp.func
66
+ def sdf_smooth_min(a: float, b: float, radius: float):
67
+ """Creates a SDF torus primitive."""
68
+ # https://iquilezles.org/articles/smin
69
+ h = wp.max(radius - wp.abs(a - b), 0.0) / radius
70
+ return wp.min(a, b) - h * h * h * radius * (1.0 / 6.0)
71
+
72
+
73
+ @wp.kernel(enable_backward=False)
74
+ def make_field(
75
+ torus_altitude: float,
76
+ torus_major_radius: float,
77
+ torus_minor_radius: float,
78
+ smooth_min_radius: float,
79
+ dim: int,
80
+ time: float,
81
+ out_data: wp.array3d(dtype=float),
82
+ ):
83
+ """Kernel to generate a SDF volume based on primitives."""
84
+ i, j, k = wp.tid()
85
+
86
+ # Retrieve the position of the current cell in a normalized [-1, 1] range
87
+ # for each dimension.
88
+ pos = wp.vec3(
89
+ 2.0 * ((float(i) + 0.5) / float(dim)) - 1.0,
90
+ 2.0 * ((float(j) + 0.5) / float(dim)) - 1.0,
91
+ 2.0 * ((float(k) + 0.5) / float(dim)) - 1.0,
92
+ )
93
+
94
+ box = sdf_create_box(
95
+ sdf_translate(pos, wp.vec3(0.0, -0.7, 0.0)),
96
+ wp.vec3(0.9, 0.3, 0.9),
97
+ )
98
+ torus = sdf_create_torus(
99
+ sdf_rotate(
100
+ sdf_translate(pos, wp.vec3(0.0, torus_altitude, 0.0)),
101
+ wp.vec3(wp.sin(time) * 90.0, wp.cos(time) * 45.0, 0.0),
102
+ ),
103
+ torus_major_radius,
104
+ torus_minor_radius,
105
+ )
106
+ out_data[i, j, k] = sdf_smooth_min(box, torus, smooth_min_radius)
107
+
108
+
109
+ class Example:
110
+ def __init__(self, stage: Optional[str]):
111
+ self.dim = 64
112
+ self.max_verts = int(1e6)
113
+ self.max_tris = int(1e6)
114
+
115
+ self.torus_altitude = -0.5
116
+ self.torus_major_radius = 0.5
117
+ self.torus_minor_radius = 0.1
118
+ self.smooth_min_radius = 0.5
119
+
120
+ self.fps = 60.0
121
+ self.frame = 0
122
+
123
+ self.field = wp.zeros((self.dim, self.dim, self.dim), dtype=float)
124
+ self.mc = wp.MarchingCubes(self.dim, self.dim, self.dim, self.max_verts, self.max_tris)
125
+
126
+ self.renderer = None
127
+ if stage is not None:
128
+ self.renderer = wp.render.UsdRenderer(stage)
129
+
130
+ def step(self):
131
+ with wp.ScopedTimer("Update Field"):
132
+ wp.launch(
133
+ make_field,
134
+ dim=self.field.shape,
135
+ inputs=(
136
+ self.torus_altitude,
137
+ self.torus_major_radius,
138
+ self.torus_minor_radius,
139
+ self.smooth_min_radius,
140
+ self.dim,
141
+ self.frame / self.fps,
142
+ ),
143
+ outputs=(self.field,),
144
+ )
145
+
146
+ with wp.ScopedTimer("Surface Extraction"):
147
+ self.mc.surface(self.field, 0.0)
148
+
149
+ def render(self):
150
+ if self.renderer is None:
151
+ return
152
+
153
+ with wp.ScopedTimer("Render"):
154
+ self.renderer.begin_frame(self.frame / self.fps)
155
+ self.renderer.render_mesh(
156
+ "surface",
157
+ self.mc.verts.numpy(),
158
+ self.mc.indices.numpy(),
159
+ colors=((0.35, 0.55, 0.9),) * len(self.mc.verts),
160
+ update_topology=True,
161
+ )
162
+ self.renderer.end_frame()
163
+
164
+
165
+ if __name__ == "__main__":
166
+ this_dir = os.path.realpath(os.path.dirname(__file__))
167
+ this_file = os.path.basename(__file__).split(".")[0]
168
+ stage_path = os.path.join(this_dir, f"{this_file}.usd")
169
+
170
+ example = Example(stage_path)
171
+ for _ in range(240):
172
+ example.step()
173
+ example.render()
174
+ example.frame += 1
175
+
176
+ if example.renderer is not None:
177
+ example.renderer.save()