warp-lang 0.9.0__py3-none-win_amd64.whl → 0.11.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (315) hide show
  1. warp/__init__.py +15 -7
  2. warp/__init__.pyi +1 -0
  3. warp/bin/warp-clang.dll +0 -0
  4. warp/bin/warp.dll +0 -0
  5. warp/build.py +22 -443
  6. warp/build_dll.py +384 -0
  7. warp/builtins.py +998 -488
  8. warp/codegen.py +1307 -739
  9. warp/config.py +5 -3
  10. warp/constants.py +6 -0
  11. warp/context.py +1291 -548
  12. warp/dlpack.py +31 -31
  13. warp/fabric.py +326 -0
  14. warp/fem/__init__.py +27 -0
  15. warp/fem/cache.py +389 -0
  16. warp/fem/dirichlet.py +181 -0
  17. warp/fem/domain.py +263 -0
  18. warp/fem/field/__init__.py +101 -0
  19. warp/fem/field/field.py +149 -0
  20. warp/fem/field/nodal_field.py +299 -0
  21. warp/fem/field/restriction.py +21 -0
  22. warp/fem/field/test.py +181 -0
  23. warp/fem/field/trial.py +183 -0
  24. warp/fem/geometry/__init__.py +19 -0
  25. warp/fem/geometry/closest_point.py +70 -0
  26. warp/fem/geometry/deformed_geometry.py +271 -0
  27. warp/fem/geometry/element.py +744 -0
  28. warp/fem/geometry/geometry.py +186 -0
  29. warp/fem/geometry/grid_2d.py +373 -0
  30. warp/fem/geometry/grid_3d.py +435 -0
  31. warp/fem/geometry/hexmesh.py +953 -0
  32. warp/fem/geometry/partition.py +376 -0
  33. warp/fem/geometry/quadmesh_2d.py +532 -0
  34. warp/fem/geometry/tetmesh.py +840 -0
  35. warp/fem/geometry/trimesh_2d.py +577 -0
  36. warp/fem/integrate.py +1616 -0
  37. warp/fem/operator.py +191 -0
  38. warp/fem/polynomial.py +213 -0
  39. warp/fem/quadrature/__init__.py +2 -0
  40. warp/fem/quadrature/pic_quadrature.py +245 -0
  41. warp/fem/quadrature/quadrature.py +294 -0
  42. warp/fem/space/__init__.py +292 -0
  43. warp/fem/space/basis_space.py +489 -0
  44. warp/fem/space/collocated_function_space.py +105 -0
  45. warp/fem/space/dof_mapper.py +236 -0
  46. warp/fem/space/function_space.py +145 -0
  47. warp/fem/space/grid_2d_function_space.py +267 -0
  48. warp/fem/space/grid_3d_function_space.py +306 -0
  49. warp/fem/space/hexmesh_function_space.py +352 -0
  50. warp/fem/space/partition.py +350 -0
  51. warp/fem/space/quadmesh_2d_function_space.py +369 -0
  52. warp/fem/space/restriction.py +160 -0
  53. warp/fem/space/shape/__init__.py +15 -0
  54. warp/fem/space/shape/cube_shape_function.py +738 -0
  55. warp/fem/space/shape/shape_function.py +103 -0
  56. warp/fem/space/shape/square_shape_function.py +611 -0
  57. warp/fem/space/shape/tet_shape_function.py +567 -0
  58. warp/fem/space/shape/triangle_shape_function.py +429 -0
  59. warp/fem/space/tetmesh_function_space.py +292 -0
  60. warp/fem/space/topology.py +295 -0
  61. warp/fem/space/trimesh_2d_function_space.py +221 -0
  62. warp/fem/types.py +77 -0
  63. warp/fem/utils.py +495 -0
  64. warp/native/array.h +164 -55
  65. warp/native/builtin.h +150 -174
  66. warp/native/bvh.cpp +75 -328
  67. warp/native/bvh.cu +406 -23
  68. warp/native/bvh.h +37 -45
  69. warp/native/clang/clang.cpp +136 -24
  70. warp/native/crt.cpp +1 -76
  71. warp/native/crt.h +111 -104
  72. warp/native/cuda_crt.h +1049 -0
  73. warp/native/cuda_util.cpp +15 -3
  74. warp/native/cuda_util.h +3 -1
  75. warp/native/cutlass/tools/library/scripts/conv2d_operation.py +463 -0
  76. warp/native/cutlass/tools/library/scripts/conv3d_operation.py +321 -0
  77. warp/native/cutlass/tools/library/scripts/gemm_operation.py +988 -0
  78. warp/native/cutlass/tools/library/scripts/generator.py +4625 -0
  79. warp/native/cutlass/tools/library/scripts/library.py +799 -0
  80. warp/native/cutlass/tools/library/scripts/manifest.py +402 -0
  81. warp/native/cutlass/tools/library/scripts/pycutlass/docs/source/conf.py +96 -0
  82. warp/native/cutlass/tools/library/scripts/pycutlass/profile/conv/conv2d_f16_sm80.py +106 -0
  83. warp/native/cutlass/tools/library/scripts/pycutlass/profile/gemm/gemm_f32_sm80.py +91 -0
  84. warp/native/cutlass/tools/library/scripts/pycutlass/setup.py +80 -0
  85. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/__init__.py +48 -0
  86. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/arguments.py +118 -0
  87. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/c_types.py +241 -0
  88. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/compiler.py +432 -0
  89. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/conv2d_operation.py +631 -0
  90. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/epilogue.py +1026 -0
  91. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/frontend.py +104 -0
  92. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/gemm_operation.py +1276 -0
  93. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/library.py +744 -0
  94. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/memory_manager.py +74 -0
  95. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/operation.py +110 -0
  96. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/parser.py +619 -0
  97. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/reduction_operation.py +398 -0
  98. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/tensor_ref.py +70 -0
  99. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/__init__.py +4 -0
  100. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/conv2d_testbed.py +646 -0
  101. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/gemm_grouped_testbed.py +235 -0
  102. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/gemm_testbed.py +557 -0
  103. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/test/profiler.py +70 -0
  104. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/type_hint.py +39 -0
  105. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/__init__.py +1 -0
  106. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/device.py +76 -0
  107. warp/native/cutlass/tools/library/scripts/pycutlass/src/pycutlass/utils/reference_model.py +255 -0
  108. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/__init__.py +0 -0
  109. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +201 -0
  110. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +177 -0
  111. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +98 -0
  112. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_dgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +95 -0
  113. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_few_channels_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.py +163 -0
  114. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_fixed_channels_f16nhwc_f16nhwc_f16nhwc_tensor_op_f32_sm80.py +187 -0
  115. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +309 -0
  116. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +54 -0
  117. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +96 -0
  118. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_fprop_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +107 -0
  119. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_strided_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +253 -0
  120. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.py +97 -0
  121. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.py +242 -0
  122. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_f32nhwc_f32nhwc_f32nhwc_simt_f32_sm80.py +96 -0
  123. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/conv2d_wgrad_implicit_gemm_tf32nhwc_tf32nhwc_f32nhwc_tensor_op_f32_sm80.py +107 -0
  124. warp/native/cutlass/tools/library/scripts/pycutlass/test/conv/run_all_tests.py +10 -0
  125. warp/native/cutlass/tools/library/scripts/pycutlass/test/frontend/test_frontend.py +146 -0
  126. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/__init__.py +0 -0
  127. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_bf16_sm80.py +96 -0
  128. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f16_sm80.py +447 -0
  129. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f32_sm80.py +146 -0
  130. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_f64_sm80.py +102 -0
  131. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_grouped_sm80.py +203 -0
  132. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/gemm_s8_sm80.py +229 -0
  133. warp/native/cutlass/tools/library/scripts/pycutlass/test/gemm/run_all_tests.py +9 -0
  134. warp/native/cutlass/tools/library/scripts/pycutlass/test/unit/test_sm80.py +453 -0
  135. warp/native/cutlass/tools/library/scripts/rank_2k_operation.py +398 -0
  136. warp/native/cutlass/tools/library/scripts/rank_k_operation.py +387 -0
  137. warp/native/cutlass/tools/library/scripts/rt.py +796 -0
  138. warp/native/cutlass/tools/library/scripts/symm_operation.py +400 -0
  139. warp/native/cutlass/tools/library/scripts/trmm_operation.py +407 -0
  140. warp/native/cutlass_gemm.cu +5 -3
  141. warp/native/exports.h +1240 -949
  142. warp/native/fabric.h +228 -0
  143. warp/native/hashgrid.cpp +4 -4
  144. warp/native/hashgrid.h +22 -2
  145. warp/native/initializer_array.h +2 -2
  146. warp/native/intersect.h +22 -7
  147. warp/native/intersect_adj.h +8 -8
  148. warp/native/intersect_tri.h +13 -16
  149. warp/native/marching.cu +157 -161
  150. warp/native/mat.h +119 -19
  151. warp/native/matnn.h +2 -2
  152. warp/native/mesh.cpp +108 -83
  153. warp/native/mesh.cu +243 -6
  154. warp/native/mesh.h +1547 -458
  155. warp/native/nanovdb/NanoVDB.h +1 -1
  156. warp/native/noise.h +272 -329
  157. warp/native/quat.h +51 -8
  158. warp/native/rand.h +45 -35
  159. warp/native/range.h +6 -2
  160. warp/native/reduce.cpp +157 -0
  161. warp/native/reduce.cu +348 -0
  162. warp/native/runlength_encode.cpp +62 -0
  163. warp/native/runlength_encode.cu +46 -0
  164. warp/native/scan.cu +11 -13
  165. warp/native/scan.h +1 -0
  166. warp/native/solid_angle.h +442 -0
  167. warp/native/sort.cpp +13 -0
  168. warp/native/sort.cu +9 -1
  169. warp/native/sparse.cpp +338 -0
  170. warp/native/sparse.cu +545 -0
  171. warp/native/spatial.h +2 -2
  172. warp/native/temp_buffer.h +30 -0
  173. warp/native/vec.h +126 -24
  174. warp/native/volume.h +120 -0
  175. warp/native/warp.cpp +658 -53
  176. warp/native/warp.cu +660 -68
  177. warp/native/warp.h +112 -12
  178. warp/optim/__init__.py +1 -0
  179. warp/optim/linear.py +922 -0
  180. warp/optim/sgd.py +92 -0
  181. warp/render/render_opengl.py +392 -152
  182. warp/render/render_usd.py +11 -11
  183. warp/sim/__init__.py +2 -2
  184. warp/sim/articulation.py +385 -185
  185. warp/sim/collide.py +21 -8
  186. warp/sim/import_mjcf.py +297 -106
  187. warp/sim/import_urdf.py +389 -210
  188. warp/sim/import_usd.py +198 -97
  189. warp/sim/inertia.py +17 -18
  190. warp/sim/integrator_euler.py +14 -8
  191. warp/sim/integrator_xpbd.py +161 -19
  192. warp/sim/model.py +795 -291
  193. warp/sim/optimizer.py +2 -6
  194. warp/sim/render.py +65 -3
  195. warp/sim/utils.py +3 -0
  196. warp/sparse.py +1227 -0
  197. warp/stubs.py +665 -223
  198. warp/tape.py +66 -15
  199. warp/tests/__main__.py +3 -6
  200. warp/tests/assets/curlnoise_golden.npy +0 -0
  201. warp/tests/assets/pnoise_golden.npy +0 -0
  202. warp/tests/assets/torus.usda +105 -105
  203. warp/tests/{test_class_kernel.py → aux_test_class_kernel.py} +9 -1
  204. warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -0
  205. warp/tests/{test_dependent.py → aux_test_dependent.py} +2 -2
  206. warp/tests/{test_reference.py → aux_test_reference.py} +1 -1
  207. warp/tests/aux_test_unresolved_func.py +14 -0
  208. warp/tests/aux_test_unresolved_symbol.py +14 -0
  209. warp/tests/disabled_kinematics.py +239 -0
  210. warp/tests/run_coverage_serial.py +31 -0
  211. warp/tests/test_adam.py +103 -106
  212. warp/tests/test_arithmetic.py +128 -74
  213. warp/tests/test_array.py +1497 -211
  214. warp/tests/test_array_reduce.py +150 -0
  215. warp/tests/test_atomic.py +64 -28
  216. warp/tests/test_bool.py +99 -0
  217. warp/tests/test_builtins_resolution.py +1292 -0
  218. warp/tests/test_bvh.py +75 -43
  219. warp/tests/test_closest_point_edge_edge.py +54 -57
  220. warp/tests/test_codegen.py +233 -128
  221. warp/tests/test_compile_consts.py +28 -20
  222. warp/tests/test_conditional.py +108 -24
  223. warp/tests/test_copy.py +10 -12
  224. warp/tests/test_ctypes.py +112 -88
  225. warp/tests/test_dense.py +21 -14
  226. warp/tests/test_devices.py +98 -0
  227. warp/tests/test_dlpack.py +136 -108
  228. warp/tests/test_examples.py +277 -0
  229. warp/tests/test_fabricarray.py +955 -0
  230. warp/tests/test_fast_math.py +15 -11
  231. warp/tests/test_fem.py +1271 -0
  232. warp/tests/test_fp16.py +53 -19
  233. warp/tests/test_func.py +187 -74
  234. warp/tests/test_generics.py +194 -49
  235. warp/tests/test_grad.py +180 -116
  236. warp/tests/test_grad_customs.py +176 -0
  237. warp/tests/test_hash_grid.py +52 -37
  238. warp/tests/test_import.py +10 -23
  239. warp/tests/test_indexedarray.py +577 -24
  240. warp/tests/test_intersect.py +18 -9
  241. warp/tests/test_large.py +141 -0
  242. warp/tests/test_launch.py +251 -15
  243. warp/tests/test_lerp.py +64 -65
  244. warp/tests/test_linear_solvers.py +154 -0
  245. warp/tests/test_lvalue.py +493 -0
  246. warp/tests/test_marching_cubes.py +12 -13
  247. warp/tests/test_mat.py +508 -2778
  248. warp/tests/test_mat_lite.py +115 -0
  249. warp/tests/test_mat_scalar_ops.py +2889 -0
  250. warp/tests/test_math.py +103 -9
  251. warp/tests/test_matmul.py +305 -69
  252. warp/tests/test_matmul_lite.py +410 -0
  253. warp/tests/test_mesh.py +71 -14
  254. warp/tests/test_mesh_query_aabb.py +41 -25
  255. warp/tests/test_mesh_query_point.py +325 -34
  256. warp/tests/test_mesh_query_ray.py +39 -22
  257. warp/tests/test_mlp.py +30 -22
  258. warp/tests/test_model.py +92 -89
  259. warp/tests/test_modules_lite.py +39 -0
  260. warp/tests/test_multigpu.py +88 -114
  261. warp/tests/test_noise.py +12 -11
  262. warp/tests/test_operators.py +16 -20
  263. warp/tests/test_options.py +11 -11
  264. warp/tests/test_pinned.py +17 -18
  265. warp/tests/test_print.py +32 -11
  266. warp/tests/test_quat.py +275 -129
  267. warp/tests/test_rand.py +18 -16
  268. warp/tests/test_reload.py +38 -34
  269. warp/tests/test_rounding.py +50 -43
  270. warp/tests/test_runlength_encode.py +190 -0
  271. warp/tests/test_smoothstep.py +9 -11
  272. warp/tests/test_snippet.py +143 -0
  273. warp/tests/test_sparse.py +460 -0
  274. warp/tests/test_spatial.py +276 -243
  275. warp/tests/test_streams.py +110 -85
  276. warp/tests/test_struct.py +331 -85
  277. warp/tests/test_tape.py +39 -21
  278. warp/tests/test_torch.py +118 -89
  279. warp/tests/test_transient_module.py +12 -13
  280. warp/tests/test_types.py +614 -0
  281. warp/tests/test_utils.py +494 -0
  282. warp/tests/test_vec.py +354 -1987
  283. warp/tests/test_vec_lite.py +73 -0
  284. warp/tests/test_vec_scalar_ops.py +2099 -0
  285. warp/tests/test_volume.py +457 -293
  286. warp/tests/test_volume_write.py +124 -134
  287. warp/tests/unittest_serial.py +35 -0
  288. warp/tests/unittest_suites.py +341 -0
  289. warp/tests/unittest_utils.py +568 -0
  290. warp/tests/unused_test_misc.py +71 -0
  291. warp/tests/{test_debug.py → walkthough_debug.py} +3 -17
  292. warp/thirdparty/appdirs.py +36 -45
  293. warp/thirdparty/unittest_parallel.py +549 -0
  294. warp/torch.py +72 -30
  295. warp/types.py +1744 -713
  296. warp/utils.py +360 -350
  297. warp_lang-0.11.0.dist-info/LICENSE.md +36 -0
  298. warp_lang-0.11.0.dist-info/METADATA +238 -0
  299. warp_lang-0.11.0.dist-info/RECORD +332 -0
  300. {warp_lang-0.9.0.dist-info → warp_lang-0.11.0.dist-info}/WHEEL +1 -1
  301. warp/bin/warp-clang.exp +0 -0
  302. warp/bin/warp-clang.lib +0 -0
  303. warp/bin/warp.exp +0 -0
  304. warp/bin/warp.lib +0 -0
  305. warp/tests/test_all.py +0 -215
  306. warp/tests/test_array_scan.py +0 -60
  307. warp/tests/test_base.py +0 -208
  308. warp/tests/test_unresolved_func.py +0 -7
  309. warp/tests/test_unresolved_symbol.py +0 -7
  310. warp_lang-0.9.0.dist-info/METADATA +0 -20
  311. warp_lang-0.9.0.dist-info/RECORD +0 -177
  312. /warp/tests/{test_compile_consts_dummy.py → aux_test_compile_consts_dummy.py} +0 -0
  313. /warp/tests/{test_reference_reference.py → aux_test_reference_reference.py} +0 -0
  314. /warp/tests/{test_square.py → aux_test_square.py} +0 -0
  315. {warp_lang-0.9.0.dist-info → warp_lang-0.11.0.dist-info}/top_level.txt +0 -0
