warp-lang 1.8.1__py3-none-macosx_10_13_universal2.whl → 1.9.1__py3-none-macosx_10_13_universal2.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 +1904 -114
- warp/bin/libwarp-clang.dylib +0 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +93 -30
- warp/build_dll.py +331 -101
- warp/builtins.py +1244 -160
- warp/codegen.py +317 -206
- warp/config.py +1 -1
- warp/context.py +1465 -789
- 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_kernel.py +2 -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 +264 -166
- warp/fem/geometry/geometry.py +5 -5
- warp/fem/integrate.py +129 -51
- warp/fem/space/restriction.py +4 -0
- warp/fem/space/shape/tet_shape_function.py +3 -10
- warp/jax_experimental/custom_call.py +25 -2
- warp/jax_experimental/ffi.py +22 -1
- warp/jax_experimental/xla_ffi.py +16 -7
- warp/marching_cubes.py +708 -0
- warp/native/array.h +99 -4
- warp/native/builtin.h +86 -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 +8 -2
- warp/native/crt.cpp +2 -2
- warp/native/crt.h +3 -5
- warp/native/cuda_util.cpp +41 -10
- 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 +2 -2
- warp/native/mat.h +1910 -116
- warp/native/mathdx.cpp +43 -43
- warp/native/mesh.cpp +24 -24
- warp/native/mesh.cu +26 -26
- warp/native/mesh.h +4 -2
- 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 +331 -14
- 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 +40 -31
- warp/native/sort.h +2 -0
- warp/native/sparse.cpp +8 -8
- warp/native/sparse.cu +13 -13
- warp/native/spatial.h +366 -17
- warp/native/temp_buffer.h +2 -2
- warp/native/tile.h +471 -82
- warp/native/vec.h +328 -14
- 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 +377 -216
- warp/native/warp.h +227 -226
- warp/optim/linear.py +736 -271
- warp/render/imgui_manager.py +289 -0
- warp/render/render_opengl.py +99 -18
- warp/render/render_usd.py +1 -0
- warp/sim/graph_coloring.py +2 -2
- warp/sparse.py +558 -175
- 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_hash_grid.py +38 -0
- warp/tests/geometry/test_marching_cubes.py +233 -12
- warp/tests/interop/test_jax.py +608 -28
- warp/tests/sim/test_coloring.py +6 -6
- warp/tests/test_array.py +58 -5
- warp/tests/test_codegen.py +4 -3
- 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 +49 -6
- 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 +15 -1
- warp/tests/test_mat.py +1518 -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 +140 -34
- warp/tests/test_quat_assign_copy.py +145 -0
- warp/tests/test_reload.py +2 -1
- warp/tests/test_sparse.py +71 -0
- warp/tests/test_spatial.py +140 -34
- warp/tests/test_spatial_assign_copy.py +160 -0
- warp/tests/test_struct.py +43 -3
- warp/tests/test_tuple.py +96 -0
- warp/tests/test_types.py +61 -20
- warp/tests/test_vec.py +179 -34
- warp/tests/test_vec_assign_copy.py +143 -0
- warp/tests/tile/test_tile.py +245 -18
- 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 +1 -1
- warp/tests/tile/test_tile_mlp.py +1 -1
- warp/tests/tile/test_tile_shared_memory.py +5 -5
- warp/tests/unittest_suites.py +6 -0
- warp/tests/walkthrough_debug.py +1 -1
- warp/thirdparty/unittest_parallel.py +108 -9
- warp/types.py +571 -267
- warp/utils.py +68 -86
- {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/METADATA +29 -69
- {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/RECORD +138 -128
- warp/native/marching.cpp +0 -19
- warp/native/marching.cu +0 -514
- warp/native/marching.h +0 -19
- {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/WHEEL +0 -0
- {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.dist-info}/licenses/LICENSE.md +0 -0
- {warp_lang-1.8.1.dist-info → warp_lang-1.9.1.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
|
@@ -390,9 +390,9 @@ def compute_gfx_vertices(
|
|
|
390
390
|
gfx_vertices: wp.array(dtype=float, ndim=2),
|
|
391
391
|
):
|
|
392
392
|
tid = wp.tid()
|
|
393
|
-
v0 = vertices[indices[tid, 0]]
|
|
394
|
-
v1 = vertices[indices[tid, 1]]
|
|
395
|
-
v2 = vertices[indices[tid, 2]]
|
|
393
|
+
v0 = wp.cw_mul(vertices[indices[tid, 0]], scale)
|
|
394
|
+
v1 = wp.cw_mul(vertices[indices[tid, 1]], scale)
|
|
395
|
+
v2 = wp.cw_mul(vertices[indices[tid, 2]], scale)
|
|
396
396
|
i = tid * 3
|
|
397
397
|
j = i + 1
|
|
398
398
|
k = i + 2
|
|
@@ -421,6 +421,7 @@ def compute_gfx_vertices(
|
|
|
421
421
|
def compute_average_normals(
|
|
422
422
|
indices: wp.array(dtype=int, ndim=2),
|
|
423
423
|
vertices: wp.array(dtype=wp.vec3),
|
|
424
|
+
scale: wp.vec3,
|
|
424
425
|
# outputs
|
|
425
426
|
normals: wp.array(dtype=wp.vec3),
|
|
426
427
|
faces_per_vertex: wp.array(dtype=int),
|
|
@@ -429,9 +430,9 @@ def compute_average_normals(
|
|
|
429
430
|
i = indices[tid, 0]
|
|
430
431
|
j = indices[tid, 1]
|
|
431
432
|
k = indices[tid, 2]
|
|
432
|
-
v0 = vertices[i]
|
|
433
|
-
v1 = vertices[j]
|
|
434
|
-
v2 = vertices[k]
|
|
433
|
+
v0 = wp.cw_mul(vertices[i], scale)
|
|
434
|
+
v1 = wp.cw_mul(vertices[j], scale)
|
|
435
|
+
v2 = wp.cw_mul(vertices[k], scale)
|
|
435
436
|
n = wp.normalize(wp.cross(v1 - v0, v2 - v0))
|
|
436
437
|
wp.atomic_add(normals, i, n)
|
|
437
438
|
wp.atomic_add(faces_per_vertex, i, 1)
|
|
@@ -446,15 +447,16 @@ def assemble_gfx_vertices(
|
|
|
446
447
|
vertices: wp.array(dtype=wp.vec3, ndim=1),
|
|
447
448
|
normals: wp.array(dtype=wp.vec3),
|
|
448
449
|
faces_per_vertex: wp.array(dtype=int),
|
|
450
|
+
scale: wp.vec3,
|
|
449
451
|
# outputs
|
|
450
452
|
gfx_vertices: wp.array(dtype=float, ndim=2),
|
|
451
453
|
):
|
|
452
454
|
tid = wp.tid()
|
|
453
455
|
v = vertices[tid]
|
|
454
456
|
n = normals[tid] / float(faces_per_vertex[tid])
|
|
455
|
-
gfx_vertices[tid, 0] = v[0]
|
|
456
|
-
gfx_vertices[tid, 1] = v[1]
|
|
457
|
-
gfx_vertices[tid, 2] = v[2]
|
|
457
|
+
gfx_vertices[tid, 0] = v[0] * scale[0]
|
|
458
|
+
gfx_vertices[tid, 1] = v[1] * scale[1]
|
|
459
|
+
gfx_vertices[tid, 2] = v[2] * scale[2]
|
|
458
460
|
gfx_vertices[tid, 3] = n[0]
|
|
459
461
|
gfx_vertices[tid, 4] = n[1]
|
|
460
462
|
gfx_vertices[tid, 5] = n[2]
|
|
@@ -998,6 +1000,7 @@ class OpenGLRenderer:
|
|
|
998
1000
|
enable_mouse_interaction=True,
|
|
999
1001
|
enable_keyboard_interaction=True,
|
|
1000
1002
|
device=None,
|
|
1003
|
+
use_legacy_opengl: bool | None = None,
|
|
1001
1004
|
):
|
|
1002
1005
|
"""
|
|
1003
1006
|
Args:
|
|
@@ -1028,6 +1031,7 @@ class OpenGLRenderer:
|
|
|
1028
1031
|
enable_mouse_interaction (bool): Whether to enable mouse interaction.
|
|
1029
1032
|
enable_keyboard_interaction (bool): Whether to enable keyboard interaction.
|
|
1030
1033
|
device (Devicelike): Where to store the internal data.
|
|
1034
|
+
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.
|
|
1031
1035
|
|
|
1032
1036
|
Note:
|
|
1033
1037
|
|
|
@@ -1073,6 +1077,11 @@ class OpenGLRenderer:
|
|
|
1073
1077
|
self.render_depth = render_depth
|
|
1074
1078
|
self.enable_backface_culling = enable_backface_culling
|
|
1075
1079
|
|
|
1080
|
+
if use_legacy_opengl is None:
|
|
1081
|
+
self.use_legacy_opengl = sys.platform == "darwin"
|
|
1082
|
+
else:
|
|
1083
|
+
self.use_legacy_opengl = use_legacy_opengl
|
|
1084
|
+
|
|
1076
1085
|
if device is None:
|
|
1077
1086
|
self._device = wp.get_preferred_device()
|
|
1078
1087
|
else:
|
|
@@ -1162,6 +1171,8 @@ class OpenGLRenderer:
|
|
|
1162
1171
|
self._wp_instance_bodies = None
|
|
1163
1172
|
self._update_shape_instances = False
|
|
1164
1173
|
self._add_shape_instances = False
|
|
1174
|
+
self.instance_matrix_size = 0
|
|
1175
|
+
self.instance_color_size = 0
|
|
1165
1176
|
|
|
1166
1177
|
# additional shape instancer used for points and line rendering
|
|
1167
1178
|
self._shape_instancers = {}
|
|
@@ -2051,9 +2062,43 @@ Instances: {len(self._instances)}"""
|
|
|
2051
2062
|
num_instances = len(self._shape_instances[shape])
|
|
2052
2063
|
|
|
2053
2064
|
gl.glBindVertexArray(vao)
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2065
|
+
if self.use_legacy_opengl:
|
|
2066
|
+
if self.instance_matrix_size > 0 and self.instance_color_size:
|
|
2067
|
+
# update attribute pointers
|
|
2068
|
+
matrix_size = self.instance_matrix_size
|
|
2069
|
+
color_size = self.instance_color_size
|
|
2070
|
+
|
|
2071
|
+
# update transforms
|
|
2072
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_transform_gl_buffer)
|
|
2073
|
+
for i in range(4):
|
|
2074
|
+
gl.glVertexAttribPointer(
|
|
2075
|
+
3 + i,
|
|
2076
|
+
4,
|
|
2077
|
+
gl.GL_FLOAT,
|
|
2078
|
+
gl.GL_FALSE,
|
|
2079
|
+
matrix_size,
|
|
2080
|
+
ctypes.c_void_p(start_instance_idx * matrix_size + i * matrix_size // 4),
|
|
2081
|
+
)
|
|
2082
|
+
gl.glVertexAttribDivisor(3 + i, 1)
|
|
2083
|
+
|
|
2084
|
+
# update colors
|
|
2085
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
|
|
2086
|
+
gl.glVertexAttribPointer(
|
|
2087
|
+
7, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2088
|
+
)
|
|
2089
|
+
gl.glVertexAttribDivisor(7, 1)
|
|
2090
|
+
|
|
2091
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
|
|
2092
|
+
gl.glVertexAttribPointer(
|
|
2093
|
+
8, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2094
|
+
)
|
|
2095
|
+
gl.glVertexAttribDivisor(8, 1)
|
|
2096
|
+
|
|
2097
|
+
gl.glDrawElementsInstanced(gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, num_instances)
|
|
2098
|
+
else:
|
|
2099
|
+
gl.glDrawElementsInstancedBaseInstance(
|
|
2100
|
+
gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, num_instances, start_instance_idx
|
|
2101
|
+
)
|
|
2057
2102
|
|
|
2058
2103
|
start_instance_idx += num_instances
|
|
2059
2104
|
|
|
@@ -2103,9 +2148,43 @@ Instances: {len(self._instances)}"""
|
|
|
2103
2148
|
start_instance_idx = self._inverse_instance_ids[instance]
|
|
2104
2149
|
|
|
2105
2150
|
gl.glBindVertexArray(vao)
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2151
|
+
if self.use_legacy_opengl:
|
|
2152
|
+
if self.instance_matrix_size > 0 and self.instance_color_size:
|
|
2153
|
+
# update attribute pointers
|
|
2154
|
+
matrix_size = self.instance_matrix_size
|
|
2155
|
+
color_size = self.instance_color_size
|
|
2156
|
+
|
|
2157
|
+
# update transforms
|
|
2158
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_transform_gl_buffer)
|
|
2159
|
+
for j in range(4):
|
|
2160
|
+
gl.glVertexAttribPointer(
|
|
2161
|
+
3 + j,
|
|
2162
|
+
4,
|
|
2163
|
+
gl.GL_FLOAT,
|
|
2164
|
+
gl.GL_FALSE,
|
|
2165
|
+
matrix_size,
|
|
2166
|
+
ctypes.c_void_p(start_instance_idx * matrix_size + j * matrix_size // 4),
|
|
2167
|
+
)
|
|
2168
|
+
gl.glVertexAttribDivisor(3 + j, 1)
|
|
2169
|
+
|
|
2170
|
+
# update colors
|
|
2171
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color1_buffer)
|
|
2172
|
+
gl.glVertexAttribPointer(
|
|
2173
|
+
7, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2174
|
+
)
|
|
2175
|
+
gl.glVertexAttribDivisor(7, 1)
|
|
2176
|
+
|
|
2177
|
+
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
|
|
2178
|
+
gl.glVertexAttribPointer(
|
|
2179
|
+
8, 3, gl.GL_FLOAT, gl.GL_FALSE, color_size, ctypes.c_void_p(start_instance_idx * color_size)
|
|
2180
|
+
)
|
|
2181
|
+
gl.glVertexAttribDivisor(8, 1)
|
|
2182
|
+
|
|
2183
|
+
gl.glDrawElementsInstanced(gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, 1)
|
|
2184
|
+
else:
|
|
2185
|
+
gl.glDrawElementsInstancedBaseInstance(
|
|
2186
|
+
gl.GL_TRIANGLES, tri_count, gl.GL_UNSIGNED_INT, None, 1, start_instance_idx
|
|
2187
|
+
)
|
|
2109
2188
|
|
|
2110
2189
|
if self.draw_axis:
|
|
2111
2190
|
self._axis_instancer.render()
|
|
@@ -2393,6 +2472,7 @@ Instances: {len(self._instances)}"""
|
|
|
2393
2472
|
|
|
2394
2473
|
# set up instance attribute pointers
|
|
2395
2474
|
matrix_size = transforms[0].nbytes
|
|
2475
|
+
self.instance_matrix_size = matrix_size
|
|
2396
2476
|
|
|
2397
2477
|
instance_ids = []
|
|
2398
2478
|
instance_custom_ids = []
|
|
@@ -2401,6 +2481,7 @@ Instances: {len(self._instances)}"""
|
|
|
2401
2481
|
inverse_instance_ids = {}
|
|
2402
2482
|
instance_count = 0
|
|
2403
2483
|
colors_size = np.zeros(3, dtype=np.float32).nbytes
|
|
2484
|
+
self.instance_color_size = colors_size
|
|
2404
2485
|
for shape, (vao, _vbo, _ebo, _tri_count, _vertex_cuda_buffer) in self._shape_gl_buffers.items():
|
|
2405
2486
|
gl.glBindVertexArray(vao)
|
|
2406
2487
|
|
|
@@ -3051,7 +3132,7 @@ Instances: {len(self._instances)}"""
|
|
|
3051
3132
|
wp.launch(
|
|
3052
3133
|
compute_average_normals,
|
|
3053
3134
|
dim=idx_count,
|
|
3054
|
-
inputs=[wp.array(indices, dtype=int), vertices],
|
|
3135
|
+
inputs=[wp.array(indices, dtype=int), vertices, scale],
|
|
3055
3136
|
outputs=[normals, faces_per_vertex],
|
|
3056
3137
|
record_tape=False,
|
|
3057
3138
|
)
|
|
@@ -3059,7 +3140,7 @@ Instances: {len(self._instances)}"""
|
|
|
3059
3140
|
wp.launch(
|
|
3060
3141
|
assemble_gfx_vertices,
|
|
3061
3142
|
dim=point_count,
|
|
3062
|
-
inputs=[vertices, normals, faces_per_vertex],
|
|
3143
|
+
inputs=[vertices, normals, faces_per_vertex, scale],
|
|
3063
3144
|
outputs=[gfx_vertices],
|
|
3064
3145
|
record_tape=False,
|
|
3065
3146
|
)
|
|
@@ -3070,7 +3151,7 @@ Instances: {len(self._instances)}"""
|
|
|
3070
3151
|
wp.launch(
|
|
3071
3152
|
compute_gfx_vertices,
|
|
3072
3153
|
dim=idx_count,
|
|
3073
|
-
inputs=[wp.array(indices, dtype=int), wp.array(points, dtype=wp.vec3)],
|
|
3154
|
+
inputs=[wp.array(indices, dtype=int), wp.array(points, dtype=wp.vec3), scale],
|
|
3074
3155
|
outputs=[gfx_vertices],
|
|
3075
3156
|
record_tape=False,
|
|
3076
3157
|
)
|
warp/render/render_usd.py
CHANGED
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,
|