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,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()
|