@@ -13,12 +13,14 @@ from .utils import tab10_color_map
13
13
 
14
14
  from collections import defaultdict
15
15
  from typing import List, Tuple, Union, Optional
16
+ from enum import Enum
16
17
 
17
18
  import numpy as np
18
19
  import ctypes
19
20
 
20
21
  Mat44 = Union[List[float], List[List[float]], np.ndarray]
21
22
 
23
+
22
24
  wp.set_module_options({"enable_backward": False})
23
25
 
24
26
  shape_vertex_shader = """
@@ -175,12 +177,13 @@ in vec2 TexCoord;
175
177
 
176
178
  uniform vec3 color1;
177
179
  uniform vec3 color2;
180
+ uniform float farPlane;
178
181
 
179
182
  uniform vec3 sunDirection;
180
183
 
181
184
  void main()
182
185
  {
183
- float y = tanh(FragPos.y*0.01)*0.5+0.5;
186
+ float y = tanh(FragPos.y/farPlane*10.0)*0.5+0.5;
184
187
  float height = sqrt(1.0-y);
185
188
 
186
189
  float s = pow(0.5, 1.0 / 10.0);
@@ -222,6 +225,42 @@ void main() {
222
225
  }
223
226
  """
224
227
 
228
+ frame_depth_fragment_shader = """
229
+ #version 330 core
230
+ in vec2 TexCoord;
231
+
232
+ out vec4 FragColor;
233
+
234
+ uniform sampler2D textureSampler;
235
+
236
+ vec3 bourkeColorMap(float v) {
237
+ vec3 c = vec3(1.0, 1.0, 1.0);
238
+
239
+ v = clamp(v, 0.0, 1.0); // Ensures v is between 0 and 1
240
+
241
+ if (v < 0.25) {
242
+ c.r = 0.0;
243
+ c.g = 4.0 * v;
244
+ } else if (v < 0.5) {
245
+ c.r = 0.0;
246
+ c.b = 1.0 + 4.0 * (0.25 - v);
247
+ } else if (v < 0.75) {
248
+ c.r = 4.0 * (v - 0.5);
249
+ c.b = 0.0;
250
+ } else {
251
+ c.g = 1.0 + 4.0 * (0.75 - v);
252
+ c.b = 0.0;
253
+ }
254
+
255
+ return c;
256
+ }
257
+
258
+ void main() {
259
+ float depth = texture(textureSampler, TexCoord).r;
260
+ FragColor = vec4(bourkeColorMap(sqrt(1.0 - depth)), 1.0);
261
+ }
262
+ """
263
+
225
264
 
