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.
- warp/__init__.py +8 -0
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +7 -6
- warp/build_dll.py +70 -79
- warp/builtins.py +10 -6
- warp/codegen.py +51 -19
- warp/config.py +7 -8
- warp/constants.py +3 -0
- warp/context.py +948 -245
- warp/dlpack.py +198 -113
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -0
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usda +42 -0
- warp/examples/assets/nv_ant.xml +92 -0
- warp/examples/assets/nv_humanoid.xml +183 -0
- warp/examples/assets/quadruped.urdf +268 -0
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usda +56 -0
- warp/examples/assets/torus.usda +105 -0
- warp/examples/benchmarks/benchmark_api.py +383 -0
- warp/examples/benchmarks/benchmark_cloth.py +279 -0
- warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -0
- warp/examples/benchmarks/benchmark_cloth_jax.py +100 -0
- warp/examples/benchmarks/benchmark_cloth_numba.py +142 -0
- warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -0
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -0
- warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -0
- warp/examples/benchmarks/benchmark_cloth_warp.py +146 -0
- warp/examples/benchmarks/benchmark_launches.py +295 -0
- warp/examples/core/example_dem.py +221 -0
- warp/examples/core/example_fluid.py +267 -0
- warp/examples/core/example_graph_capture.py +129 -0
- warp/examples/core/example_marching_cubes.py +177 -0
- warp/examples/core/example_mesh.py +154 -0
- warp/examples/core/example_mesh_intersect.py +193 -0
- warp/examples/core/example_nvdb.py +169 -0
- warp/examples/core/example_raycast.py +89 -0
- warp/examples/core/example_raymarch.py +178 -0
- warp/examples/core/example_render_opengl.py +141 -0
- warp/examples/core/example_sph.py +389 -0
- warp/examples/core/example_torch.py +181 -0
- warp/examples/core/example_wave.py +249 -0
- warp/examples/fem/bsr_utils.py +380 -0
- warp/examples/fem/example_apic_fluid.py +391 -0
- warp/examples/fem/example_convection_diffusion.py +168 -0
- warp/examples/fem/example_convection_diffusion_dg.py +209 -0
- warp/examples/fem/example_convection_diffusion_dg0.py +194 -0
- warp/examples/fem/example_deformed_geometry.py +159 -0
- warp/examples/fem/example_diffusion.py +173 -0
- warp/examples/fem/example_diffusion_3d.py +152 -0
- warp/examples/fem/example_diffusion_mgpu.py +214 -0
- warp/examples/fem/example_mixed_elasticity.py +222 -0
- warp/examples/fem/example_navier_stokes.py +243 -0
- warp/examples/fem/example_stokes.py +192 -0
- warp/examples/fem/example_stokes_transfer.py +249 -0
- warp/examples/fem/mesh_utils.py +109 -0
- warp/examples/fem/plot_utils.py +287 -0
- warp/examples/optim/example_bounce.py +248 -0
- warp/examples/optim/example_cloth_throw.py +210 -0
- warp/examples/optim/example_diffray.py +535 -0
- warp/examples/optim/example_drone.py +850 -0
- warp/examples/optim/example_inverse_kinematics.py +169 -0
- warp/examples/optim/example_inverse_kinematics_torch.py +170 -0
- warp/examples/optim/example_spring_cage.py +234 -0
- warp/examples/optim/example_trajectory.py +201 -0
- warp/examples/sim/example_cartpole.py +128 -0
- warp/examples/sim/example_cloth.py +184 -0
- warp/examples/sim/example_granular.py +113 -0
- warp/examples/sim/example_granular_collision_sdf.py +185 -0
- warp/examples/sim/example_jacobian_ik.py +213 -0
- warp/examples/sim/example_particle_chain.py +106 -0
- warp/examples/sim/example_quadruped.py +179 -0
- warp/examples/sim/example_rigid_chain.py +191 -0
- warp/examples/sim/example_rigid_contact.py +176 -0
- warp/examples/sim/example_rigid_force.py +126 -0
- warp/examples/sim/example_rigid_gyroscopic.py +97 -0
- warp/examples/sim/example_rigid_soft_contact.py +124 -0
- warp/examples/sim/example_soft_body.py +178 -0
- warp/fabric.py +29 -20
- warp/fem/cache.py +0 -1
- warp/fem/dirichlet.py +0 -2
- warp/fem/integrate.py +0 -1
- warp/jax.py +45 -0
- warp/jax_experimental.py +339 -0
- warp/native/builtin.h +12 -0
- warp/native/bvh.cu +18 -18
- warp/native/clang/clang.cpp +8 -3
- warp/native/cuda_util.cpp +94 -5
- warp/native/cuda_util.h +35 -6
- warp/native/cutlass_gemm.cpp +1 -1
- warp/native/cutlass_gemm.cu +4 -1
- warp/native/error.cpp +66 -0
- warp/native/error.h +27 -0
- warp/native/mesh.cu +2 -2
- warp/native/reduce.cu +4 -4
- warp/native/runlength_encode.cu +2 -2
- warp/native/scan.cu +2 -2
- warp/native/sparse.cu +0 -1
- warp/native/temp_buffer.h +2 -2
- warp/native/warp.cpp +95 -60
- warp/native/warp.cu +1053 -218
- warp/native/warp.h +49 -32
- warp/optim/linear.py +33 -16
- warp/render/render_opengl.py +202 -101
- warp/render/render_usd.py +82 -40
- warp/sim/__init__.py +13 -4
- warp/sim/articulation.py +4 -5
- warp/sim/collide.py +320 -175
- warp/sim/import_mjcf.py +25 -30
- warp/sim/import_urdf.py +94 -63
- warp/sim/import_usd.py +51 -36
- warp/sim/inertia.py +3 -2
- warp/sim/integrator.py +233 -0
- warp/sim/integrator_euler.py +447 -469
- warp/sim/integrator_featherstone.py +1991 -0
- warp/sim/integrator_xpbd.py +1420 -640
- warp/sim/model.py +765 -487
- warp/sim/particles.py +2 -1
- warp/sim/render.py +35 -13
- warp/sim/utils.py +222 -11
- warp/stubs.py +8 -0
- warp/tape.py +16 -1
- warp/tests/aux_test_grad_customs.py +23 -0
- warp/tests/test_array.py +190 -1
- warp/tests/test_async.py +656 -0
- warp/tests/test_bool.py +50 -0
- warp/tests/test_dlpack.py +164 -11
- warp/tests/test_examples.py +166 -74
- warp/tests/test_fem.py +8 -1
- warp/tests/test_generics.py +15 -5
- warp/tests/test_grad.py +1 -1
- warp/tests/test_grad_customs.py +172 -12
- warp/tests/test_jax.py +254 -0
- warp/tests/test_large.py +29 -6
- warp/tests/test_launch.py +25 -0
- warp/tests/test_linear_solvers.py +20 -3
- warp/tests/test_matmul.py +61 -16
- warp/tests/test_matmul_lite.py +13 -13
- warp/tests/test_mempool.py +186 -0
- warp/tests/test_multigpu.py +3 -0
- warp/tests/test_options.py +16 -2
- warp/tests/test_peer.py +137 -0
- warp/tests/test_print.py +3 -1
- warp/tests/test_quat.py +23 -0
- warp/tests/test_sim_kinematics.py +97 -0
- warp/tests/test_snippet.py +126 -3
- warp/tests/test_streams.py +108 -79
- warp/tests/test_torch.py +16 -8
- warp/tests/test_utils.py +32 -27
- warp/tests/test_verify_fp.py +65 -0
- warp/tests/test_volume.py +1 -1
- warp/tests/unittest_serial.py +2 -0
- warp/tests/unittest_suites.py +12 -0
- warp/tests/unittest_utils.py +14 -7
- warp/thirdparty/unittest_parallel.py +15 -3
- warp/torch.py +10 -8
- warp/types.py +363 -246
- warp/utils.py +143 -19
- warp_lang-1.0.0.dist-info/LICENSE.md +126 -0
- warp_lang-1.0.0.dist-info/METADATA +394 -0
- {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/RECORD +167 -86
- warp/sim/optimizer.py +0 -138
- warp_lang-0.11.0.dist-info/LICENSE.md +0 -36
- warp_lang-0.11.0.dist-info/METADATA +0 -238
- /warp/tests/{walkthough_debug.py → walkthrough_debug.py} +0 -0
- {warp_lang-0.11.0.dist-info → warp_lang-1.0.0.dist-info}/WHEEL +0 -0
- {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()
|