warp-lang 1.8.0__py3-none-manylinux_2_34_aarch64.whl → 1.9.0__py3-none-manylinux_2_34_aarch64.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 +282 -103
- warp/__init__.pyi +482 -110
- warp/bin/warp-clang.so +0 -0
- warp/bin/warp.so +0 -0
- warp/build.py +93 -30
- warp/build_dll.py +48 -63
- warp/builtins.py +955 -137
- warp/codegen.py +327 -209
- warp/config.py +1 -1
- warp/context.py +1363 -800
- warp/examples/core/example_marching_cubes.py +1 -0
- warp/examples/core/example_render_opengl.py +100 -3
- warp/examples/fem/example_apic_fluid.py +98 -52
- warp/examples/fem/example_convection_diffusion_dg.py +25 -4
- warp/examples/fem/example_diffusion_mgpu.py +8 -3
- warp/examples/fem/utils.py +68 -22
- warp/examples/interop/example_jax_callable.py +34 -4
- warp/examples/interop/example_jax_kernel.py +27 -1
- warp/fabric.py +1 -1
- warp/fem/cache.py +27 -19
- warp/fem/domain.py +2 -2
- warp/fem/field/nodal_field.py +2 -2
- warp/fem/field/virtual.py +266 -166
- warp/fem/geometry/geometry.py +5 -5
- warp/fem/integrate.py +200 -91
- warp/fem/space/restriction.py +4 -0
- warp/fem/space/shape/tet_shape_function.py +3 -10
- warp/jax_experimental/custom_call.py +1 -1
- warp/jax_experimental/ffi.py +203 -54
- warp/marching_cubes.py +708 -0
- warp/native/array.h +103 -8
- warp/native/builtin.h +90 -9
- warp/native/bvh.cpp +64 -28
- warp/native/bvh.cu +58 -58
- warp/native/bvh.h +2 -2
- warp/native/clang/clang.cpp +7 -7
- warp/native/coloring.cpp +13 -3
- warp/native/crt.cpp +2 -2
- warp/native/crt.h +3 -5
- warp/native/cuda_util.cpp +42 -11
- warp/native/cuda_util.h +10 -4
- warp/native/exports.h +1842 -1908
- warp/native/fabric.h +2 -1
- warp/native/hashgrid.cpp +37 -37
- warp/native/hashgrid.cu +2 -2
- warp/native/initializer_array.h +1 -1
- warp/native/intersect.h +4 -4
- warp/native/mat.h +1913 -119
- warp/native/mathdx.cpp +43 -43
- warp/native/mesh.cpp +24 -24
- warp/native/mesh.cu +26 -26
- warp/native/mesh.h +5 -3
- warp/native/nanovdb/GridHandle.h +179 -12
- warp/native/nanovdb/HostBuffer.h +8 -7
- warp/native/nanovdb/NanoVDB.h +517 -895
- warp/native/nanovdb/NodeManager.h +323 -0
- warp/native/nanovdb/PNanoVDB.h +2 -2
- warp/native/quat.h +337 -16
- warp/native/rand.h +7 -7
- warp/native/range.h +7 -1
- warp/native/reduce.cpp +10 -10
- warp/native/reduce.cu +13 -14
- warp/native/runlength_encode.cpp +2 -2
- warp/native/runlength_encode.cu +5 -5
- warp/native/scan.cpp +3 -3
- warp/native/scan.cu +4 -4
- warp/native/sort.cpp +10 -10
- warp/native/sort.cu +22 -22
- warp/native/sparse.cpp +8 -8
- warp/native/sparse.cu +14 -14
- warp/native/spatial.h +366 -17
- warp/native/svd.h +23 -8
- warp/native/temp_buffer.h +2 -2
- warp/native/tile.h +303 -70
- warp/native/tile_radix_sort.h +5 -1
- warp/native/tile_reduce.h +16 -25
- warp/native/tuple.h +2 -2
- warp/native/vec.h +385 -18
- warp/native/volume.cpp +54 -54
- warp/native/volume.cu +1 -1
- warp/native/volume.h +2 -1
- warp/native/volume_builder.cu +30 -37
- warp/native/warp.cpp +150 -149
- warp/native/warp.cu +337 -193
- warp/native/warp.h +227 -226
- warp/optim/linear.py +736 -271
- warp/render/imgui_manager.py +289 -0
- warp/render/render_opengl.py +137 -57
- warp/render/render_usd.py +0 -1
- warp/sim/collide.py +1 -2
- warp/sim/graph_coloring.py +2 -2
- warp/sim/integrator_vbd.py +10 -2
- warp/sparse.py +559 -176
- warp/tape.py +2 -0
- warp/tests/aux_test_module_aot.py +7 -0
- warp/tests/cuda/test_async.py +3 -3
- warp/tests/cuda/test_conditional_captures.py +101 -0
- warp/tests/geometry/test_marching_cubes.py +233 -12
- warp/tests/sim/test_cloth.py +89 -6
- warp/tests/sim/test_coloring.py +82 -7
- warp/tests/test_array.py +56 -5
- warp/tests/test_assert.py +53 -0
- warp/tests/test_atomic_cas.py +127 -114
- warp/tests/test_codegen.py +3 -2
- warp/tests/test_context.py +8 -15
- warp/tests/test_enum.py +136 -0
- warp/tests/test_examples.py +2 -2
- warp/tests/test_fem.py +45 -2
- warp/tests/test_fixedarray.py +229 -0
- warp/tests/test_func.py +18 -15
- warp/tests/test_future_annotations.py +7 -5
- warp/tests/test_linear_solvers.py +30 -0
- warp/tests/test_map.py +1 -1
- warp/tests/test_mat.py +1540 -378
- warp/tests/test_mat_assign_copy.py +178 -0
- warp/tests/test_mat_constructors.py +574 -0
- warp/tests/test_module_aot.py +287 -0
- warp/tests/test_print.py +69 -0
- warp/tests/test_quat.py +162 -34
- warp/tests/test_quat_assign_copy.py +145 -0
- warp/tests/test_reload.py +2 -1
- warp/tests/test_sparse.py +103 -0
- warp/tests/test_spatial.py +140 -34
- warp/tests/test_spatial_assign_copy.py +160 -0
- warp/tests/test_static.py +48 -0
- warp/tests/test_struct.py +43 -3
- warp/tests/test_tape.py +38 -0
- warp/tests/test_types.py +0 -20
- warp/tests/test_vec.py +216 -441
- warp/tests/test_vec_assign_copy.py +143 -0
- warp/tests/test_vec_constructors.py +325 -0
- warp/tests/tile/test_tile.py +206 -152
- warp/tests/tile/test_tile_cholesky.py +605 -0
- warp/tests/tile/test_tile_load.py +169 -0
- warp/tests/tile/test_tile_mathdx.py +2 -558
- warp/tests/tile/test_tile_matmul.py +179 -0
- warp/tests/tile/test_tile_mlp.py +1 -1
- warp/tests/tile/test_tile_reduce.py +100 -11
- warp/tests/tile/test_tile_shared_memory.py +16 -16
- warp/tests/tile/test_tile_sort.py +59 -55
- warp/tests/unittest_suites.py +16 -0
- warp/tests/walkthrough_debug.py +1 -1
- warp/thirdparty/unittest_parallel.py +108 -9
- warp/types.py +554 -264
- warp/utils.py +68 -86
- {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/METADATA +28 -65
- {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/RECORD +150 -138
- warp/native/marching.cpp +0 -19
- warp/native/marching.cu +0 -514
- warp/native/marching.h +0 -19
- {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/licenses/LICENSE.md +0 -0
- {warp_lang-1.8.0.dist-info → warp_lang-1.9.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import warp as wp
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ImGuiManager:
|
|
22
|
+
"""Base class for managing an ImGui UI."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, renderer):
|
|
25
|
+
try:
|
|
26
|
+
import imgui
|
|
27
|
+
from imgui.integrations.pyglet import PygletProgrammablePipelineRenderer
|
|
28
|
+
|
|
29
|
+
self.imgui = imgui
|
|
30
|
+
self.is_available = True
|
|
31
|
+
except ImportError:
|
|
32
|
+
self.is_available = False
|
|
33
|
+
print('Warning: imgui not found. To use the UI, please install it with: pip install "imgui[pyglet]"')
|
|
34
|
+
return
|
|
35
|
+
|
|
36
|
+
self.imgui.create_context()
|
|
37
|
+
self.renderer = renderer
|
|
38
|
+
self.impl = PygletProgrammablePipelineRenderer(self.renderer.window)
|
|
39
|
+
|
|
40
|
+
def render_frame(self):
|
|
41
|
+
"""Renders a single frame of the UI. This should be called from the main render loop."""
|
|
42
|
+
if not self.is_available:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
io = self.imgui.get_io()
|
|
46
|
+
self.renderer.enable_mouse_interaction = not io.want_capture_mouse
|
|
47
|
+
self.renderer.enable_keyboard_interaction = not io.want_capture_keyboard
|
|
48
|
+
io.display_size = self.renderer.screen_width, self.renderer.screen_height
|
|
49
|
+
|
|
50
|
+
self.imgui.new_frame()
|
|
51
|
+
|
|
52
|
+
self.draw_ui()
|
|
53
|
+
|
|
54
|
+
self.imgui.render()
|
|
55
|
+
self.imgui.end_frame()
|
|
56
|
+
self.impl.render(self.imgui.get_draw_data())
|
|
57
|
+
|
|
58
|
+
def draw_ui(self):
|
|
59
|
+
"""Draws the UI. To be implemented by subclasses."""
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
def open_save_file_dialog(
|
|
63
|
+
self,
|
|
64
|
+
title: str = "Save File",
|
|
65
|
+
defaultextension: str = "",
|
|
66
|
+
filetypes: list[tuple[str, str]] | None = None,
|
|
67
|
+
) -> str | None:
|
|
68
|
+
"""Opens a file dialog for saving a file and returns the selected path."""
|
|
69
|
+
try:
|
|
70
|
+
import tkinter as tk
|
|
71
|
+
from tkinter import filedialog
|
|
72
|
+
except ImportError:
|
|
73
|
+
print("Warning: tkinter not found. To use the file dialog, please install it.")
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
root = tk.Tk()
|
|
78
|
+
except tk.TclError:
|
|
79
|
+
print("Warning: no display found - cannot open file dialog.")
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
root.withdraw() # Hide the main window
|
|
83
|
+
file_path = filedialog.asksaveasfilename(
|
|
84
|
+
defaultextension=defaultextension,
|
|
85
|
+
filetypes=filetypes or [("All Files", "*.*")],
|
|
86
|
+
title=title,
|
|
87
|
+
)
|
|
88
|
+
root.destroy()
|
|
89
|
+
return file_path
|
|
90
|
+
|
|
91
|
+
def open_load_file_dialog(
|
|
92
|
+
self, title: str = "Open File", filetypes: list[tuple[str, str]] | None = None
|
|
93
|
+
) -> str | None:
|
|
94
|
+
"""Opens a file dialog for loading a file and returns the selected path."""
|
|
95
|
+
try:
|
|
96
|
+
import tkinter as tk
|
|
97
|
+
from tkinter import filedialog
|
|
98
|
+
except ImportError:
|
|
99
|
+
print("Warning: tkinter not found. To use the file dialog, please install it.")
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
root = tk.Tk()
|
|
104
|
+
except tk.TclError:
|
|
105
|
+
print("Warning: no display found - cannot open file dialog.")
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
root.withdraw() # Hide the main window
|
|
109
|
+
file_path = filedialog.askopenfilename(
|
|
110
|
+
filetypes=filetypes or [("All Files", "*.*")],
|
|
111
|
+
title=title,
|
|
112
|
+
)
|
|
113
|
+
root.destroy()
|
|
114
|
+
return file_path
|
|
115
|
+
|
|
116
|
+
def drag_vec3(self, label, vec, speed=0.1, min_val=0.0, max_val=100.0):
|
|
117
|
+
"""Helper method to create a drag widget for a wp.vec3"""
|
|
118
|
+
changed, *values = self.imgui.drag_float3(label, *vec, speed, min_val, max_val)
|
|
119
|
+
if changed:
|
|
120
|
+
vec = wp.vec3(*values)
|
|
121
|
+
return changed, vec
|
|
122
|
+
|
|
123
|
+
def drag_vec3_list(
|
|
124
|
+
self,
|
|
125
|
+
label_prefix: str,
|
|
126
|
+
vec_list: list[wp.vec3] | wp.array,
|
|
127
|
+
speed: float = 0.1,
|
|
128
|
+
min_val: float = 0.0,
|
|
129
|
+
max_val: float = 100.0,
|
|
130
|
+
max_num_elements: int = 10,
|
|
131
|
+
) -> tuple[bool, list[wp.vec3] | wp.array]:
|
|
132
|
+
"""Helper method to create drag widgets for a list of wp.vec3.
|
|
133
|
+
|
|
134
|
+
Note: The `label_prefix` is used to create unique IDs for each widget.
|
|
135
|
+
If you are displaying multiple lists, ensure that `label_prefix` is unique
|
|
136
|
+
for each list to prevent UI elements from interfering with each other.
|
|
137
|
+
"""
|
|
138
|
+
self.imgui.text(f"List: {label_prefix} with {len(vec_list)} elements")
|
|
139
|
+
changed = False
|
|
140
|
+
|
|
141
|
+
# Convert to numpy array if it's a warp array
|
|
142
|
+
is_warp_array = isinstance(vec_list, wp.array)
|
|
143
|
+
working_array = vec_list.numpy() if is_warp_array else vec_list
|
|
144
|
+
|
|
145
|
+
for i, vec in enumerate(working_array[:max_num_elements]):
|
|
146
|
+
vec_changed, new_vec = self.drag_vec3(f"{label_prefix} {i}", vec, speed, min_val, max_val)
|
|
147
|
+
if vec_changed:
|
|
148
|
+
working_array[i] = new_vec
|
|
149
|
+
changed = True
|
|
150
|
+
|
|
151
|
+
if is_warp_array:
|
|
152
|
+
if changed:
|
|
153
|
+
return changed, wp.array(working_array, dtype=wp.vec3)
|
|
154
|
+
return changed, vec_list
|
|
155
|
+
return changed, working_array
|
|
156
|
+
|
|
157
|
+
def drag_vec2(
|
|
158
|
+
self, label: str, vec: wp.vec2, speed: float = 0.1, min_val: float = 0.0, max_val: float = 100.0
|
|
159
|
+
) -> tuple[bool, wp.vec2]:
|
|
160
|
+
"""Helper method to create a drag widget for a wp.vec2"""
|
|
161
|
+
changed, *values = self.imgui.drag_float2(label, *vec, speed, min_val, max_val)
|
|
162
|
+
if changed:
|
|
163
|
+
vec = wp.vec2(*values)
|
|
164
|
+
return changed, vec
|
|
165
|
+
|
|
166
|
+
def drag_vec2_list(
|
|
167
|
+
self,
|
|
168
|
+
label_prefix: str,
|
|
169
|
+
vec_list: list[wp.vec2] | wp.array,
|
|
170
|
+
speed: float = 0.1,
|
|
171
|
+
min_val: float = 0.0,
|
|
172
|
+
max_val: float = 100.0,
|
|
173
|
+
max_num_elements: int = 10,
|
|
174
|
+
) -> tuple[bool, list[wp.vec2] | wp.array]:
|
|
175
|
+
"""Helper method to create drag widgets for a list of wp.vec2.
|
|
176
|
+
|
|
177
|
+
Note: The `label_prefix` is used to create unique IDs for each widget.
|
|
178
|
+
If you are displaying multiple lists, ensure that `label_prefix` is unique
|
|
179
|
+
for each list to prevent UI elements from interfering with each other.
|
|
180
|
+
"""
|
|
181
|
+
self.imgui.text(f"List: {label_prefix} with {len(vec_list)} elements")
|
|
182
|
+
changed = False
|
|
183
|
+
|
|
184
|
+
# Convert to numpy array if it's a warp array
|
|
185
|
+
is_warp_array = isinstance(vec_list, wp.array)
|
|
186
|
+
working_array = vec_list.numpy() if is_warp_array else vec_list
|
|
187
|
+
|
|
188
|
+
for i, vec in enumerate(working_array[:max_num_elements]):
|
|
189
|
+
vec_changed, new_vec = self.drag_vec2(f"{label_prefix} {i}", vec, speed, min_val, max_val)
|
|
190
|
+
if vec_changed:
|
|
191
|
+
working_array[i] = new_vec
|
|
192
|
+
changed = True
|
|
193
|
+
|
|
194
|
+
if is_warp_array:
|
|
195
|
+
if changed:
|
|
196
|
+
return changed, wp.array(working_array, dtype=wp.vec2)
|
|
197
|
+
return changed, vec_list
|
|
198
|
+
return changed, working_array
|
|
199
|
+
|
|
200
|
+
def drag_vec4(
|
|
201
|
+
self, label: str, vec: wp.vec4, speed: float = 0.1, min_val: float = 0.0, max_val: float = 100.0
|
|
202
|
+
) -> tuple[bool, wp.vec4]:
|
|
203
|
+
"""Helper method to create a drag widget for a wp.vec4"""
|
|
204
|
+
changed, *values = self.imgui.drag_float4(label, *vec, speed, min_val, max_val)
|
|
205
|
+
if changed:
|
|
206
|
+
vec = wp.vec4(*values)
|
|
207
|
+
return changed, vec
|
|
208
|
+
|
|
209
|
+
def drag_vec4_list(
|
|
210
|
+
self,
|
|
211
|
+
label_prefix: str,
|
|
212
|
+
vec_list: list[wp.vec4] | wp.array,
|
|
213
|
+
speed: float = 0.1,
|
|
214
|
+
min_val: float = 0.0,
|
|
215
|
+
max_val: float = 100.0,
|
|
216
|
+
max_num_elements: int = 10,
|
|
217
|
+
) -> tuple[bool, list[wp.vec4] | wp.array]:
|
|
218
|
+
"""Helper method to create drag widgets for a list of wp.vec4.
|
|
219
|
+
|
|
220
|
+
Note: The `label_prefix` is used to create unique IDs for each widget.
|
|
221
|
+
If you are displaying multiple lists, ensure that `label_prefix` is unique
|
|
222
|
+
for each list to prevent UI elements from interfering with each other.
|
|
223
|
+
"""
|
|
224
|
+
self.imgui.text(f"List: {label_prefix} with {len(vec_list)} elements")
|
|
225
|
+
changed = False
|
|
226
|
+
|
|
227
|
+
# Convert to numpy array if it's a warp array
|
|
228
|
+
is_warp_array = isinstance(vec_list, wp.array)
|
|
229
|
+
working_array = vec_list.numpy() if is_warp_array else vec_list
|
|
230
|
+
|
|
231
|
+
for i, vec in enumerate(working_array[:max_num_elements]):
|
|
232
|
+
vec_changed, new_vec = self.drag_vec4(f"{label_prefix} {i}", vec, speed, min_val, max_val)
|
|
233
|
+
if vec_changed:
|
|
234
|
+
working_array[i] = new_vec
|
|
235
|
+
changed = True
|
|
236
|
+
|
|
237
|
+
if is_warp_array:
|
|
238
|
+
if changed:
|
|
239
|
+
return changed, wp.array(working_array, dtype=wp.vec4)
|
|
240
|
+
return changed, vec_list
|
|
241
|
+
return changed, working_array
|
|
242
|
+
|
|
243
|
+
def drag_float(
|
|
244
|
+
self, label: str, val: float, speed: float = 0.1, min_val: float = 0.0, max_val: float = 100.0
|
|
245
|
+
) -> tuple[bool, float]:
|
|
246
|
+
"""Helper method to create a drag widget for a float"""
|
|
247
|
+
changed, value = self.imgui.drag_float(label, val, speed, min_val, max_val)
|
|
248
|
+
if changed:
|
|
249
|
+
val = value
|
|
250
|
+
return changed, val
|
|
251
|
+
|
|
252
|
+
def drag_float_list(
|
|
253
|
+
self,
|
|
254
|
+
label_prefix: str,
|
|
255
|
+
float_list: list[float] | wp.array,
|
|
256
|
+
speed: float = 0.1,
|
|
257
|
+
min_val: float = 0.0,
|
|
258
|
+
max_val: float = 100.0,
|
|
259
|
+
max_num_elements: int = 10,
|
|
260
|
+
) -> tuple[bool, list[float] | wp.array]:
|
|
261
|
+
"""Helper method to create drag widgets for a list of floats.
|
|
262
|
+
|
|
263
|
+
Note: The `label_prefix` is used to create unique IDs for each widget.
|
|
264
|
+
If you are displaying multiple lists, ensure that `label_prefix` is unique
|
|
265
|
+
for each list to prevent UI elements from interfering with each other.
|
|
266
|
+
"""
|
|
267
|
+
self.imgui.text(f"List: {label_prefix} with {len(float_list)} elements")
|
|
268
|
+
changed = False
|
|
269
|
+
|
|
270
|
+
# Convert to numpy array if it's a warp array
|
|
271
|
+
is_warp_array = isinstance(float_list, wp.array)
|
|
272
|
+
working_array = float_list.numpy() if is_warp_array else float_list
|
|
273
|
+
|
|
274
|
+
for i, val in enumerate(working_array[:max_num_elements]):
|
|
275
|
+
val_changed, new_val = self.drag_float(f"{label_prefix} {i}", val, speed, min_val, max_val)
|
|
276
|
+
if val_changed:
|
|
277
|
+
working_array[i] = new_val
|
|
278
|
+
changed = True
|
|
279
|
+
|
|
280
|
+
if is_warp_array:
|
|
281
|
+
if changed:
|
|
282
|
+
return changed, wp.array(working_array, dtype=float_list.dtype)
|
|
283
|
+
return changed, float_list
|
|
284
|
+
return changed, working_array
|
|
285
|
+
|
|
286
|
+
def shutdown(self):
|
|
287
|
+
if not self.is_available:
|
|
288
|
+
return
|
|
289
|
+
self.impl.shutdown()
|
warp/render/render_opengl.py
CHANGED
|
@@ -320,15 +320,14 @@ def update_vbo_transforms(
|
|
|
320
320
|
@wp.kernel
|
|
321
321
|
def update_vbo_vertices(
|
|
322
322
|
points: wp.array(dtype=wp.vec3),
|
|
323
|
-
scale: wp.vec3,
|
|
324
323
|
# outputs
|
|
325
324
|
vbo_vertices: wp.array(dtype=float, ndim=2),
|
|
326
325
|
):
|
|
327
326
|
tid = wp.tid()
|
|
328
327
|
p = points[tid]
|
|
329
|
-
vbo_vertices[tid, 0] = p[0]
|
|
330
|
-
vbo_vertices[tid, 1] = p[1]
|
|
331
|
-
vbo_vertices[tid, 2] = p[2]
|
|
328
|
+
vbo_vertices[tid, 0] = p[0]
|
|
329
|
+
vbo_vertices[tid, 1] = p[1]
|
|
330
|
+
vbo_vertices[tid, 2] = p[2]
|
|
332
331
|
|
|
333
332
|
|
|
334
333
|
@wp.kernel
|
|
@@ -422,7 +421,6 @@ def compute_gfx_vertices(
|
|
|
422
421
|
def compute_average_normals(
|
|
423
422
|
indices: wp.array(dtype=int, ndim=2),
|
|
424
423
|
vertices: wp.array(dtype=wp.vec3),
|
|
425
|
-
scale: wp.vec3,
|
|
426
424
|
# outputs
|
|
427
425
|
normals: wp.array(dtype=wp.vec3),
|
|
428
426
|
faces_per_vertex: wp.array(dtype=int),
|
|
@@ -431,9 +429,9 @@ def compute_average_normals(
|
|
|
431
429
|
i = indices[tid, 0]
|
|
432
430
|
j = indices[tid, 1]
|
|
433
431
|
k = indices[tid, 2]
|
|
434
|
-
v0 = vertices[i]
|
|
435
|
-
v1 = vertices[j]
|
|
436
|
-
v2 = vertices[k]
|
|
432
|
+
v0 = vertices[i]
|
|
433
|
+
v1 = vertices[j]
|
|
434
|
+
v2 = vertices[k]
|
|
437
435
|
n = wp.normalize(wp.cross(v1 - v0, v2 - v0))
|
|
438
436
|
wp.atomic_add(normals, i, n)
|
|
439
437
|
wp.atomic_add(faces_per_vertex, i, 1)
|
|
@@ -448,16 +446,15 @@ def assemble_gfx_vertices(
|
|
|
448
446
|
vertices: wp.array(dtype=wp.vec3, ndim=1),
|
|
449
447
|
normals: wp.array(dtype=wp.vec3),
|
|
450
448
|
faces_per_vertex: wp.array(dtype=int),
|
|
451
|
-
scale: wp.vec3,
|
|
452
449
|
# outputs
|
|
453
450
|
gfx_vertices: wp.array(dtype=float, ndim=2),
|
|
454
451
|
):
|
|
455
452
|
tid = wp.tid()
|
|
456
453
|
v = vertices[tid]
|
|
457
454
|
n = normals[tid] / float(faces_per_vertex[tid])
|
|
458
|
-
gfx_vertices[tid, 0] = v[0]
|
|
459
|
-
gfx_vertices[tid, 1] = v[1]
|
|
460
|
-
gfx_vertices[tid, 2] = v[2]
|
|
455
|
+
gfx_vertices[tid, 0] = v[0]
|
|
456
|
+
gfx_vertices[tid, 1] = v[1]
|
|
457
|
+
gfx_vertices[tid, 2] = v[2]
|
|
461
458
|
gfx_vertices[tid, 3] = n[0]
|
|
462
459
|
gfx_vertices[tid, 4] = n[1]
|
|
463
460
|
gfx_vertices[tid, 5] = n[2]
|
|
@@ -1001,6 +998,7 @@ class OpenGLRenderer:
|
|
|
1001
998
|
enable_mouse_interaction=True,
|
|
1002
999
|
enable_keyboard_interaction=True,
|
|
1003
1000
|
device=None,
|
|
1001
|
+
use_legacy_opengl: bool | None = None,
|
|
1004
1002
|
):
|
|
1005
1003
|
"""
|
|
1006
1004
|
Args:
|
|
@@ -1031,6 +1029,7 @@ class OpenGLRenderer:
|
|
|
1031
1029
|
enable_mouse_interaction (bool): Whether to enable mouse interaction.
|
|
1032
1030
|
enable_keyboard_interaction (bool): Whether to enable keyboard interaction.
|
|
1033
1031
|
device (Devicelike): Where to store the internal data.
|
|
1032
|
+
use_legacy_opengl (bool | None): Whether to use a legacy OpenGL implementation that is more compatible with macOS. If ``None``, it will be automatically detected based on the operating system.
|
|
1034
1033
|
|
|
1035
1034
|
Note:
|
|
1036
1035
|
|
|
@@ -1076,6 +1075,11 @@ class OpenGLRenderer:
|
|
|
1076
1075
|
self.render_depth = render_depth
|
|
1077
1076
|
self.enable_backface_culling = enable_backface_culling
|
|
1078
1077
|
|
|
1078
|
+
if use_legacy_opengl is None:
|
|
1079
|
+
self.use_legacy_opengl = sys.platform == "darwin"
|
|
1080
|
+
else:
|
|
1081
|
+
self.use_legacy_opengl = use_legacy_opengl
|
|
1082
|
+
|
|
1079
1083
|
if device is None:
|
|
1080
1084
|
self._device = wp.get_preferred_device()
|
|
1081
1085
|
else:
|
|
@@ -1165,6 +1169,8 @@ class OpenGLRenderer:
|
|
|
1165
1169
|
self._wp_instance_bodies = None
|
|
1166
1170
|
self._update_shape_instances = False
|
|
1167
1171
|
self._add_shape_instances = False
|
|
1172
|
+
self.instance_matrix_size = 0
|
|
1173
|
+
self.instance_color_size = 0
|
|
1168
1174
|
|
|
1169
1175
|
# additional shape instancer used for points and line rendering
|
|
1170
1176
|
self._shape_instancers = {}
|
|
@@ -2054,9 +2060,43 @@ Instances: {len(self._instances)}"""
|
|
|
2054
2060
|
num_instances = len(self._shape_instances[shape])
|
|
2055
2061
|
|
|
2056
2062
|
gl.glBindVertexArray(vao)
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2063
|
+
if self.use_legacy_opengl:
|
|
2064
|
+
if self.instance_matrix_size > 0 and self.instance_color_size:
|
|
2065
|
+
# update attribute pointers
|
|
2066
|
+
matrix_size = self.instance_matrix_size
|
|
2067
|
+
color_size = self.instance_color_size
|
|
2068
|
+
|
|
2069
|
+
# update transforms
|
|
2070
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_transform_gl_buffer)
|
|
2071
|
+
for i in range(4):
|
|
2072
|
+
gl.glVertexAttribPointer(
|
|
2073
|
+
3 + i,
|
|
2074
|
+
4,
|
|
2075
|
+
gl.GL_FLOAT,
|
|
2076
|
+
gl.GL_FALSE,
|
|
2077
|
+
matrix_size,
|
|
2078
|
+
ctypes.c_void_p(start_instance_idx * matrix_size + i * matrix_size // 4),
|
|
2079
|
+
)
|
|
2080
|
+
gl.glVertexAttribDivisor(3 + i, 1)
|
|
2081
|
+
|
|
2082
|
+
# update colors
|
|
2083
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
|
|
2084
|
+
gl.glVertexAttribPointer(
|
|
2085
|
+
7, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2086
|
+
)
|
|
2087
|
+
gl.glVertexAttribDivisor(7, 1)
|
|
2088
|
+
|
|
2089
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
|
|
2090
|
+
gl.glVertexAttribPointer(
|
|
2091
|
+
8, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2092
|
+
)
|
|
2093
|
+
gl.glVertexAttribDivisor(8, 1)
|
|
2094
|
+
|
|
2095
|
+
gl.glDrawElementsInstanced(gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, num_instances)
|
|
2096
|
+
else:
|
|
2097
|
+
gl.glDrawElementsInstancedBaseInstance(
|
|
2098
|
+
gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, num_instances, start_instance_idx
|
|
2099
|
+
)
|
|
2060
2100
|
|
|
2061
2101
|
start_instance_idx += num_instances
|
|
2062
2102
|
|
|
@@ -2106,9 +2146,43 @@ Instances: {len(self._instances)}"""
|
|
|
2106
2146
|
start_instance_idx = self._inverse_instance_ids[instance]
|
|
2107
2147
|
|
|
2108
2148
|
gl.glBindVertexArray(vao)
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2149
|
+
if self.use_legacy_opengl:
|
|
2150
|
+
if self.instance_matrix_size > 0 and self.instance_color_size:
|
|
2151
|
+
# update attribute pointers
|
|
2152
|
+
matrix_size = self.instance_matrix_size
|
|
2153
|
+
color_size = self.instance_color_size
|
|
2154
|
+
|
|
2155
|
+
# update transforms
|
|
2156
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_transform_gl_buffer)
|
|
2157
|
+
for j in range(4):
|
|
2158
|
+
gl.glVertexAttribPointer(
|
|
2159
|
+
3 + j,
|
|
2160
|
+
4,
|
|
2161
|
+
gl.GL_FLOAT,
|
|
2162
|
+
gl.GL_FALSE,
|
|
2163
|
+
matrix_size,
|
|
2164
|
+
ctypes.c_void_p(start_instance_idx * matrix_size + j * matrix_size // 4),
|
|
2165
|
+
)
|
|
2166
|
+
gl.glVertexAttribDivisor(3 + j, 1)
|
|
2167
|
+
|
|
2168
|
+
# update colors
|
|
2169
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
|
|
2170
|
+
gl.glVertexAttribPointer(
|
|
2171
|
+
7, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2172
|
+
)
|
|
2173
|
+
gl.glVertexAttribDivisor(7, 1)
|
|
2174
|
+
|
|
2175
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
|
|
2176
|
+
gl.glVertexAttribPointer(
|
|
2177
|
+
8, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2178
|
+
)
|
|
2179
|
+
gl.glVertexAttribDivisor(8, 1)
|
|
2180
|
+
|
|
2181
|
+
gl.glDrawElementsInstanced(gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, 1)
|
|
2182
|
+
else:
|
|
2183
|
+
gl.glDrawElementsInstancedBaseInstance(
|
|
2184
|
+
gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, 1, start_instance_idx
|
|
2185
|
+
)
|
|
2112
2186
|
|
|
2113
2187
|
if self.draw_axis:
|
|
2114
2188
|
self._axis_instancer.render()
|
|
@@ -2396,6 +2470,7 @@ Instances: {len(self._instances)}"""
|
|
|
2396
2470
|
|
|
2397
2471
|
# set up instance attribute pointers
|
|
2398
2472
|
matrix_size = transforms[0].nbytes
|
|
2473
|
+
self.instance_matrix_size = matrix_size
|
|
2399
2474
|
|
|
2400
2475
|
instance_ids = []
|
|
2401
2476
|
instance_custom_ids = []
|
|
@@ -2404,6 +2479,7 @@ Instances: {len(self._instances)}"""
|
|
|
2404
2479
|
inverse_instance_ids = {}
|
|
2405
2480
|
instance_count = 0
|
|
2406
2481
|
colors_size = np.zeros(3, dtype=np.float32).nbytes
|
|
2482
|
+
self.instance_color_size = colors_size
|
|
2407
2483
|
for shape, (vao, _vbo, _ebo, _tri_count, _vertex_cuda_buffer) in self._shape_gl_buffers.items():
|
|
2408
2484
|
gl.glBindVertexArray(vao)
|
|
2409
2485
|
|
|
@@ -2445,7 +2521,7 @@ Instances: {len(self._instances)}"""
|
|
|
2445
2521
|
|
|
2446
2522
|
gl.glBindVertexArray(0)
|
|
2447
2523
|
|
|
2448
|
-
def update_shape_instance(self, name, pos=None, rot=None, color1=None, color2=None, visible=None):
|
|
2524
|
+
def update_shape_instance(self, name, pos=None, rot=None, color1=None, color2=None, scale=None, visible=None):
|
|
2449
2525
|
"""Update the instance properties of the shape
|
|
2450
2526
|
|
|
2451
2527
|
Args:
|
|
@@ -2461,7 +2537,7 @@ Instances: {len(self._instances)}"""
|
|
|
2461
2537
|
self._switch_context()
|
|
2462
2538
|
|
|
2463
2539
|
if name in self._instances:
|
|
2464
|
-
i, body, shape, tf,
|
|
2540
|
+
i, body, shape, tf, old_scale, old_color1, old_color2, v = self._instances[name]
|
|
2465
2541
|
if visible is None:
|
|
2466
2542
|
visible = v
|
|
2467
2543
|
new_tf = np.copy(tf)
|
|
@@ -2474,7 +2550,7 @@ Instances: {len(self._instances)}"""
|
|
|
2474
2550
|
body,
|
|
2475
2551
|
shape,
|
|
2476
2552
|
new_tf,
|
|
2477
|
-
scale,
|
|
2553
|
+
old_scale if scale is None else scale,
|
|
2478
2554
|
old_color1 if color1 is None else color1,
|
|
2479
2555
|
old_color2 if color2 is None else color2,
|
|
2480
2556
|
visible,
|
|
@@ -2968,7 +3044,7 @@ Instances: {len(self._instances)}"""
|
|
|
2968
3044
|
geo_hash = hash(("box", tuple(extents)))
|
|
2969
3045
|
if geo_hash in self._shape_geo_hash:
|
|
2970
3046
|
shape = self._shape_geo_hash[geo_hash]
|
|
2971
|
-
if self.update_shape_instance(name, pos, rot):
|
|
3047
|
+
if self.update_shape_instance(name, pos, rot, color1=color, color2=color):
|
|
2972
3048
|
return shape
|
|
2973
3049
|
else:
|
|
2974
3050
|
vertices, indices = self._create_box_mesh(extents)
|
|
@@ -3031,50 +3107,54 @@ Instances: {len(self._instances)}"""
|
|
|
3031
3107
|
if not update_topology:
|
|
3032
3108
|
if name in self._instances:
|
|
3033
3109
|
# Update the instance's transform.
|
|
3034
|
-
self.update_shape_instance(name, pos, rot, color1=colors)
|
|
3110
|
+
self.update_shape_instance(name, pos, rot, color1=colors, color2=colors, scale=scale, visible=visible)
|
|
3035
3111
|
|
|
3036
3112
|
if shape is not None:
|
|
3037
3113
|
# Update the shape's point positions.
|
|
3038
|
-
self.update_shape_vertices(shape, points
|
|
3114
|
+
self.update_shape_vertices(shape, points)
|
|
3039
3115
|
|
|
3040
3116
|
if not is_template and name not in self._instances:
|
|
3041
3117
|
# Create a new instance.
|
|
3042
3118
|
body = self._resolve_body_id(parent_body)
|
|
3043
|
-
self.add_shape_instance(name, shape, body, pos, rot, color1=colors)
|
|
3119
|
+
self.add_shape_instance(name, shape, body, pos, rot, color1=colors, scale=scale)
|
|
3044
3120
|
|
|
3045
3121
|
return shape
|
|
3046
3122
|
|
|
3047
3123
|
# No existing shape for the given mesh was found, or its topology may have changed,
|
|
3048
3124
|
# so we need to define a new one either way.
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3125
|
+
with wp.ScopedDevice(self._device):
|
|
3126
|
+
if smooth_shading:
|
|
3127
|
+
normals = wp.zeros(point_count, dtype=wp.vec3)
|
|
3128
|
+
vertices = wp.array(points, dtype=wp.vec3)
|
|
3129
|
+
faces_per_vertex = wp.zeros(point_count, dtype=int)
|
|
3130
|
+
wp.launch(
|
|
3131
|
+
compute_average_normals,
|
|
3132
|
+
dim=idx_count,
|
|
3133
|
+
inputs=[wp.array(indices, dtype=int), vertices],
|
|
3134
|
+
outputs=[normals, faces_per_vertex],
|
|
3135
|
+
record_tape=False,
|
|
3136
|
+
)
|
|
3137
|
+
gfx_vertices = wp.zeros((point_count, 8), dtype=float)
|
|
3138
|
+
wp.launch(
|
|
3139
|
+
assemble_gfx_vertices,
|
|
3140
|
+
dim=point_count,
|
|
3141
|
+
inputs=[vertices, normals, faces_per_vertex],
|
|
3142
|
+
outputs=[gfx_vertices],
|
|
3143
|
+
record_tape=False,
|
|
3144
|
+
)
|
|
3145
|
+
gfx_vertices = gfx_vertices.numpy()
|
|
3146
|
+
gfx_indices = indices.flatten()
|
|
3147
|
+
else:
|
|
3148
|
+
gfx_vertices = wp.zeros((idx_count * 3, 8), dtype=float)
|
|
3149
|
+
wp.launch(
|
|
3150
|
+
compute_gfx_vertices,
|
|
3151
|
+
dim=idx_count,
|
|
3152
|
+
inputs=[wp.array(indices, dtype=int), wp.array(points, dtype=wp.vec3)],
|
|
3153
|
+
outputs=[gfx_vertices],
|
|
3154
|
+
record_tape=False,
|
|
3155
|
+
)
|
|
3156
|
+
gfx_vertices = gfx_vertices.numpy()
|
|
3157
|
+
gfx_indices = np.arange(idx_count * 3)
|
|
3078
3158
|
|
|
3079
3159
|
# If there was a shape for the given mesh, clean it up.
|
|
3080
3160
|
if shape is not None:
|
|
@@ -3090,7 +3170,7 @@ Instances: {len(self._instances)}"""
|
|
|
3090
3170
|
if not is_template:
|
|
3091
3171
|
# Create a new instance if necessary.
|
|
3092
3172
|
body = self._resolve_body_id(parent_body)
|
|
3093
|
-
self.add_shape_instance(name, shape, body, pos, rot, color1=colors)
|
|
3173
|
+
self.add_shape_instance(name, shape, body, pos, rot, color1=colors, scale=scale)
|
|
3094
3174
|
|
|
3095
3175
|
return shape
|
|
3096
3176
|
|
|
@@ -3278,7 +3358,7 @@ Instances: {len(self._instances)}"""
|
|
|
3278
3358
|
lines = np.array(lines)
|
|
3279
3359
|
self._render_lines(name, lines, color, radius)
|
|
3280
3360
|
|
|
3281
|
-
def update_shape_vertices(self, shape, points
|
|
3361
|
+
def update_shape_vertices(self, shape, points):
|
|
3282
3362
|
if isinstance(points, wp.array):
|
|
3283
3363
|
wp_points = points.to(self._device)
|
|
3284
3364
|
else:
|
|
@@ -3291,7 +3371,7 @@ Instances: {len(self._instances)}"""
|
|
|
3291
3371
|
wp.launch(
|
|
3292
3372
|
update_vbo_vertices,
|
|
3293
3373
|
dim=vertices_shape[0],
|
|
3294
|
-
inputs=[wp_points
|
|
3374
|
+
inputs=[wp_points],
|
|
3295
3375
|
outputs=[vbo_vertices],
|
|
3296
3376
|
device=self._device,
|
|
3297
3377
|
)
|
warp/render/render_usd.py
CHANGED
warp/sim/collide.py
CHANGED
|
@@ -1236,8 +1236,7 @@ def handle_contact_pairs(
|
|
|
1236
1236
|
p_b_body = closest_point_box(geo_scale_b, query_b)
|
|
1237
1237
|
p_b_world = wp.transform_point(X_ws_b, p_b_body)
|
|
1238
1238
|
diff = p_a_world - p_b_world
|
|
1239
|
-
|
|
1240
|
-
query_b = wp.transform_point(X_sw_b, wp.transform_get_translation(X_ws_a))
|
|
1239
|
+
|
|
1241
1240
|
normal = wp.transform_vector(X_ws_b, box_sdf_grad(geo_scale_b, query_b))
|
|
1242
1241
|
distance = wp.dot(diff, normal)
|
|
1243
1242
|
|
warp/sim/graph_coloring.py
CHANGED
|
@@ -234,7 +234,7 @@ def color_graph(
|
|
|
234
234
|
f"graph_edge_indices must be a 2 dimensional array! The provided one is {graph_edge_indices.ndim} dimensional."
|
|
235
235
|
)
|
|
236
236
|
|
|
237
|
-
num_colors = wp.context.runtime.core.
|
|
237
|
+
num_colors = wp.context.runtime.core.wp_graph_coloring(
|
|
238
238
|
num_nodes,
|
|
239
239
|
graph_edge_indices.__ctype__(),
|
|
240
240
|
algorithm.value,
|
|
@@ -242,7 +242,7 @@ def color_graph(
|
|
|
242
242
|
)
|
|
243
243
|
|
|
244
244
|
if balance_colors:
|
|
245
|
-
max_min_ratio = wp.context.runtime.core.
|
|
245
|
+
max_min_ratio = wp.context.runtime.core.wp_balance_coloring(
|
|
246
246
|
num_nodes,
|
|
247
247
|
graph_edge_indices.__ctype__(),
|
|
248
248
|
num_colors,
|