226
265
  @wp.kernel
227
266
  def update_vbo_transforms(
@@ -411,7 +450,7 @@ def assemble_gfx_vertices(
411
450
 
412
451
 
413
452
  @wp.kernel
414
- def copy_frame(
453
+ def copy_rgb_frame(
415
454
  input_img: wp.array(dtype=wp.uint8),
416
455
  width: int,
417
456
  height: int,
@@ -432,7 +471,26 @@ def copy_frame(
432
471
 
433
472
 
434
473
  @wp.kernel
435
- def copy_frame_tiles(
474
+ def copy_depth_frame(
475
+ input_img: wp.array(dtype=wp.float32),
476
+ width: int,
477
+ height: int,
478
+ near: float,
479
+ far: float,
480
+ # outputs
481
+ output_img: wp.array(dtype=wp.float32, ndim=3),
482
+ ):
483
+ w, v = wp.tid()
484
+ pixel = v * width + w
485
+ # flip vertically (OpenGL coordinates start at bottom)
486
+ v = height - v - 1
487
+ d = 2.0 * input_img[pixel] - 1.0
488
+ d = 2.0 * near * far / ((far - near) * d - near - far)
489
+ output_img[v, w, 0] = -d
490
+
491
+
492
+ @wp.kernel
493
+ def copy_rgb_frame_tiles(
436
494
  input_img: wp.array(dtype=wp.uint8),
437
495
  positions: wp.array(dtype=int, ndim=2),
438
496
  screen_width: int,
@@ -463,7 +521,34 @@ def copy_frame_tiles(
463
521
 
464
522
 
465
523
  @wp.kernel
466
- def copy_frame_tile(
524
+ def copy_depth_frame_tiles(
525
+ input_img: wp.array(dtype=wp.float32),
526
+ positions: wp.array(dtype=int, ndim=2),
527
+ screen_width: int,
528
+ screen_height: int,
529
+ tile_height: int,
530
+ near: float,
531
+ far: float,
532
+ # outputs
533
+ output_img: wp.array(dtype=wp.float32, ndim=4),
534
+ ):
535
+ tile, x, y = wp.tid()
536
+ p = positions[tile]
537
+ qx = x + p[0]
538
+ qy = y + p[1]
539
+ pixel = qy * screen_width + qx
540
+ # flip vertically (OpenGL coordinates start at bottom)
541
+ y = tile_height - y - 1
542
+ if qx >= screen_width or qy >= screen_height:
543
+ output_img[tile, y, x, 0] = far
544
+ return # prevent out-of-bounds access
545
+ d = 2.0 * input_img[pixel] - 1.0
546
+ d = 2.0 * near * far / ((far - near) * d - near - far)
547
+ output_img[tile, y, x, 0] = -d
548
+
549
+
550
+ @wp.kernel
551
+ def copy_rgb_frame_tile(
467
552
  input_img: wp.array(dtype=wp.uint8),
468
553
  offset_x: int,
469
554
  offset_y: int,
@@ -765,27 +850,35 @@ class OpenGLRenderer:
765
850
  title="Warp sim",
766
851
  scaling=1.0,
767
852
  fps=60,
768
- up_axis="y",
853
+ up_axis="Y",
769
854
  screen_width=1024,
770
855
  screen_height=768,
771
- near_plane=0.01,
772
- far_plane=1000.0,
856
+ near_plane=1.0,
857
+ far_plane=100.0,
773
858
  camera_fov=45.0,
859
+ camera_pos=(0.0, 2.0, 10.0),
860
+ camera_front=(0.0, 0.0, -1.0),
861
+ camera_up=(0.0, 1.0, 0.0),
774
862
  background_color=(0.53, 0.8, 0.92),
775
863
  draw_grid=True,
776
864
  draw_sky=True,
777
865
  draw_axis=True,
778
866
  show_info=True,
867
+ render_wireframe=False,
868
+ render_depth=False,
779
869
  axis_scale=1.0,
780
- vsync=True,
870
+ vsync=False,
781
871
  headless=False,
872
+ enable_backface_culling=True,
873
+ enable_mouse_interaction=True,
874
+ enable_keyboard_interaction=True,
782
875
  ):
783
876
  try:
784
877
  import pyglet
785
-
878
+
786
879
  # disable error checking for performance
787
- pyglet.options['debug_gl'] = False
788
-
880
+ pyglet.options["debug_gl"] = False
881
+
789
882
  from pyglet import gl
790
883
  from pyglet.math import Vec3 as PyVec3
791
884
  from pyglet.graphics.shader import Shader, ShaderProgram
@@ -801,6 +894,9 @@ class OpenGLRenderer:
801
894
  self.draw_sky = draw_sky
802
895
  self.draw_axis = draw_axis
803
896
  self.show_info = show_info
897
+ self.render_wireframe = render_wireframe
898
+ self.render_depth = render_depth
899
+ self.enable_backface_culling = enable_backface_culling
804
900
 
805
901
  self._device = wp.get_cuda_device()
806
902
  self._title = title
@@ -815,19 +911,26 @@ class OpenGLRenderer:
815
911
 
816
912
  self.screen_width, self.screen_height = self.window.get_framebuffer_size()
817
913
 
818
- self._camera_pos = PyVec3(0.0, 2.0, 10.0)
819
- self._camera_front = PyVec3(0.0, 0.0, -1.0)
820
- self._camera_up = PyVec3(0.0, 1.0, 0.0)
914
+ self.enable_mouse_interaction = enable_mouse_interaction
915
+ self.enable_keyboard_interaction = enable_keyboard_interaction
916
+
917
+ self._camera_pos = PyVec3(*camera_pos)
918
+ self._camera_front = PyVec3(*camera_front)
919
+ self._camera_up = PyVec3(*camera_up)
821
920
  self._camera_speed = 0.04
822
921
  if isinstance(up_axis, int):
823
922
  self._camera_axis = up_axis
824
923
  else:
825
- self._camera_axis = "xyz".index(up_axis.lower())
924
+ self._camera_axis = "XYZ".index(up_axis.upper())
826
925
  self._yaw, self._pitch = -90.0, 0.0
827
926
  self._last_x, self._last_y = self.screen_width // 2, self.screen_height // 2
828
927
  self._first_mouse = True
829
928
  self._left_mouse_pressed = False
830
929
  self._keys_pressed = defaultdict(bool)
930
+ self._key_callbacks = []
931
+
932
+ self.render_2d_callbacks = []
933
+ self.render_3d_callbacks = []
831
934
 
832
935
  self.update_view_matrix()
833
936
  self.update_projection_matrix()
@@ -850,6 +953,7 @@ class OpenGLRenderer:
850
953
  self._shape_gl_buffers = {}
851
954
  self._shape_instances = defaultdict(list)
852
955
  self._instances = {}
956
+ self._instance_custom_ids = {}
853
957
  self._instance_shape = {}
854
958
  self._instance_gl_buffers = {}
855
959
  self._instance_transform_gl_buffer = None
@@ -858,6 +962,8 @@ class OpenGLRenderer:
858
962
  self._instance_color2_buffer = None
859
963
  self._instance_count = 0
860
964
  self._wp_instance_ids = None
965
+ self._wp_instance_custom_ids = None
966
+ self._np_instance_visible = None
861
967
  self._instance_ids = None
862
968
  self._inverse_instance_ids = None
863
969
  self._wp_instance_transforms = None
@@ -884,6 +990,7 @@ class OpenGLRenderer:
884
990
  self._tile_projection_matrices = None
885
991
 
886
992
  self._frame_texture = None
993
+ self._frame_depth_texture = None
887
994
  self._frame_fbo = None
888
995
  self._frame_pbo = None
889
996
 
@@ -899,6 +1006,8 @@ class OpenGLRenderer:
899
1006
 
900
1007
  gl.glClearColor(*self.background_color, 1)
901
1008
  gl.glEnable(gl.GL_DEPTH_TEST)
1009
+ gl.glDepthMask(True)
1010
+ gl.glDepthRange(0.0, 1.0)
902
1011
 
903
1012
  self._shape_shader = ShaderProgram(
904
1013
  Shader(shape_vertex_shader, "vertex"), Shader(shape_fragment_shader, "fragment")
@@ -965,20 +1074,22 @@ class OpenGLRenderer:
965
1074
 
966
1075
  self._loc_sky_color1 = gl.glGetUniformLocation(self._sky_shader.id, str_buffer("color1"))
967
1076
  self._loc_sky_color2 = gl.glGetUniformLocation(self._sky_shader.id, str_buffer("color2"))
1077
+ self._loc_sky_far_plane = gl.glGetUniformLocation(self._sky_shader.id, str_buffer("farPlane"))
968
1078
  gl.glUniform3f(self._loc_sky_color1, *background_color)
969
1079
  # glUniform3f(self._loc_sky_color2, *np.clip(np.array(background_color)+0.5, 0.0, 1.0))
970
1080
  gl.glUniform3f(self._loc_sky_color2, 0.8, 0.4, 0.05)
1081
+ gl.glUniform1f(self._loc_sky_far_plane, self.camera_far_plane)
971
1082
  self._loc_sky_view_pos = gl.glGetUniformLocation(self._sky_shader.id, str_buffer("viewPos"))
972
1083
  gl.glUniform3f(
973
1084
  gl.glGetUniformLocation(self._sky_shader.id, str_buffer("sunDirection")), *self._sun_direction
974
1085
  )
975
1086
 
976
- # Create VAO, VBO, and EBO
1087
+ # create VAO, VBO, and EBO
977
1088
  self._sky_vao = gl.GLuint()
978
1089
  gl.glGenVertexArrays(1, self._sky_vao)
979
1090
  gl.glBindVertexArray(self._sky_vao)
980
1091
 
981
- vertices, indices = self._create_sphere_mesh(self.camera_far_plane * 0.9, 32, 32)
1092
+ vertices, indices = self._create_sphere_mesh(self.camera_far_plane * 0.9, 32, 32, reverse_winding=True)
982
1093
  self._sky_tri_count = len(indices)
983
1094
 
984
1095
  self._sky_vbo = gl.GLuint()
@@ -991,7 +1102,7 @@ class OpenGLRenderer:
991
1102
  gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self._sky_ebo)
992
1103
  gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices.ctypes.data, gl.GL_STATIC_DRAW)
993
1104
 
994
- # Set up vertex attributes
1105
+ # set up vertex attributes
995
1106
  vertex_stride = vertices.shape[1] * vertices.itemsize
996
1107
  # positions
997
1108
  gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, vertex_stride, ctypes.c_void_p(0))
@@ -1025,6 +1136,7 @@ class OpenGLRenderer:
1025
1136
 
1026
1137
  # create frame buffer for rendering to a texture
1027
1138
  self._frame_texture = None
1139
+ self._frame_depth_texture = None
1028
1140
  self._frame_fbo = None
1029
1141
  self._setup_framebuffer()
1030
1142
 
@@ -1072,7 +1184,15 @@ class OpenGLRenderer:
1072
1184
  gl.glUseProgram(self._frame_shader.id)
1073
1185
  self._frame_loc_texture = gl.glGetUniformLocation(self._frame_shader.id, str_buffer("textureSampler"))
1074
1186
 
1075
- # Unbind the VBO and VAO
1187
+ self._frame_depth_shader = ShaderProgram(
1188
+ Shader(frame_vertex_shader, "vertex"), Shader(frame_depth_fragment_shader, "fragment")
1189
+ )
1190
+ gl.glUseProgram(self._frame_depth_shader.id)
1191
+ self._frame_loc_depth_texture = gl.glGetUniformLocation(
1192
+ self._frame_depth_shader.id, str_buffer("textureSampler")
1193
+ )
1194
+
1195
+ # unbind the VBO and VAO
1076
1196
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
1077
1197
  gl.glBindVertexArray(0)
1078
1198
 
@@ -1160,11 +1280,17 @@ class OpenGLRenderer:
1160
1280
  self._instance_color1_buffer = None
1161
1281
  self._instance_color2_buffer = None
1162
1282
  self._wp_instance_ids = None
1283
+ self._wp_instance_custom_ids = None
1163
1284
  self._wp_instance_transforms = None
1164
1285
  self._wp_instance_scalings = None
1165
1286
  self._wp_instance_bodies = None
1287
+ self._np_instance_visible = None
1166
1288
  self._update_shape_instances = False
1167
1289
 
1290
+ def close(self):
1291
+ self.clear()
1292
+ self.window.close()
1293
+
1168
1294
  @property
1169
1295
  def tiled_rendering(self):
1170
1296
  return self._tiled_rendering
@@ -1318,7 +1444,11 @@ class OpenGLRenderer:
1318
1444
  if self._frame_texture is None:
1319
1445
  self._frame_texture = gl.GLuint()
1320
1446
  gl.glGenTextures(1, self._frame_texture)
1447
+ if self._frame_depth_texture is None:
1448
+ self._frame_depth_texture = gl.GLuint()
1449
+ gl.glGenTextures(1, self._frame_depth_texture)
1321
1450
 
1451
+ # set up RGB texture
1322
1452
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
1323
1453
  gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0)
1324
1454
  gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
@@ -1335,6 +1465,22 @@ class OpenGLRenderer:
1335
1465
  )
1336
1466
  gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
1337
1467
  gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
1468
+
1469
+ # set up depth texture
1470
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_depth_texture)
1471
+ gl.glTexImage2D(
1472
+ gl.GL_TEXTURE_2D,
1473
+ 0,
1474
+ gl.GL_DEPTH_COMPONENT32,
1475
+ self.screen_width,
1476
+ self.screen_height,
1477
+ 0,
1478
+ gl.GL_DEPTH_COMPONENT,
1479
+ gl.GL_FLOAT,
1480
+ None,
1481
+ )
1482
+ gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR)
1483
+ gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR)
1338
1484
  gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
1339
1485
 
1340
1486
  # create a framebuffer object (FBO)
@@ -1347,15 +1493,9 @@ class OpenGLRenderer:
1347
1493
  gl.glFramebufferTexture2D(
1348
1494
  gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self._frame_texture, 0
1349
1495
  )
1350
-
1351
- self._frame_depth_renderbuffer = gl.GLuint()
1352
- gl.glGenRenderbuffers(1, self._frame_depth_renderbuffer)
1353
- gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, self._frame_depth_renderbuffer)
1354
- gl.glRenderbufferStorage(gl.GL_RENDERBUFFER, gl.GL_DEPTH_COMPONENT, self.screen_width, self.screen_height)
1355
-
1356
- # attach the depth renderbuffer to the FBO
1357
- gl.glFramebufferRenderbuffer(
1358
- gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_RENDERBUFFER, self._frame_depth_renderbuffer
1496
+ # attach the depth texture to the FBO as its depth attachment
1497
+ gl.glFramebufferTexture2D(
1498
+ gl.GL_FRAMEBUFFER, gl.GL_DEPTH_ATTACHMENT, gl.GL_TEXTURE_2D, self._frame_depth_texture, 0
1359
1499
  )
1360
1500
 
1361
1501
  if gl.glCheckFramebufferStatus(gl.GL_FRAMEBUFFER) != gl.GL_FRAMEBUFFER_COMPLETE:
@@ -1363,13 +1503,6 @@ class OpenGLRenderer:
1363
1503
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
1364
1504
  sys.exit(1)
1365
1505
 
1366
- gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, 0)
1367
- else:
1368
- # rescale framebuffer
1369
- gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, self._frame_depth_renderbuffer)
1370
- gl.glRenderbufferStorage(gl.GL_RENDERBUFFER, gl.GL_DEPTH_COMPONENT, self.screen_width, self.screen_height)
1371
- gl.glBindRenderbuffer(gl.GL_RENDERBUFFER, 0)
1372
-
1373
1506
  # unbind the FBO (switch back to the default framebuffer)
1374
1507
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
1375
1508
 
@@ -1379,7 +1512,11 @@ class OpenGLRenderer:
1379
1512
  gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, self._frame_pbo) # binding to this buffer
1380
1513
 
1381
1514
  # allocate memory for PBO
1382
- pixels = np.zeros((self.screen_height, self.screen_width, 3), dtype=np.uint8)
1515
+ rgb_bytes_per_pixel = 3
1516
+ depth_bytes_per_pixel = 4
1517
+ pixels = np.zeros(
1518
+ (self.screen_height, self.screen_width, rgb_bytes_per_pixel + depth_bytes_per_pixel), dtype=np.uint8
1519
+ )
1383
1520
  gl.glBufferData(gl.GL_PIXEL_PACK_BUFFER, pixels.nbytes, pixels.ctypes.data, gl.GL_DYNAMIC_DRAW)
1384
1521
  gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)
1385
1522
 
@@ -1431,7 +1568,7 @@ class OpenGLRenderer:
1431
1568
  ))
1432
1569
  elif self._camera_axis == 2:
1433
1570
  self._model_matrix = np.array((
1434
- self._scaling, 0, 0, 0,
1571
+ -self._scaling, 0, 0, 0,
1435
1572
  0, 0, self._scaling, 0,
1436
1573
  0, self._scaling, 0, 0,
1437
1574
  0, 0, 0, 1
@@ -1502,28 +1639,28 @@ class OpenGLRenderer:
1502
1639
  self._last_time = self.clock_time
1503
1640
  self._frame_speed = update_duration * 100.0
1504
1641
 
1505
- self.app.event_loop.idle()
1506
- self.app.platform_event_loop.step(self._frame_dt)
1642
+ # self.app.event_loop.idle()
1643
+ self.app.platform_event_loop.step(self._frame_dt * 1e-3)
1507
1644
 
1508
- self._skip_frame_counter += 1
1509
- if self._skip_frame_counter > 100:
1510
- self._skip_frame_counter = 0
1645
+ if not self.skip_rendering:
1646
+ self._skip_frame_counter += 1
1647
+ if self._skip_frame_counter > 100:
1648
+ self._skip_frame_counter = 0
1511
1649
 
1512
- if frame_duration > 0.0:
1513
- if self._fps_update is None:
1514
- self._fps_update = 1.0 / frame_duration
1515
- else:
1516
- update = 1.0 / frame_duration
1517
- self._fps_update = (1.0 - self._fps_alpha) * self._fps_update + self._fps_alpha * update
1518
- if update_duration > 0.0:
1519
- if self._fps_render is None:
1520
- self._fps_render = 1.0 / update_duration
1521
- else:
1522
- update = 1.0 / update_duration
1523
- self._fps_render = (1.0 - self._fps_alpha) * self._fps_render + self._fps_alpha * update
1650
+ if frame_duration > 0.0:
1651
+ if self._fps_update is None:
1652
+ self._fps_update = 1.0 / frame_duration
1653
+ else:
1654
+ update = 1.0 / frame_duration
1655
+ self._fps_update = (1.0 - self._fps_alpha) * self._fps_update + self._fps_alpha * update
1656
+ if update_duration > 0.0:
1657
+ if self._fps_render is None:
1658
+ self._fps_render = 1.0 / update_duration
1659
+ else:
1660
+ update = 1.0 / update_duration
1661
+ self._fps_render = (1.0 - self._fps_alpha) * self._fps_render + self._fps_alpha * update
1524
1662
 
1525
- if not self.skip_rendering:
1526
- self.app.event_loop._redraw_windows(self._frame_dt)
1663
+ self.app.event_loop._redraw_windows(self._frame_dt * 1e-3)
1527
1664
 
1528
1665
  def _draw(self):
1529
1666
  from pyglet import gl
@@ -1531,9 +1668,13 @@ class OpenGLRenderer:
1531
1668
  # catch key hold events
1532
1669
  self._process_inputs()
1533
1670
 
1671
+ if self.enable_backface_culling:
1672
+ gl.glEnable(gl.GL_CULL_FACE)
1673
+ else:
1674
+ gl.glDisable(gl.GL_CULL_FACE)
1675
+
1534
1676
  if self._frame_fbo is not None:
1535
1677
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self._frame_fbo)
1536
- gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, self._frame_fbo)
1537
1678
 
1538
1679
  gl.glClearColor(*self.background_color, 1)
1539
1680
  gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
@@ -1554,11 +1695,19 @@ class OpenGLRenderer:
1554
1695
  gl.glUniformMatrix4fv(self._loc_shape_view, 1, gl.GL_FALSE, view_mat_ptr)
1555
1696
  gl.glUniformMatrix4fv(self._loc_shape_projection, 1, gl.GL_FALSE, projection_mat_ptr)
1556
1697
 
1698
+ if self.render_wireframe:
1699
+ gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
1700
+
1557
1701
  if self._tiled_rendering:
1558
1702
  self._render_scene_tiled()
1559
1703
  else:
1560
1704
  self._render_scene()
1561
1705
 
1706
+ for cb in self.render_3d_callbacks:
1707
+ cb()
1708
+
1709
+ gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
1710
+
1562
1711
  gl.glBindBuffer(gl.GL_PIXEL_UNPACK_BUFFER, 0)
1563
1712
  gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0)
1564
1713
  gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
@@ -1566,15 +1715,26 @@ class OpenGLRenderer:
1566
1715
 
1567
1716
  # render frame buffer texture to screen
1568
1717
  if self._frame_fbo is not None:
1569
- with self._frame_shader:
1570
- gl.glActiveTexture(gl.GL_TEXTURE0)
1571
- gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
1572
- gl.glUniform1i(self._frame_loc_texture, 0)
1718
+ if self.render_depth:
1719
+ with self._frame_depth_shader:
1720
+ gl.glActiveTexture(gl.GL_TEXTURE0)
1721
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_depth_texture)
1722
+ gl.glUniform1i(self._frame_loc_depth_texture, 0)
1723
+
1724
+ gl.glBindVertexArray(self._frame_vao)
1725
+ gl.glDrawElements(gl.GL_TRIANGLES, len(self._frame_indices), gl.GL_UNSIGNED_INT, None)
1726
+ gl.glBindVertexArray(0)
1727
+ gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
1728
+ else:
1729
+ with self._frame_shader:
1730
+ gl.glActiveTexture(gl.GL_TEXTURE0)
1731
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
1732
+ gl.glUniform1i(self._frame_loc_texture, 0)
1573
1733
 
1574
- gl.glBindVertexArray(self._frame_vao)
1575
- gl.glDrawElements(gl.GL_TRIANGLES, len(self._frame_indices), gl.GL_UNSIGNED_INT, None)
1576
- gl.glBindVertexArray(0)
1577
- gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
1734
+ gl.glBindVertexArray(self._frame_vao)
1735
+ gl.glDrawElements(gl.GL_TRIANGLES, len(self._frame_indices), gl.GL_UNSIGNED_INT, None)
1736
+ gl.glBindVertexArray(0)
1737
+ gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
1578
1738
 
1579
1739
  # check for OpenGL errors
1580
1740
  # check_gl_error()
@@ -1597,6 +1757,9 @@ Instances: {len(self._instances)}"""
1597
1757
  self._info_label.y = self.screen_height - 5
1598
1758
  self._info_label.draw()
1599
1759
 
1760
+ for cb in self.render_2d_callbacks:
1761
+ cb()
1762
+
1600
1763
  def _draw_grid(self, is_tiled=False):
1601
1764
  from pyglet import gl
1602
1765
 
@@ -1694,6 +1857,9 @@ Instances: {len(self._instances)}"""
1694
1857
  gl.glBindVertexArray(0)
1695
1858
 
1696
1859
  def _mouse_drag_callback(self, x, y, dx, dy, buttons, modifiers):
1860
+ if not self.enable_mouse_interaction:
1861
+ return
1862
+
1697
1863
  import pyglet
1698
1864
 
1699
1865
  if buttons & pyglet.window.mouse.LEFT:
@@ -1713,6 +1879,9 @@ Instances: {len(self._instances)}"""
1713
1879
  self.update_view_matrix()
1714
1880
 
1715
1881
  def _scroll_callback(self, x, y, scroll_x, scroll_y):
1882
+ if not self.enable_mouse_interaction:
1883
+ return
1884
+
1716
1885
  self.camera_fov -= scroll_y
1717
1886
  self.camera_fov = max(min(self.camera_fov, 90.0), 15.0)
1718
1887
  self.update_projection_matrix()
@@ -1739,8 +1908,11 @@ Instances: {len(self._instances)}"""
1739
1908
  def _key_press_callback(self, symbol, modifiers):
1740
1909
  import pyglet
1741
1910
 
1911
+ if not self.enable_keyboard_interaction:
1912
+ return
1913
+
1742
1914
  if symbol == pyglet.window.key.ESCAPE:
1743
- self.window.close()
1915
+ self.close()
1744
1916
  if symbol == pyglet.window.key.SPACE:
1745
1917
  self.paused = not self.paused
1746
1918
  if symbol == pyglet.window.key.TAB:
@@ -1751,6 +1923,18 @@ Instances: {len(self._instances)}"""
1751
1923
  self.draw_grid = not self.draw_grid
1752
1924
  if symbol == pyglet.window.key.I:
1753
1925
  self.show_info = not self.show_info
1926
+ if symbol == pyglet.window.key.X:
1927
+ self.render_wireframe = not self.render_wireframe
1928
+ if symbol == pyglet.window.key.T:
1929
+ self.render_depth = not self.render_depth
1930
+ if symbol == pyglet.window.key.B:
1931
+ self.enable_backface_culling = not self.enable_backface_culling
1932
+
1933
+ for cb in self._key_callbacks:
1934
+ cb(symbol, modifiers)
1935
+
1936
+ def register_key_press_callback(self, callback):
1937
+ self._key_callbacks.append(callback)
1754
1938
 
1755
1939
  def _window_resize_callback(self, width, height):
1756
1940
  self._first_mouse = True
@@ -1808,7 +1992,17 @@ Instances: {len(self._instances)}"""
1808
1992
  return shape
1809
1993
 
1810
1994
  def add_shape_instance(
1811
- self, name: str, shape: int, body, pos, rot, scale=(1.0, 1.0, 1.0), color1=None, color2=None
1995
+ self,
1996
+ name: str,
1997
+ shape: int,
1998
+ body,
1999
+ pos,
2000
+ rot,
2001
+ scale=(1.0, 1.0, 1.0),
2002
+ color1=None,
2003
+ color2=None,
2004
+ custom_index: int = -1,
2005
+ visible: bool = True,
1812
2006
  ):
1813
2007
  if color1 is None:
1814
2008
  color1 = self._shapes[shape][2]
@@ -1817,8 +2011,9 @@ Instances: {len(self._instances)}"""
1817
2011
  instance = len(self._instances)
1818
2012
  self._shape_instances[shape].append(instance)
1819
2013
  body = self._resolve_body_id(body)
1820
- self._instances[name] = (instance, body, shape, [*pos, *rot], scale, color1, color2)
2014
+ self._instances[name] = (instance, body, shape, [*pos, *rot], scale, color1, color2, visible)
1821
2015
  self._instance_shape[instance] = shape
2016
+ self._instance_custom_ids[instance] = custom_index
1822
2017
  self._add_shape_instances = True
1823
2018
  self._instance_count = len(self._instances)
1824
2019
  return instance
@@ -1843,7 +2038,7 @@ Instances: {len(self._instances)}"""
1843
2038
  gl.glDeleteBuffers(1, self._instance_color1_buffer)
1844
2039
  gl.glDeleteBuffers(1, self._instance_color2_buffer)
1845
2040
 
1846
- # Create instance buffer and bind it as an instanced array
2041
+ # create instance buffer and bind it as an instanced array
1847
2042
  self._instance_transform_gl_buffer = gl.GLuint()
1848
2043
  gl.glGenBuffers(1, self._instance_transform_gl_buffer)
1849
2044
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_transform_gl_buffer)
@@ -1851,7 +2046,7 @@ Instances: {len(self._instances)}"""
1851
2046
  transforms = np.tile(np.diag(np.ones(4, dtype=np.float32)), (len(self._instances), 1, 1))
1852
2047
  gl.glBufferData(gl.GL_ARRAY_BUFFER, transforms.nbytes, transforms.ctypes.data, gl.GL_DYNAMIC_DRAW)
1853
2048
 
1854
- # Create CUDA buffer for instance transforms
2049
+ # create CUDA buffer for instance transforms
1855
2050
  self._instance_transform_cuda_buffer = wp.RegisteredGLBuffer(
1856
2051
  int(self._instance_transform_gl_buffer.value), self._device
1857
2052
  )
@@ -1879,10 +2074,13 @@ Instances: {len(self._instances)}"""
1879
2074
  gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self._instance_color2_buffer)
1880
2075
  gl.glBufferData(gl.GL_ARRAY_BUFFER, colors2.nbytes, colors2.ctypes.data, gl.GL_STATIC_DRAW)
1881
2076
 
1882
- # Set up instance attribute pointers
2077
+ # set up instance attribute pointers
1883
2078
  matrix_size = transforms[0].nbytes
1884
2079
 
1885
2080
  instance_ids = []
2081
+ instance_custom_ids = []
2082
+ instance_visible = []
2083
+ instances = list(self._instances.values())
1886
2084
  inverse_instance_ids = {}
1887
2085
  instance_count = 0
1888
2086
  for shape, (vao, vbo, ebo, tri_count, vertex_cuda_buffer) in self._shape_gl_buffers.items():
@@ -1912,27 +2110,45 @@ Instances: {len(self._instances)}"""
1912
2110
  for i in self._shape_instances[shape]:
1913
2111
  inverse_instance_ids[i] = instance_count
1914
2112
  instance_count += 1
2113
+ instance_custom_ids.append(self._instance_custom_ids[i])
2114
+ instance_visible.append(instances[i][7])
1915
2115
 
1916
2116
  # trigger update to the instance transforms
1917
2117
  self._update_shape_instances = True
1918
2118
 
1919
2119
  self._wp_instance_ids = wp.array(instance_ids, dtype=wp.int32, device=self._device)
2120
+ self._wp_instance_custom_ids = wp.array(instance_custom_ids, dtype=wp.int32, device=self._device)
2121
+ self._np_instance_visible = np.array(instance_visible)
1920
2122
  self._instance_ids = instance_ids
1921
2123
  self._inverse_instance_ids = inverse_instance_ids
1922
2124
 
1923
2125
  gl.glBindVertexArray(0)
1924
2126
 
1925
- def update_shape_instance(self, name, pos, rot, color1=None, color2=None):
2127
+ def update_shape_instance(self, name, pos, rot, color1=None, color2=None, visible=None):
1926
2128
  """Update the instance transform of the shape
1927
2129
 
1928
2130
  Args:
1929
2131
  name: The name of the shape
1930
2132
  pos: The position of the shape
1931
2133
  rot: The rotation of the shape
2134
+ color1: The first color of the checker pattern
2135
+ color2: The second color of the checker pattern
2136
+ visible: Whether the shape is visible
1932
2137
  """
1933
2138
  if name in self._instances:
1934
- i, body, shape, _, scale, old_color1, old_color2 = self._instances[name]
1935
- self._instances[name] = (i, body, shape, [*pos, *rot], scale, color1 or old_color1, color2 or old_color2)
2139
+ i, body, shape, _, scale, old_color1, old_color2, v = self._instances[name]
2140
+ if visible is None:
2141
+ visible = v
2142
+ self._instances[name] = (
2143
+ i,
2144
+ body,
2145
+ shape,
2146
+ [*pos, *rot],
2147
+ scale,
2148
+ color1 or old_color1,
2149
+ color2 or old_color2,
2150
+ visible,
2151
+ )
1936
2152
  self._update_shape_instances = True
1937
2153
  return True
1938
2154
  return False
@@ -2000,9 +2216,27 @@ Instances: {len(self._instances)}"""
2000
2216
  self.clear()
2001
2217
  self.app.event_loop.exit()
2002
2218
 
2003
- def get_pixels(self, target_image: wp.array, split_up_tiles=True):
2219
+ def get_pixels(self, target_image: wp.array, split_up_tiles=True, mode="rgb"):
2220
+ """
2221
+ Read the pixels from the frame buffer (RGB or depth are supported) into the given array.
2222
+
2223
+ If `split_up_tiles` is False, array must be of shape (screen_height, screen_width, 3) for RGB mode or
2224
+ (screen_height, screen_width, 1) for depth mode.
2225
+ If `split_up_tiles` is True, the pixels will be split up into tiles (see :attr:`tile_width` and :attr:`tile_height` for dimensions):
2226
+ array must be of shape (num_tiles, tile_height, tile_width, 3) for RGB mode or (num_tiles, tile_height, tile_width, 1) for depth mode.
2227
+
2228
+ Args:
2229
+ target_image (array): The array to read the pixels into. Must have float32 as dtype and be on a CUDA device.
2230
+ split_up_tiles (bool): Whether to split up the viewport into tiles, see :meth:`setup_tiled_rendering`.
2231
+ mode (str): can be either "rgb" or "depth"
2232
+
2233
+ Returns:
2234
+ bool: Whether the pixels were successfully read.
2235
+ """
2004
2236
  from pyglet import gl
2005
2237
 
2238
+ channels = 3 if mode == "rgb" else 1
2239
+
2006
2240
  if split_up_tiles:
2007
2241
  assert (
2008
2242
  self._tile_width is not None and self._tile_height is not None
@@ -2017,20 +2251,26 @@ Instances: {len(self._instances)}"""
2017
2251
  self.num_tiles,
2018
2252
  self._tile_height,
2019
2253
  self._tile_width,
2020
- 3,
2021
- ), f"Shape of `target_image` array does not match {self.num_tiles} x {self.screen_height} x {self.screen_width} x 3"
2254
+ channels,
2255
+ ), f"Shape of `target_image` array does not match {self.num_tiles} x {self.screen_height} x {self.screen_width} x {channels}"
2022
2256
  else:
2023
2257
  assert target_image.shape == (
2024
2258
  self.screen_height,
2025
2259
  self.screen_width,
2026
- 3,
2027
- ), f"Shape of `target_image` array does not match {self.screen_height} x {self.screen_width} x 3"
2260
+ channels,
2261
+ ), f"Shape of `target_image` array does not match {self.screen_height} x {self.screen_width} x {channels}"
2028
2262
 
2029
2263
  gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, self._frame_pbo)
2030
- gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
2264
+ if mode == "rgb":
2265
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
2266
+ if mode == "depth":
2267
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_depth_texture)
2031
2268
  try:
2032
2269
  # read screen texture into PBO
2033
- gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0))
2270
+ if mode == "rgb":
2271
+ gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0))
2272
+ elif mode == "depth":
2273
+ gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT, ctypes.c_void_p(0))
2034
2274
  except gl.GLException:
2035
2275
  # this can happen if the window is closed/being moved to a different display
2036
2276
  gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
@@ -2043,63 +2283,54 @@ Instances: {len(self._instances)}"""
2043
2283
  int(self._frame_pbo.value), self._device, wp.RegisteredGLBuffer.WRITE_DISCARD
2044
2284
  )
2045
2285
  screen_size = self.screen_height * self.screen_width
2046
- img = pbo_buffer.map(dtype=wp.uint8, shape=(screen_size * 3))
2286
+ if mode == "rgb":
2287
+ img = pbo_buffer.map(dtype=wp.uint8, shape=(screen_size * channels))
2288
+ elif mode == "depth":
2289
+ img = pbo_buffer.map(dtype=wp.float32, shape=(screen_size * channels))
2047
2290
  img = img.to(target_image.device)
2048
2291
  if split_up_tiles:
2049
2292
  positions = wp.array(self._tile_viewports, ndim=2, dtype=wp.int32, device=target_image.device)
2050
- wp.launch(
2051
- copy_frame_tiles,
2052
- dim=(self.num_tiles, self._tile_width, self._tile_height),
2053
- inputs=[img, positions, self.screen_width, self.screen_height, self._tile_height],
2054
- outputs=[target_image],
2055
- device=target_image.device,
2056
- )
2293
+ if mode == "rgb":
2294
+ wp.launch(
2295
+ copy_rgb_frame_tiles,
2296
+ dim=(self.num_tiles, self._tile_width, self._tile_height),
2297
+ inputs=[img, positions, self.screen_width, self.screen_height, self._tile_height],
2298
+ outputs=[target_image],
2299
+ device=target_image.device,
2300
+ )
2301
+ elif mode == "depth":
2302
+ wp.launch(
2303
+ copy_depth_frame_tiles,
2304
+ dim=(self.num_tiles, self._tile_width, self._tile_height),
2305
+ inputs=[
2306
+ img,
2307
+ positions,
2308
+ self.screen_width,
2309
+ self.screen_height,
2310
+ self._tile_height,
2311
+ self.camera_near_plane,
2312
+ self.camera_far_plane,
2313
+ ],
2314
+ outputs=[target_image],
2315
+ device=target_image.device,
2316
+ )
2057
2317
  else:
2058
- wp.launch(
2059
- copy_frame,
2060
- dim=(self.screen_width, self.screen_height),
2061
- inputs=[img, self.screen_width, self.screen_height],
2062
- outputs=[target_image],
2063
- device=target_image.device,
2064
- )
2065
- pbo_buffer.unmap()
2066
- return True
2067
-
2068
- def get_tile_pixels(self, tile_id: int, target_image: wp.array):
2069
- from pyglet import gl
2070
-
2071
- viewport = self._tile_viewports[tile_id]
2072
- assert target_image.shape == (
2073
- viewport[3],
2074
- viewport[2],
2075
- 3,
2076
- ), f"Shape of `target_image` array does not match {viewport[3]} x {viewport[2]} x 3"
2077
- gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, self._frame_pbo)
2078
- gl.glBindTexture(gl.GL_TEXTURE_2D, self._frame_texture)
2079
- try:
2080
- # read screen texture into PBO
2081
- gl.glGetTexImage(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, gl.GL_UNSIGNED_BYTE, ctypes.c_void_p(0))
2082
- except gl.GLException:
2083
- # this can happen if the window is closed/being moved to a different display
2084
- gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
2085
- gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)
2086
- return False
2087
- gl.glBindTexture(gl.GL_TEXTURE_2D, 0)
2088
- gl.glBindBuffer(gl.GL_PIXEL_PACK_BUFFER, 0)
2089
-
2090
- pbo_buffer = wp.RegisteredGLBuffer(
2091
- int(self._frame_pbo.value), self._device, wp.RegisteredGLBuffer.WRITE_DISCARD
2092
- )
2093
- screen_size = self.screen_height * self.screen_width
2094
- img = pbo_buffer.map(dtype=wp.uint8, shape=(screen_size * 3))
2095
- img = img.to(target_image.device)
2096
- wp.launch(
2097
- copy_frame_tiles,
2098
- dim=(self.num_tiles, self._tile_width, self._tile_height),
2099
- inputs=[img, viewport[0], viewport[1], self.screen_width, self.screen_height, self._tile_height],
2100
- outputs=[target_image],
2101
- device=target_image.device,
2102
- )
2318
+ if mode == "rgb":
2319
+ wp.launch(
2320
+ copy_rgb_frame,
2321
+ dim=(self.screen_width, self.screen_height),
2322
+ inputs=[img, self.screen_width, self.screen_height],
2323
+ outputs=[target_image],
2324
+ device=target_image.device,
2325
+ )
2326
+ elif mode == "depth":
2327
+ wp.launch(
2328
+ copy_depth_frame,
2329
+ dim=(self.screen_width, self.screen_height),
2330
+ inputs=[img, self.screen_width, self.screen_height, self.camera_near_plane, self.camera_far_plane],
2331
+ outputs=[target_image],
2332
+ device=target_image.device,
2333
+ )
2103
2334
  pbo_buffer.unmap()
2104
2335
  return True
2105
2336
 
@@ -2515,6 +2746,7 @@ Instances: {len(self._instances)}"""
2515
2746
  wp_points = wp.array(points, dtype=wp.vec3, device=self._device)
2516
2747
 
2517
2748
  if name not in self._shape_instancers:
2749
+ np_points = points.numpy() if isinstance(points, wp.array) else points
2518
2750
  instancer = ShapeInstancer(self._shape_shader, self._device)
2519
2751
  radius_is_scalar = np.isscalar(radius)
2520
2752
  if radius_is_scalar:
@@ -2527,12 +2759,13 @@ Instances: {len(self._instances)}"""
2527
2759
  color = colors[0]
2528
2760
  instancer.register_shape(vertices, indices, color, color)
2529
2761
  scalings = None if radius_is_scalar else np.tile(radius, (3, 1)).T
2530
- instancer.allocate_instances(np.array(points), colors1=colors, colors2=colors, scalings=scalings)
2762
+ instancer.allocate_instances(np_points, colors1=colors, colors2=colors, scalings=scalings)
2531
2763
  self._shape_instancers[name] = instancer
2532
2764
  else:
2533
2765
  instancer = self._shape_instancers[name]
2534
2766
  if len(points) != instancer.num_instances:
2535
- instancer.allocate_instances(np.array(points))
2767
+ np_points = points.numpy() if isinstance(points, wp.array) else points
2768
+ instancer.allocate_instances(np_points)
2536
2769
 
2537
2770
  with instancer:
2538
2771
  wp.launch(
@@ -2550,7 +2783,7 @@ Instances: {len(self._instances)}"""
2550
2783
  if name not in self._shape_instancers:
2551
2784
  instancer = ShapeInstancer(self._shape_shader, self._device)
2552
2785
  vertices, indices = self._create_capsule_mesh(radius, 0.5)
2553
- if color is None:
2786
+ if color is None or isinstance(color, list) and len(color) > 0 and isinstance(color[0], list):
2554
2787
  color = tab10_color_map(len(self._shape_geo_hash))
2555
2788
  instancer.register_shape(vertices, indices, color, color)
2556
2789
  instancer.allocate_instances(np.zeros((len(lines), 3)))
@@ -2570,7 +2803,7 @@ Instances: {len(self._instances)}"""
2570
2803
  device=self._device,
2571
2804
  )
2572
2805
 
2573
- def render_line_list(self, name, vertices, indices, color, radius):
2806
+ def render_line_list(self, name: str, vertices, indices, color: tuple = None, radius: float = 0.01):
2574
2807
  """Add a line list as a set of capsules
2575
2808
 
2576
2809
  Args:
@@ -2585,7 +2818,7 @@ Instances: {len(self._instances)}"""
2585
2818
  lines = np.array(lines)
2586
2819
  self._render_lines(name, lines, color, radius)
2587
2820
 
2588
- def render_line_strip(self, name: str, vertices, color: tuple, radius: float = 0.01):
2821
+ def render_line_strip(self, name: str, vertices, color: tuple = None, radius: float = 0.01):
2589
2822
  """Add a line strip as a set of capsules
2590
2823
 
2591
2824
  Args:
@@ -2620,7 +2853,12 @@ Instances: {len(self._instances)}"""
2620
2853
  cuda_buffer.unmap()
2621
2854
 
2622
2855
  @staticmethod
2623
- def _create_sphere_mesh(radius=1.0, num_latitudes=default_num_segments, num_longitudes=default_num_segments):
2856
+ def _create_sphere_mesh(
2857
+ radius=1.0,
2858
+ num_latitudes=default_num_segments,
2859
+ num_longitudes=default_num_segments,
2860
+ reverse_winding=False,
2861
+ ):
2624
2862
  vertices = []
2625
2863
  indices = []
2626
2864
 
@@ -2648,7 +2886,10 @@ Instances: {len(self._instances)}"""
2648
2886
  first = i * (num_longitudes + 1) + j
2649
2887
  second = first + num_longitudes + 1
2650
2888
 
2651
- indices.extend([first, second, first + 1, second, second + 1, first + 1])
2889
+ if reverse_winding:
2890
+ indices.extend([first, second, first + 1, second, second + 1, first + 1])
2891
+ else:
2892
+ indices.extend([first, first + 1, second, second, first + 1, second + 1])
2652
2893
 
2653
2894
  return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)
2654
2895
 
@@ -2731,7 +2972,7 @@ Instances: {len(self._instances)}"""
2731
2972
  top_radius = radius
2732
2973
  side_slope = -np.arctan2(top_radius - radius, 2 * half_height)
2733
2974
 
2734
- # Create the cylinder base and top vertices
2975
+ # create the cylinder base and top vertices
2735
2976
  for j in (-1, 1):
2736
2977
  center_index = max(j, 0)
2737
2978
  if j == 1:
@@ -2759,11 +3000,10 @@ Instances: {len(self._instances)}"""
2759
3000
  vertex = np.hstack([position[[x_dir, y_dir, z_dir]], normal[[x_dir, y_dir, z_dir]], uv])
2760
3001
  cap_vertices.append(vertex)
2761
3002
 
2762
- indices.extend(
2763
- [center_index, i + center_index * segments + 2, (i + 1) % segments + center_index * segments + 2]
2764
- )
3003
+ cs = center_index * segments
3004
+ indices.extend([center_index, i + cs + 2, (i + 1) % segments + cs + 2][::-j])
2765
3005
 
2766
- # Create the cylinder side indices
3006
+ # create the cylinder side indices
2767
3007
  for i in range(segments):
2768
3008
  index1 = len(cap_vertices) + i + segments
2769
3009
  index2 = len(cap_vertices) + ((i + 1) % segments) + segments
@@ -2841,16 +3081,16 @@ Instances: {len(self._instances)}"""
2841
3081
  indices = [
2842
3082
  0, 1, 2,
2843
3083
  0, 2, 3,
2844
- 4, 5, 6,
2845
- 4, 6, 7,
2846
- 8, 9, 10,
2847
- 8, 10, 11,
3084
+ 4, 6, 5,
3085
+ 4, 7, 6,
3086
+ 8, 10, 9,
3087
+ 8, 11, 10,
2848
3088
  12, 13, 14,
2849
3089
  12, 14, 15,
2850
3090
  16, 17, 18,
2851
3091
  16, 18, 19,
2852
- 20, 21, 22,
2853
- 20, 22, 23,
3092
+ 20, 22, 21,
3093
+ 20, 23, 22,
2854
3094
  ]
2855
3095
  # fmt: on
2856
3096
  return np.array(vertices, dtype=np.float32), np.array(indices, dtype=np.uint32)