warp-lang 1.0.2__py3-none-macosx_10_13_universal2.whl → 1.1.0__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 +108 -97
- warp/__init__.pyi +1 -1
- warp/bin/libwarp-clang.dylib +0 -0
- warp/bin/libwarp.dylib +0 -0
- warp/build.py +115 -113
- warp/build_dll.py +383 -375
- warp/builtins.py +3425 -3354
- warp/codegen.py +2878 -2792
- warp/config.py +40 -36
- warp/constants.py +45 -45
- warp/context.py +5194 -5102
- warp/dlpack.py +442 -442
- warp/examples/__init__.py +16 -16
- warp/examples/assets/bear.usd +0 -0
- warp/examples/assets/bunny.usd +0 -0
- warp/examples/assets/cartpole.urdf +110 -110
- warp/examples/assets/crazyflie.usd +0 -0
- warp/examples/assets/cube.usd +0 -0
- warp/examples/assets/nv_ant.xml +92 -92
- warp/examples/assets/nv_humanoid.xml +183 -183
- warp/examples/assets/quadruped.urdf +267 -267
- warp/examples/assets/rocks.nvdb +0 -0
- warp/examples/assets/rocks.usd +0 -0
- warp/examples/assets/sphere.usd +0 -0
- warp/examples/benchmarks/benchmark_api.py +383 -383
- warp/examples/benchmarks/benchmark_cloth.py +278 -277
- warp/examples/benchmarks/benchmark_cloth_cupy.py +88 -88
- warp/examples/benchmarks/benchmark_cloth_jax.py +97 -100
- warp/examples/benchmarks/benchmark_cloth_numba.py +146 -142
- warp/examples/benchmarks/benchmark_cloth_numpy.py +77 -77
- warp/examples/benchmarks/benchmark_cloth_pytorch.py +86 -86
- warp/examples/benchmarks/benchmark_cloth_taichi.py +112 -112
- warp/examples/benchmarks/benchmark_cloth_warp.py +146 -146
- warp/examples/benchmarks/benchmark_launches.py +295 -295
- warp/examples/browse.py +29 -29
- warp/examples/core/example_dem.py +234 -219
- warp/examples/core/example_fluid.py +293 -267
- warp/examples/core/example_graph_capture.py +144 -126
- warp/examples/core/example_marching_cubes.py +188 -174
- warp/examples/core/example_mesh.py +174 -155
- warp/examples/core/example_mesh_intersect.py +205 -193
- warp/examples/core/example_nvdb.py +176 -170
- warp/examples/core/example_raycast.py +105 -90
- warp/examples/core/example_raymarch.py +199 -178
- warp/examples/core/example_render_opengl.py +185 -141
- warp/examples/core/example_sph.py +405 -387
- warp/examples/core/example_torch.py +222 -181
- warp/examples/core/example_wave.py +263 -248
- warp/examples/fem/bsr_utils.py +378 -380
- warp/examples/fem/example_apic_fluid.py +407 -389
- warp/examples/fem/example_convection_diffusion.py +182 -168
- warp/examples/fem/example_convection_diffusion_dg.py +219 -209
- warp/examples/fem/example_convection_diffusion_dg0.py +204 -194
- warp/examples/fem/example_deformed_geometry.py +177 -159
- warp/examples/fem/example_diffusion.py +201 -173
- warp/examples/fem/example_diffusion_3d.py +177 -152
- warp/examples/fem/example_diffusion_mgpu.py +221 -214
- warp/examples/fem/example_mixed_elasticity.py +244 -222
- warp/examples/fem/example_navier_stokes.py +259 -243
- warp/examples/fem/example_stokes.py +220 -192
- warp/examples/fem/example_stokes_transfer.py +265 -249
- warp/examples/fem/mesh_utils.py +133 -109
- warp/examples/fem/plot_utils.py +292 -287
- warp/examples/optim/example_bounce.py +260 -246
- warp/examples/optim/example_cloth_throw.py +222 -209
- warp/examples/optim/example_diffray.py +566 -536
- warp/examples/optim/example_drone.py +864 -835
- warp/examples/optim/example_inverse_kinematics.py +176 -168
- warp/examples/optim/example_inverse_kinematics_torch.py +185 -169
- warp/examples/optim/example_spring_cage.py +239 -231
- warp/examples/optim/example_trajectory.py +223 -199
- warp/examples/optim/example_walker.py +306 -293
- warp/examples/sim/example_cartpole.py +139 -129
- warp/examples/sim/example_cloth.py +196 -186
- warp/examples/sim/example_granular.py +124 -111
- warp/examples/sim/example_granular_collision_sdf.py +197 -186
- warp/examples/sim/example_jacobian_ik.py +236 -214
- warp/examples/sim/example_particle_chain.py +118 -105
- warp/examples/sim/example_quadruped.py +193 -180
- warp/examples/sim/example_rigid_chain.py +197 -187
- warp/examples/sim/example_rigid_contact.py +189 -177
- warp/examples/sim/example_rigid_force.py +127 -125
- warp/examples/sim/example_rigid_gyroscopic.py +109 -95
- warp/examples/sim/example_rigid_soft_contact.py +134 -122
- warp/examples/sim/example_soft_body.py +190 -177
- warp/fabric.py +337 -335
- warp/fem/__init__.py +60 -27
- warp/fem/cache.py +401 -388
- warp/fem/dirichlet.py +178 -179
- warp/fem/domain.py +262 -263
- warp/fem/field/__init__.py +100 -101
- warp/fem/field/field.py +148 -149
- warp/fem/field/nodal_field.py +298 -299
- warp/fem/field/restriction.py +22 -21
- warp/fem/field/test.py +180 -181
- warp/fem/field/trial.py +183 -183
- warp/fem/geometry/__init__.py +15 -19
- warp/fem/geometry/closest_point.py +69 -70
- warp/fem/geometry/deformed_geometry.py +270 -271
- warp/fem/geometry/element.py +744 -744
- warp/fem/geometry/geometry.py +184 -186
- warp/fem/geometry/grid_2d.py +380 -373
- warp/fem/geometry/grid_3d.py +441 -435
- warp/fem/geometry/hexmesh.py +953 -953
- warp/fem/geometry/partition.py +374 -376
- warp/fem/geometry/quadmesh_2d.py +532 -532
- warp/fem/geometry/tetmesh.py +840 -840
- warp/fem/geometry/trimesh_2d.py +577 -577
- warp/fem/integrate.py +1630 -1615
- warp/fem/operator.py +190 -191
- warp/fem/polynomial.py +214 -213
- warp/fem/quadrature/__init__.py +2 -2
- warp/fem/quadrature/pic_quadrature.py +243 -245
- warp/fem/quadrature/quadrature.py +295 -294
- warp/fem/space/__init__.py +294 -292
- warp/fem/space/basis_space.py +488 -489
- warp/fem/space/collocated_function_space.py +100 -105
- warp/fem/space/dof_mapper.py +236 -236
- warp/fem/space/function_space.py +148 -145
- warp/fem/space/grid_2d_function_space.py +267 -267
- warp/fem/space/grid_3d_function_space.py +305 -306
- warp/fem/space/hexmesh_function_space.py +350 -352
- warp/fem/space/partition.py +350 -350
- warp/fem/space/quadmesh_2d_function_space.py +368 -369
- warp/fem/space/restriction.py +158 -160
- warp/fem/space/shape/__init__.py +13 -15
- warp/fem/space/shape/cube_shape_function.py +738 -738
- warp/fem/space/shape/shape_function.py +102 -103
- warp/fem/space/shape/square_shape_function.py +611 -611
- warp/fem/space/shape/tet_shape_function.py +565 -567
- warp/fem/space/shape/triangle_shape_function.py +429 -429
- warp/fem/space/tetmesh_function_space.py +294 -292
- warp/fem/space/topology.py +297 -295
- warp/fem/space/trimesh_2d_function_space.py +223 -221
- warp/fem/types.py +77 -77
- warp/fem/utils.py +495 -495
- warp/jax.py +166 -141
- warp/jax_experimental.py +341 -339
- warp/native/array.h +1072 -1025
- warp/native/builtin.h +1560 -1560
- warp/native/bvh.cpp +398 -398
- warp/native/bvh.cu +525 -525
- warp/native/bvh.h +429 -429
- warp/native/clang/clang.cpp +495 -464
- warp/native/crt.cpp +31 -31
- warp/native/crt.h +334 -334
- warp/native/cuda_crt.h +1049 -1049
- warp/native/cuda_util.cpp +549 -540
- warp/native/cuda_util.h +288 -203
- warp/native/cutlass_gemm.cpp +34 -34
- warp/native/cutlass_gemm.cu +372 -372
- warp/native/error.cpp +66 -66
- warp/native/error.h +27 -27
- warp/native/fabric.h +228 -228
- warp/native/hashgrid.cpp +301 -278
- warp/native/hashgrid.cu +78 -77
- warp/native/hashgrid.h +227 -227
- warp/native/initializer_array.h +32 -32
- warp/native/intersect.h +1204 -1204
- warp/native/intersect_adj.h +365 -365
- warp/native/intersect_tri.h +322 -322
- warp/native/marching.cpp +2 -2
- warp/native/marching.cu +497 -497
- warp/native/marching.h +2 -2
- warp/native/mat.h +1498 -1498
- warp/native/matnn.h +333 -333
- warp/native/mesh.cpp +203 -203
- warp/native/mesh.cu +293 -293
- warp/native/mesh.h +1887 -1887
- warp/native/nanovdb/NanoVDB.h +4782 -4782
- warp/native/nanovdb/PNanoVDB.h +2553 -2553
- warp/native/nanovdb/PNanoVDBWrite.h +294 -294
- warp/native/noise.h +850 -850
- warp/native/quat.h +1084 -1084
- warp/native/rand.h +299 -299
- warp/native/range.h +108 -108
- warp/native/reduce.cpp +156 -156
- warp/native/reduce.cu +348 -348
- warp/native/runlength_encode.cpp +61 -61
- warp/native/runlength_encode.cu +46 -46
- warp/native/scan.cpp +30 -30
- warp/native/scan.cu +36 -36
- warp/native/scan.h +7 -7
- warp/native/solid_angle.h +442 -442
- warp/native/sort.cpp +94 -94
- warp/native/sort.cu +97 -97
- warp/native/sort.h +14 -14
- warp/native/sparse.cpp +337 -337
- warp/native/sparse.cu +544 -544
- warp/native/spatial.h +630 -630
- warp/native/svd.h +562 -562
- warp/native/temp_buffer.h +30 -30
- warp/native/vec.h +1132 -1132
- warp/native/volume.cpp +297 -297
- warp/native/volume.cu +32 -32
- warp/native/volume.h +538 -538
- warp/native/volume_builder.cu +425 -425
- warp/native/volume_builder.h +19 -19
- warp/native/warp.cpp +1057 -1052
- warp/native/warp.cu +2943 -2828
- warp/native/warp.h +313 -305
- warp/optim/__init__.py +9 -9
- warp/optim/adam.py +120 -120
- warp/optim/linear.py +1104 -939
- warp/optim/sgd.py +104 -92
- warp/render/__init__.py +10 -10
- warp/render/render_opengl.py +3217 -3204
- warp/render/render_usd.py +768 -749
- warp/render/utils.py +152 -150
- warp/sim/__init__.py +52 -59
- warp/sim/articulation.py +685 -685
- warp/sim/collide.py +1594 -1590
- warp/sim/import_mjcf.py +489 -481
- warp/sim/import_snu.py +220 -221
- warp/sim/import_urdf.py +536 -516
- warp/sim/import_usd.py +887 -881
- warp/sim/inertia.py +316 -317
- warp/sim/integrator.py +234 -233
- warp/sim/integrator_euler.py +1956 -1956
- warp/sim/integrator_featherstone.py +1910 -1991
- warp/sim/integrator_xpbd.py +3294 -3312
- warp/sim/model.py +4473 -4314
- warp/sim/particles.py +113 -112
- warp/sim/render.py +417 -403
- warp/sim/utils.py +413 -410
- warp/sparse.py +1227 -1227
- warp/stubs.py +2109 -2469
- warp/tape.py +1162 -225
- warp/tests/__init__.py +1 -1
- warp/tests/__main__.py +4 -4
- warp/tests/assets/torus.usda +105 -105
- warp/tests/aux_test_class_kernel.py +26 -26
- warp/tests/aux_test_compile_consts_dummy.py +10 -10
- warp/tests/aux_test_conditional_unequal_types_kernels.py +21 -21
- warp/tests/aux_test_dependent.py +22 -22
- warp/tests/aux_test_grad_customs.py +23 -23
- warp/tests/aux_test_reference.py +11 -11
- warp/tests/aux_test_reference_reference.py +10 -10
- warp/tests/aux_test_square.py +17 -17
- warp/tests/aux_test_unresolved_func.py +14 -14
- warp/tests/aux_test_unresolved_symbol.py +14 -14
- warp/tests/disabled_kinematics.py +239 -239
- warp/tests/run_coverage_serial.py +31 -31
- warp/tests/test_adam.py +157 -157
- warp/tests/test_arithmetic.py +1124 -1124
- warp/tests/test_array.py +2417 -2326
- warp/tests/test_array_reduce.py +150 -150
- warp/tests/test_async.py +668 -656
- warp/tests/test_atomic.py +141 -141
- warp/tests/test_bool.py +204 -149
- warp/tests/test_builtins_resolution.py +1292 -1292
- warp/tests/test_bvh.py +164 -171
- warp/tests/test_closest_point_edge_edge.py +228 -228
- warp/tests/test_codegen.py +566 -553
- warp/tests/test_compile_consts.py +97 -101
- warp/tests/test_conditional.py +246 -246
- warp/tests/test_copy.py +232 -215
- warp/tests/test_ctypes.py +632 -632
- warp/tests/test_dense.py +67 -67
- warp/tests/test_devices.py +91 -98
- warp/tests/test_dlpack.py +530 -529
- warp/tests/test_examples.py +400 -378
- warp/tests/test_fabricarray.py +955 -955
- warp/tests/test_fast_math.py +62 -54
- warp/tests/test_fem.py +1277 -1278
- warp/tests/test_fp16.py +130 -130
- warp/tests/test_func.py +338 -337
- warp/tests/test_generics.py +571 -571
- warp/tests/test_grad.py +746 -640
- warp/tests/test_grad_customs.py +333 -336
- warp/tests/test_hash_grid.py +210 -164
- warp/tests/test_import.py +39 -39
- warp/tests/test_indexedarray.py +1134 -1134
- warp/tests/test_intersect.py +67 -67
- warp/tests/test_jax.py +307 -307
- warp/tests/test_large.py +167 -164
- warp/tests/test_launch.py +354 -354
- warp/tests/test_lerp.py +261 -261
- warp/tests/test_linear_solvers.py +191 -171
- warp/tests/test_lvalue.py +421 -493
- warp/tests/test_marching_cubes.py +65 -65
- warp/tests/test_mat.py +1801 -1827
- warp/tests/test_mat_lite.py +115 -115
- warp/tests/test_mat_scalar_ops.py +2907 -2889
- warp/tests/test_math.py +126 -193
- warp/tests/test_matmul.py +500 -499
- warp/tests/test_matmul_lite.py +410 -410
- warp/tests/test_mempool.py +188 -190
- warp/tests/test_mesh.py +284 -324
- warp/tests/test_mesh_query_aabb.py +228 -241
- warp/tests/test_mesh_query_point.py +692 -702
- warp/tests/test_mesh_query_ray.py +292 -303
- warp/tests/test_mlp.py +276 -276
- warp/tests/test_model.py +110 -110
- warp/tests/test_modules_lite.py +39 -39
- warp/tests/test_multigpu.py +163 -163
- warp/tests/test_noise.py +248 -248
- warp/tests/test_operators.py +250 -250
- warp/tests/test_options.py +123 -125
- warp/tests/test_peer.py +133 -137
- warp/tests/test_pinned.py +78 -78
- warp/tests/test_print.py +54 -54
- warp/tests/test_quat.py +2086 -2086
- warp/tests/test_rand.py +288 -288
- warp/tests/test_reload.py +217 -217
- warp/tests/test_rounding.py +179 -179
- warp/tests/test_runlength_encode.py +190 -190
- warp/tests/test_sim_grad.py +243 -0
- warp/tests/test_sim_kinematics.py +91 -97
- warp/tests/test_smoothstep.py +168 -168
- warp/tests/test_snippet.py +305 -266
- warp/tests/test_sparse.py +468 -460
- warp/tests/test_spatial.py +2148 -2148
- warp/tests/test_streams.py +486 -473
- warp/tests/test_struct.py +710 -675
- warp/tests/test_tape.py +173 -148
- warp/tests/test_torch.py +743 -743
- warp/tests/test_transient_module.py +87 -87
- warp/tests/test_types.py +556 -659
- warp/tests/test_utils.py +490 -499
- warp/tests/test_vec.py +1264 -1268
- warp/tests/test_vec_lite.py +73 -73
- warp/tests/test_vec_scalar_ops.py +2099 -2099
- warp/tests/test_verify_fp.py +94 -94
- warp/tests/test_volume.py +737 -736
- warp/tests/test_volume_write.py +255 -265
- warp/tests/unittest_serial.py +37 -37
- warp/tests/unittest_suites.py +363 -359
- warp/tests/unittest_utils.py +603 -578
- warp/tests/unused_test_misc.py +71 -71
- warp/tests/walkthrough_debug.py +85 -85
- warp/thirdparty/appdirs.py +598 -598
- warp/thirdparty/dlpack.py +143 -143
- warp/thirdparty/unittest_parallel.py +566 -561
- warp/torch.py +321 -295
- warp/types.py +4504 -4450
- warp/utils.py +1008 -821
- {warp_lang-1.0.2.dist-info → warp_lang-1.1.0.dist-info}/LICENSE.md +126 -126
- {warp_lang-1.0.2.dist-info → warp_lang-1.1.0.dist-info}/METADATA +338 -400
- warp_lang-1.1.0.dist-info/RECORD +352 -0
- warp/examples/assets/cube.usda +0 -42
- warp/examples/assets/sphere.usda +0 -56
- warp/examples/assets/torus.usda +0 -105
- warp_lang-1.0.2.dist-info/RECORD +0 -352
- {warp_lang-1.0.2.dist-info → warp_lang-1.1.0.dist-info}/WHEEL +0 -0
- {warp_lang-1.0.2.dist-info → warp_lang-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,536 +1,566 @@
|
|
|
1
|
-
# Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
|
|
2
|
-
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
|
3
|
-
# and proprietary rights in and to this software, related documentation
|
|
4
|
-
# and any modifications thereto. Any use, reproduction, disclosure or
|
|
5
|
-
# distribution of this software and related documentation without an express
|
|
6
|
-
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
|
7
|
-
|
|
8
|
-
#############################################################################
|
|
9
|
-
# Example Differentiable Ray Caster
|
|
10
|
-
#
|
|
11
|
-
# Shows how to use the built-in wp.Mesh data structure and wp.mesh_query_ray()
|
|
12
|
-
# function to implement a basic differentiable ray caster
|
|
13
|
-
#
|
|
14
|
-
##############################################################################
|
|
15
|
-
|
|
16
|
-
import math
|
|
17
|
-
import os
|
|
18
|
-
|
|
19
|
-
import numpy as np
|
|
20
|
-
from pxr import Usd, UsdGeom
|
|
21
|
-
|
|
22
|
-
import warp as wp
|
|
23
|
-
import warp.examples
|
|
24
|
-
from warp.optim import SGD
|
|
25
|
-
|
|
26
|
-
wp.init()
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class RenderMode:
|
|
30
|
-
"""Rendering modes
|
|
31
|
-
grayscale: Lambertian shading from multiple directional lights
|
|
32
|
-
texture: 2D texture map
|
|
33
|
-
normal_map: mesh normal computed from interpolated vertex normals
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
grayscale = 0
|
|
37
|
-
texture = 1
|
|
38
|
-
normal_map = 2
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
@wp.struct
|
|
42
|
-
class RenderMesh:
|
|
43
|
-
"""Mesh to be ray casted.
|
|
44
|
-
Assumes a triangle mesh as input.
|
|
45
|
-
Per-vertex normals are computed with compute_vertex_normals()
|
|
46
|
-
"""
|
|
47
|
-
|
|
48
|
-
id: wp.uint64
|
|
49
|
-
vertices: wp.array(dtype=wp.vec3)
|
|
50
|
-
indices: wp.array(dtype=int)
|
|
51
|
-
tex_coords: wp.array(dtype=wp.vec2)
|
|
52
|
-
tex_indices: wp.array(dtype=int)
|
|
53
|
-
vertex_normals: wp.array(dtype=wp.vec3)
|
|
54
|
-
pos: wp.array(dtype=wp.vec3)
|
|
55
|
-
rot: wp.array(dtype=wp.quat)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@wp.struct
|
|
59
|
-
class Camera:
|
|
60
|
-
"""Basic camera for ray casting"""
|
|
61
|
-
|
|
62
|
-
horizontal: float
|
|
63
|
-
vertical: float
|
|
64
|
-
aspect: float
|
|
65
|
-
e: float
|
|
66
|
-
tan: float
|
|
67
|
-
pos: wp.vec3
|
|
68
|
-
rot: wp.quat
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@wp.struct
|
|
72
|
-
class DirectionalLights:
|
|
73
|
-
"""Stores arrays of directional light directions and intensities."""
|
|
74
|
-
|
|
75
|
-
dirs: wp.array(dtype=wp.vec3)
|
|
76
|
-
intensities: wp.array(dtype=float)
|
|
77
|
-
num_lights: int
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@wp.kernel
|
|
81
|
-
def vertex_normal_sum_kernel(
|
|
82
|
-
verts: wp.array(dtype=wp.vec3), indices: wp.array(dtype=int), normal_sums: wp.array(dtype=wp.vec3)
|
|
83
|
-
):
|
|
84
|
-
tid = wp.tid()
|
|
85
|
-
|
|
86
|
-
i = indices[tid * 3]
|
|
87
|
-
j = indices[tid * 3 + 1]
|
|
88
|
-
k = indices[tid * 3 + 2]
|
|
89
|
-
|
|
90
|
-
a = verts[i]
|
|
91
|
-
b = verts[j]
|
|
92
|
-
c = verts[k]
|
|
93
|
-
|
|
94
|
-
ab = b - a
|
|
95
|
-
ac = c - a
|
|
96
|
-
|
|
97
|
-
area_normal = wp.cross(ab, ac)
|
|
98
|
-
wp.atomic_add(normal_sums, i, area_normal)
|
|
99
|
-
wp.atomic_add(normal_sums, j, area_normal)
|
|
100
|
-
wp.atomic_add(normal_sums, k, area_normal)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@wp.kernel
|
|
104
|
-
def normalize_kernel(
|
|
105
|
-
normal_sums: wp.array(dtype=wp.vec3),
|
|
106
|
-
vertex_normals: wp.array(dtype=wp.vec3),
|
|
107
|
-
):
|
|
108
|
-
tid = wp.tid()
|
|
109
|
-
vertex_normals[tid] = wp.normalize(normal_sums[tid])
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@wp.func
|
|
113
|
-
def texture_interpolation(tex_interp: wp.vec2, texture: wp.array2d(dtype=wp.vec3)):
|
|
114
|
-
tex_width = texture.shape[1]
|
|
115
|
-
tex_height = texture.shape[0]
|
|
116
|
-
tex = wp.vec2(tex_interp[0] * float(tex_width - 1), (1.0 - tex_interp[1]) * float(tex_height - 1))
|
|
117
|
-
|
|
118
|
-
x0 = int(tex[0])
|
|
119
|
-
x1 = x0 + 1
|
|
120
|
-
alpha_x = tex[0] - float(x0)
|
|
121
|
-
y0 = int(tex[1])
|
|
122
|
-
y1 = y0 + 1
|
|
123
|
-
alpha_y = tex[1] - float(y0)
|
|
124
|
-
c00 = texture[y0, x0]
|
|
125
|
-
c10 = texture[y0, x1]
|
|
126
|
-
c01 = texture[y1, x0]
|
|
127
|
-
c11 = texture[y1, x1]
|
|
128
|
-
lower = (1.0 - alpha_x) * c00 + alpha_x * c10
|
|
129
|
-
upper = (1.0 - alpha_x) * c01 + alpha_x * c11
|
|
130
|
-
color = (1.0 - alpha_y) * lower + alpha_y * upper
|
|
131
|
-
|
|
132
|
-
return color
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@wp.kernel
|
|
136
|
-
def draw_kernel(
|
|
137
|
-
mesh: RenderMesh,
|
|
138
|
-
camera: Camera,
|
|
139
|
-
texture: wp.array2d(dtype=wp.vec3),
|
|
140
|
-
rays_width: int,
|
|
141
|
-
rays_height: int,
|
|
142
|
-
rays: wp.array(dtype=wp.vec3),
|
|
143
|
-
lights: DirectionalLights,
|
|
144
|
-
mode: int,
|
|
145
|
-
):
|
|
146
|
-
tid = wp.tid()
|
|
147
|
-
|
|
148
|
-
x = tid % rays_width
|
|
149
|
-
y = rays_height - tid // rays_width
|
|
150
|
-
|
|
151
|
-
sx = 2.0 * float(x) / float(rays_width) - 1.0
|
|
152
|
-
sy = 2.0 * float(y) / float(rays_height) - 1.0
|
|
153
|
-
|
|
154
|
-
# compute view ray in world space
|
|
155
|
-
ro_world = camera.pos
|
|
156
|
-
rd_world = wp.normalize(wp.quat_rotate(camera.rot, wp.vec3(sx * camera.tan * camera.aspect, sy * camera.tan, -1.0)))
|
|
157
|
-
|
|
158
|
-
# compute view ray in mesh space
|
|
159
|
-
inv = wp.transform_inverse(wp.transform(mesh.pos[0], mesh.rot[0]))
|
|
160
|
-
ro = wp.transform_point(inv, ro_world)
|
|
161
|
-
rd = wp.transform_vector(inv, rd_world)
|
|
162
|
-
|
|
163
|
-
color = wp.vec3(0.0, 0.0, 0.0)
|
|
164
|
-
|
|
165
|
-
query = wp.mesh_query_ray(mesh.id, ro, rd, 1.0e6)
|
|
166
|
-
if query.result:
|
|
167
|
-
i = mesh.indices[query.face * 3]
|
|
168
|
-
j = mesh.indices[query.face * 3 + 1]
|
|
169
|
-
k = mesh.indices[query.face * 3 + 2]
|
|
170
|
-
|
|
171
|
-
a = mesh.vertices[i]
|
|
172
|
-
b = mesh.vertices[j]
|
|
173
|
-
c = mesh.vertices[k]
|
|
174
|
-
|
|
175
|
-
p = wp.mesh_eval_position(mesh.id, query.face, query.u, query.v)
|
|
176
|
-
|
|
177
|
-
# barycentric coordinates
|
|
178
|
-
tri_area = wp.length(wp.cross(b - a, c - a))
|
|
179
|
-
w = wp.length(wp.cross(b - a, p - a)) / tri_area
|
|
180
|
-
v = wp.length(wp.cross(p - a, c - a)) / tri_area
|
|
181
|
-
u = 1.0 - w - v
|
|
182
|
-
|
|
183
|
-
a_n = mesh.vertex_normals[i]
|
|
184
|
-
b_n = mesh.vertex_normals[j]
|
|
185
|
-
c_n = mesh.vertex_normals[k]
|
|
186
|
-
|
|
187
|
-
# vertex normal interpolation
|
|
188
|
-
normal = u * a_n + v * b_n + w * c_n
|
|
189
|
-
|
|
190
|
-
if mode == 0 or mode == 1:
|
|
191
|
-
if mode == 0: # grayscale
|
|
192
|
-
color = wp.vec3(1.0)
|
|
193
|
-
|
|
194
|
-
elif mode == 1: # texture interpolation
|
|
195
|
-
tex_a = mesh.tex_coords[mesh.tex_indices[query.face * 3]]
|
|
196
|
-
tex_b = mesh.tex_coords[mesh.tex_indices[query.face * 3 + 1]]
|
|
197
|
-
tex_c = mesh.tex_coords[mesh.tex_indices[query.face * 3 + 2]]
|
|
198
|
-
|
|
199
|
-
tex = u * tex_a + v * tex_b + w * tex_c
|
|
200
|
-
|
|
201
|
-
color = texture_interpolation(tex, texture)
|
|
202
|
-
|
|
203
|
-
# lambertian directional lighting
|
|
204
|
-
lambert = float(0.0)
|
|
205
|
-
for i in range(lights.num_lights):
|
|
206
|
-
dir = wp.transform_vector(inv, lights.dirs[i])
|
|
207
|
-
val = lights.intensities[i] * wp.dot(normal, dir)
|
|
208
|
-
if val < 0.0:
|
|
209
|
-
val = 0.0
|
|
210
|
-
lambert = lambert + val
|
|
211
|
-
|
|
212
|
-
color = lambert * color
|
|
213
|
-
|
|
214
|
-
elif mode == 2: # normal map
|
|
215
|
-
color = normal * 0.5 + wp.vec3(0.5, 0.5, 0.5)
|
|
216
|
-
|
|
217
|
-
if color[0] > 1.0:
|
|
218
|
-
color = wp.vec3(1.0, color[1], color[2])
|
|
219
|
-
if color[1] > 1.0:
|
|
220
|
-
color = wp.vec3(color[0], 1.0, color[2])
|
|
221
|
-
if color[2] > 1.0:
|
|
222
|
-
color = wp.vec3(color[0], color[1], 1.0)
|
|
223
|
-
|
|
224
|
-
rays[tid] = color
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
@wp.kernel
|
|
228
|
-
def downsample_kernel(
|
|
229
|
-
rays: wp.array(dtype=wp.vec3), pixels: wp.array(dtype=wp.vec3), rays_width: int, num_samples: int
|
|
230
|
-
):
|
|
231
|
-
tid = wp.tid()
|
|
232
|
-
|
|
233
|
-
pixels_width = rays_width / num_samples
|
|
234
|
-
px = tid % pixels_width
|
|
235
|
-
py = tid // pixels_width
|
|
236
|
-
start_idx = py * num_samples * rays_width + px * num_samples
|
|
237
|
-
|
|
238
|
-
color = wp.vec3(0.0, 0.0, 0.0)
|
|
239
|
-
|
|
240
|
-
for i in range(0, num_samples):
|
|
241
|
-
for j in range(0, num_samples):
|
|
242
|
-
ray = rays[start_idx + i * rays_width + j]
|
|
243
|
-
color = wp.vec3(color[0] + ray[0], color[1] + ray[1], color[2] + ray[2])
|
|
244
|
-
|
|
245
|
-
num_samples_sq = float(num_samples * num_samples)
|
|
246
|
-
color = wp.vec3(color[0] / num_samples_sq, color[1] / num_samples_sq, color[2] / num_samples_sq)
|
|
247
|
-
pixels[tid] = color
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
@wp.kernel
|
|
251
|
-
def loss_kernel(pixels: wp.array(dtype=wp.vec3), target_pixels: wp.array(dtype=wp.vec3), loss: wp.array(dtype=float)):
|
|
252
|
-
tid = wp.tid()
|
|
253
|
-
|
|
254
|
-
pixel = pixels[tid]
|
|
255
|
-
target_pixel = target_pixels[tid]
|
|
256
|
-
|
|
257
|
-
diff = target_pixel - pixel
|
|
258
|
-
|
|
259
|
-
# pseudo Huber loss
|
|
260
|
-
delta = 1.0
|
|
261
|
-
x = delta * delta * (wp.sqrt(1.0 + (diff[0] / delta) * (diff[0] / delta)) - 1.0)
|
|
262
|
-
y = delta * delta * (wp.sqrt(1.0 + (diff[1] / delta) * (diff[1] / delta)) - 1.0)
|
|
263
|
-
z = delta * delta * (wp.sqrt(1.0 + (diff[2] / delta) * (diff[2] / delta)) - 1.0)
|
|
264
|
-
sum = x + y + z
|
|
265
|
-
|
|
266
|
-
wp.atomic_add(loss, 0, sum)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
@wp.kernel
|
|
270
|
-
def normalize(x: wp.array(dtype=wp.quat)):
|
|
271
|
-
tid = wp.tid()
|
|
272
|
-
|
|
273
|
-
x[tid] = wp.normalize(x[tid])
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
class Example:
|
|
277
|
-
"""
|
|
278
|
-
Non-differentiable variables:
|
|
279
|
-
camera.horizontal: camera horizontal aperture size
|
|
280
|
-
camera.vertical: camera vertical aperture size
|
|
281
|
-
camera.aspect: camera aspect ratio
|
|
282
|
-
camera.e: focal length
|
|
283
|
-
camera.pos: camera displacement
|
|
284
|
-
camera.rot: camera rotation (quaternion)
|
|
285
|
-
pix_width: final image width in pixels
|
|
286
|
-
pix_height: final image height in pixels
|
|
287
|
-
num_samples: anti-aliasing. calculated as pow(2, num_samples)
|
|
288
|
-
directional_lights: characterized by intensity (scalar) and direction (vec3)
|
|
289
|
-
render_mesh.indices: mesh vertex indices
|
|
290
|
-
render_mesh.tex_indices: texture indices
|
|
291
|
-
|
|
292
|
-
Differentiable variables:
|
|
293
|
-
render_mesh.pos: parent transform displacement
|
|
294
|
-
render_mesh.quat: parent transform rotation (quaternion)
|
|
295
|
-
render_mesh.vertices: mesh vertex positions
|
|
296
|
-
render_mesh.vertex_normals: mesh vertex normals
|
|
297
|
-
render_mesh.tex_coords: 2D texture coordinates
|
|
298
|
-
"""
|
|
299
|
-
|
|
300
|
-
def __init__(self,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
self.
|
|
309
|
-
self.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
distance =
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
self.
|
|
343
|
-
self.
|
|
344
|
-
self.
|
|
345
|
-
self.
|
|
346
|
-
self.
|
|
347
|
-
self.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
self.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
self.
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
self.render_mesh.
|
|
360
|
-
self.render_mesh.
|
|
361
|
-
self.render_mesh.
|
|
362
|
-
self.render_mesh.
|
|
363
|
-
self.
|
|
364
|
-
self.
|
|
365
|
-
self.render_mesh.
|
|
366
|
-
self.render_mesh.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
self.camera
|
|
383
|
-
self.camera.
|
|
384
|
-
self.camera.
|
|
385
|
-
self.camera.
|
|
386
|
-
self.camera.
|
|
387
|
-
self.camera.
|
|
388
|
-
self.camera.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
self.lights
|
|
396
|
-
self.lights.
|
|
397
|
-
self.lights.
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
self.
|
|
402
|
-
self.
|
|
403
|
-
self.
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
self.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
self.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
self.
|
|
438
|
-
self.
|
|
439
|
-
self.
|
|
440
|
-
self.
|
|
441
|
-
self.
|
|
442
|
-
self.
|
|
443
|
-
self.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
self.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
def
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
plt.
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
)
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
1
|
+
# Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
|
|
2
|
+
# NVIDIA CORPORATION and its licensors retain all intellectual property
|
|
3
|
+
# and proprietary rights in and to this software, related documentation
|
|
4
|
+
# and any modifications thereto. Any use, reproduction, disclosure or
|
|
5
|
+
# distribution of this software and related documentation without an express
|
|
6
|
+
# license agreement from NVIDIA CORPORATION is strictly prohibited.
|
|
7
|
+
|
|
8
|
+
#############################################################################
|
|
9
|
+
# Example Differentiable Ray Caster
|
|
10
|
+
#
|
|
11
|
+
# Shows how to use the built-in wp.Mesh data structure and wp.mesh_query_ray()
|
|
12
|
+
# function to implement a basic differentiable ray caster
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
|
|
16
|
+
import math
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
from pxr import Usd, UsdGeom
|
|
21
|
+
|
|
22
|
+
import warp as wp
|
|
23
|
+
import warp.examples
|
|
24
|
+
from warp.optim import SGD
|
|
25
|
+
|
|
26
|
+
wp.init()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class RenderMode:
|
|
30
|
+
"""Rendering modes
|
|
31
|
+
grayscale: Lambertian shading from multiple directional lights
|
|
32
|
+
texture: 2D texture map
|
|
33
|
+
normal_map: mesh normal computed from interpolated vertex normals
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
grayscale = 0
|
|
37
|
+
texture = 1
|
|
38
|
+
normal_map = 2
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@wp.struct
|
|
42
|
+
class RenderMesh:
|
|
43
|
+
"""Mesh to be ray casted.
|
|
44
|
+
Assumes a triangle mesh as input.
|
|
45
|
+
Per-vertex normals are computed with compute_vertex_normals()
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
id: wp.uint64
|
|
49
|
+
vertices: wp.array(dtype=wp.vec3)
|
|
50
|
+
indices: wp.array(dtype=int)
|
|
51
|
+
tex_coords: wp.array(dtype=wp.vec2)
|
|
52
|
+
tex_indices: wp.array(dtype=int)
|
|
53
|
+
vertex_normals: wp.array(dtype=wp.vec3)
|
|
54
|
+
pos: wp.array(dtype=wp.vec3)
|
|
55
|
+
rot: wp.array(dtype=wp.quat)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@wp.struct
|
|
59
|
+
class Camera:
|
|
60
|
+
"""Basic camera for ray casting"""
|
|
61
|
+
|
|
62
|
+
horizontal: float
|
|
63
|
+
vertical: float
|
|
64
|
+
aspect: float
|
|
65
|
+
e: float
|
|
66
|
+
tan: float
|
|
67
|
+
pos: wp.vec3
|
|
68
|
+
rot: wp.quat
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@wp.struct
|
|
72
|
+
class DirectionalLights:
|
|
73
|
+
"""Stores arrays of directional light directions and intensities."""
|
|
74
|
+
|
|
75
|
+
dirs: wp.array(dtype=wp.vec3)
|
|
76
|
+
intensities: wp.array(dtype=float)
|
|
77
|
+
num_lights: int
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@wp.kernel
|
|
81
|
+
def vertex_normal_sum_kernel(
|
|
82
|
+
verts: wp.array(dtype=wp.vec3), indices: wp.array(dtype=int), normal_sums: wp.array(dtype=wp.vec3)
|
|
83
|
+
):
|
|
84
|
+
tid = wp.tid()
|
|
85
|
+
|
|
86
|
+
i = indices[tid * 3]
|
|
87
|
+
j = indices[tid * 3 + 1]
|
|
88
|
+
k = indices[tid * 3 + 2]
|
|
89
|
+
|
|
90
|
+
a = verts[i]
|
|
91
|
+
b = verts[j]
|
|
92
|
+
c = verts[k]
|
|
93
|
+
|
|
94
|
+
ab = b - a
|
|
95
|
+
ac = c - a
|
|
96
|
+
|
|
97
|
+
area_normal = wp.cross(ab, ac)
|
|
98
|
+
wp.atomic_add(normal_sums, i, area_normal)
|
|
99
|
+
wp.atomic_add(normal_sums, j, area_normal)
|
|
100
|
+
wp.atomic_add(normal_sums, k, area_normal)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@wp.kernel
|
|
104
|
+
def normalize_kernel(
|
|
105
|
+
normal_sums: wp.array(dtype=wp.vec3),
|
|
106
|
+
vertex_normals: wp.array(dtype=wp.vec3),
|
|
107
|
+
):
|
|
108
|
+
tid = wp.tid()
|
|
109
|
+
vertex_normals[tid] = wp.normalize(normal_sums[tid])
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@wp.func
|
|
113
|
+
def texture_interpolation(tex_interp: wp.vec2, texture: wp.array2d(dtype=wp.vec3)):
|
|
114
|
+
tex_width = texture.shape[1]
|
|
115
|
+
tex_height = texture.shape[0]
|
|
116
|
+
tex = wp.vec2(tex_interp[0] * float(tex_width - 1), (1.0 - tex_interp[1]) * float(tex_height - 1))
|
|
117
|
+
|
|
118
|
+
x0 = int(tex[0])
|
|
119
|
+
x1 = x0 + 1
|
|
120
|
+
alpha_x = tex[0] - float(x0)
|
|
121
|
+
y0 = int(tex[1])
|
|
122
|
+
y1 = y0 + 1
|
|
123
|
+
alpha_y = tex[1] - float(y0)
|
|
124
|
+
c00 = texture[y0, x0]
|
|
125
|
+
c10 = texture[y0, x1]
|
|
126
|
+
c01 = texture[y1, x0]
|
|
127
|
+
c11 = texture[y1, x1]
|
|
128
|
+
lower = (1.0 - alpha_x) * c00 + alpha_x * c10
|
|
129
|
+
upper = (1.0 - alpha_x) * c01 + alpha_x * c11
|
|
130
|
+
color = (1.0 - alpha_y) * lower + alpha_y * upper
|
|
131
|
+
|
|
132
|
+
return color
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@wp.kernel
|
|
136
|
+
def draw_kernel(
|
|
137
|
+
mesh: RenderMesh,
|
|
138
|
+
camera: Camera,
|
|
139
|
+
texture: wp.array2d(dtype=wp.vec3),
|
|
140
|
+
rays_width: int,
|
|
141
|
+
rays_height: int,
|
|
142
|
+
rays: wp.array(dtype=wp.vec3),
|
|
143
|
+
lights: DirectionalLights,
|
|
144
|
+
mode: int,
|
|
145
|
+
):
|
|
146
|
+
tid = wp.tid()
|
|
147
|
+
|
|
148
|
+
x = tid % rays_width
|
|
149
|
+
y = rays_height - tid // rays_width
|
|
150
|
+
|
|
151
|
+
sx = 2.0 * float(x) / float(rays_width) - 1.0
|
|
152
|
+
sy = 2.0 * float(y) / float(rays_height) - 1.0
|
|
153
|
+
|
|
154
|
+
# compute view ray in world space
|
|
155
|
+
ro_world = camera.pos
|
|
156
|
+
rd_world = wp.normalize(wp.quat_rotate(camera.rot, wp.vec3(sx * camera.tan * camera.aspect, sy * camera.tan, -1.0)))
|
|
157
|
+
|
|
158
|
+
# compute view ray in mesh space
|
|
159
|
+
inv = wp.transform_inverse(wp.transform(mesh.pos[0], mesh.rot[0]))
|
|
160
|
+
ro = wp.transform_point(inv, ro_world)
|
|
161
|
+
rd = wp.transform_vector(inv, rd_world)
|
|
162
|
+
|
|
163
|
+
color = wp.vec3(0.0, 0.0, 0.0)
|
|
164
|
+
|
|
165
|
+
query = wp.mesh_query_ray(mesh.id, ro, rd, 1.0e6)
|
|
166
|
+
if query.result:
|
|
167
|
+
i = mesh.indices[query.face * 3]
|
|
168
|
+
j = mesh.indices[query.face * 3 + 1]
|
|
169
|
+
k = mesh.indices[query.face * 3 + 2]
|
|
170
|
+
|
|
171
|
+
a = mesh.vertices[i]
|
|
172
|
+
b = mesh.vertices[j]
|
|
173
|
+
c = mesh.vertices[k]
|
|
174
|
+
|
|
175
|
+
p = wp.mesh_eval_position(mesh.id, query.face, query.u, query.v)
|
|
176
|
+
|
|
177
|
+
# barycentric coordinates
|
|
178
|
+
tri_area = wp.length(wp.cross(b - a, c - a))
|
|
179
|
+
w = wp.length(wp.cross(b - a, p - a)) / tri_area
|
|
180
|
+
v = wp.length(wp.cross(p - a, c - a)) / tri_area
|
|
181
|
+
u = 1.0 - w - v
|
|
182
|
+
|
|
183
|
+
a_n = mesh.vertex_normals[i]
|
|
184
|
+
b_n = mesh.vertex_normals[j]
|
|
185
|
+
c_n = mesh.vertex_normals[k]
|
|
186
|
+
|
|
187
|
+
# vertex normal interpolation
|
|
188
|
+
normal = u * a_n + v * b_n + w * c_n
|
|
189
|
+
|
|
190
|
+
if mode == 0 or mode == 1:
|
|
191
|
+
if mode == 0: # grayscale
|
|
192
|
+
color = wp.vec3(1.0)
|
|
193
|
+
|
|
194
|
+
elif mode == 1: # texture interpolation
|
|
195
|
+
tex_a = mesh.tex_coords[mesh.tex_indices[query.face * 3]]
|
|
196
|
+
tex_b = mesh.tex_coords[mesh.tex_indices[query.face * 3 + 1]]
|
|
197
|
+
tex_c = mesh.tex_coords[mesh.tex_indices[query.face * 3 + 2]]
|
|
198
|
+
|
|
199
|
+
tex = u * tex_a + v * tex_b + w * tex_c
|
|
200
|
+
|
|
201
|
+
color = texture_interpolation(tex, texture)
|
|
202
|
+
|
|
203
|
+
# lambertian directional lighting
|
|
204
|
+
lambert = float(0.0)
|
|
205
|
+
for i in range(lights.num_lights):
|
|
206
|
+
dir = wp.transform_vector(inv, lights.dirs[i])
|
|
207
|
+
val = lights.intensities[i] * wp.dot(normal, dir)
|
|
208
|
+
if val < 0.0:
|
|
209
|
+
val = 0.0
|
|
210
|
+
lambert = lambert + val
|
|
211
|
+
|
|
212
|
+
color = lambert * color
|
|
213
|
+
|
|
214
|
+
elif mode == 2: # normal map
|
|
215
|
+
color = normal * 0.5 + wp.vec3(0.5, 0.5, 0.5)
|
|
216
|
+
|
|
217
|
+
if color[0] > 1.0:
|
|
218
|
+
color = wp.vec3(1.0, color[1], color[2])
|
|
219
|
+
if color[1] > 1.0:
|
|
220
|
+
color = wp.vec3(color[0], 1.0, color[2])
|
|
221
|
+
if color[2] > 1.0:
|
|
222
|
+
color = wp.vec3(color[0], color[1], 1.0)
|
|
223
|
+
|
|
224
|
+
rays[tid] = color
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@wp.kernel
|
|
228
|
+
def downsample_kernel(
|
|
229
|
+
rays: wp.array(dtype=wp.vec3), pixels: wp.array(dtype=wp.vec3), rays_width: int, num_samples: int
|
|
230
|
+
):
|
|
231
|
+
tid = wp.tid()
|
|
232
|
+
|
|
233
|
+
pixels_width = rays_width / num_samples
|
|
234
|
+
px = tid % pixels_width
|
|
235
|
+
py = tid // pixels_width
|
|
236
|
+
start_idx = py * num_samples * rays_width + px * num_samples
|
|
237
|
+
|
|
238
|
+
color = wp.vec3(0.0, 0.0, 0.0)
|
|
239
|
+
|
|
240
|
+
for i in range(0, num_samples):
|
|
241
|
+
for j in range(0, num_samples):
|
|
242
|
+
ray = rays[start_idx + i * rays_width + j]
|
|
243
|
+
color = wp.vec3(color[0] + ray[0], color[1] + ray[1], color[2] + ray[2])
|
|
244
|
+
|
|
245
|
+
num_samples_sq = float(num_samples * num_samples)
|
|
246
|
+
color = wp.vec3(color[0] / num_samples_sq, color[1] / num_samples_sq, color[2] / num_samples_sq)
|
|
247
|
+
pixels[tid] = color
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@wp.kernel
|
|
251
|
+
def loss_kernel(pixels: wp.array(dtype=wp.vec3), target_pixels: wp.array(dtype=wp.vec3), loss: wp.array(dtype=float)):
|
|
252
|
+
tid = wp.tid()
|
|
253
|
+
|
|
254
|
+
pixel = pixels[tid]
|
|
255
|
+
target_pixel = target_pixels[tid]
|
|
256
|
+
|
|
257
|
+
diff = target_pixel - pixel
|
|
258
|
+
|
|
259
|
+
# pseudo Huber loss
|
|
260
|
+
delta = 1.0
|
|
261
|
+
x = delta * delta * (wp.sqrt(1.0 + (diff[0] / delta) * (diff[0] / delta)) - 1.0)
|
|
262
|
+
y = delta * delta * (wp.sqrt(1.0 + (diff[1] / delta) * (diff[1] / delta)) - 1.0)
|
|
263
|
+
z = delta * delta * (wp.sqrt(1.0 + (diff[2] / delta) * (diff[2] / delta)) - 1.0)
|
|
264
|
+
sum = x + y + z
|
|
265
|
+
|
|
266
|
+
wp.atomic_add(loss, 0, sum)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@wp.kernel
|
|
270
|
+
def normalize(x: wp.array(dtype=wp.quat)):
|
|
271
|
+
tid = wp.tid()
|
|
272
|
+
|
|
273
|
+
x[tid] = wp.normalize(x[tid])
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class Example:
|
|
277
|
+
"""
|
|
278
|
+
Non-differentiable variables:
|
|
279
|
+
camera.horizontal: camera horizontal aperture size
|
|
280
|
+
camera.vertical: camera vertical aperture size
|
|
281
|
+
camera.aspect: camera aspect ratio
|
|
282
|
+
camera.e: focal length
|
|
283
|
+
camera.pos: camera displacement
|
|
284
|
+
camera.rot: camera rotation (quaternion)
|
|
285
|
+
pix_width: final image width in pixels
|
|
286
|
+
pix_height: final image height in pixels
|
|
287
|
+
num_samples: anti-aliasing. calculated as pow(2, num_samples)
|
|
288
|
+
directional_lights: characterized by intensity (scalar) and direction (vec3)
|
|
289
|
+
render_mesh.indices: mesh vertex indices
|
|
290
|
+
render_mesh.tex_indices: texture indices
|
|
291
|
+
|
|
292
|
+
Differentiable variables:
|
|
293
|
+
render_mesh.pos: parent transform displacement
|
|
294
|
+
render_mesh.quat: parent transform rotation (quaternion)
|
|
295
|
+
render_mesh.vertices: mesh vertex positions
|
|
296
|
+
render_mesh.vertex_normals: mesh vertex normals
|
|
297
|
+
render_mesh.tex_coords: 2D texture coordinates
|
|
298
|
+
"""
|
|
299
|
+
|
|
300
|
+
def __init__(self, height=1024, train_iters=150, rot_array=None):
|
|
301
|
+
cam_pos = wp.vec3(0.0, 0.75, 7.0)
|
|
302
|
+
cam_rot = wp.quat(0.0, 0.0, 0.0, 1.0)
|
|
303
|
+
horizontal_aperture = 36.0
|
|
304
|
+
vertical_aperture = 20.25
|
|
305
|
+
aspect = horizontal_aperture / vertical_aperture
|
|
306
|
+
focal_length = 50.0
|
|
307
|
+
self.height = height
|
|
308
|
+
self.width = int(aspect * self.height)
|
|
309
|
+
self.num_pixels = self.width * self.height
|
|
310
|
+
|
|
311
|
+
if rot_array is None:
|
|
312
|
+
rot_array = [0.0, 0.0, 0.0, 1.0]
|
|
313
|
+
|
|
314
|
+
asset_stage = Usd.Stage.Open(os.path.join(warp.examples.get_asset_directory(), "bunny.usd"))
|
|
315
|
+
mesh_geom = UsdGeom.Mesh(asset_stage.GetPrimAtPath("/root/bunny"))
|
|
316
|
+
|
|
317
|
+
points = np.array(mesh_geom.GetPointsAttr().Get())
|
|
318
|
+
indices = np.array(mesh_geom.GetFaceVertexIndicesAttr().Get())
|
|
319
|
+
num_points = points.shape[0]
|
|
320
|
+
num_faces = int(indices.shape[0] / 3)
|
|
321
|
+
|
|
322
|
+
# manufacture texture coordinates + indices for this asset
|
|
323
|
+
distance = np.linalg.norm(points, axis=1)
|
|
324
|
+
radius = np.max(distance)
|
|
325
|
+
distance = distance / radius
|
|
326
|
+
tex_coords = np.stack((distance, distance), axis=1)
|
|
327
|
+
tex_indices = indices
|
|
328
|
+
|
|
329
|
+
# manufacture texture for this asset
|
|
330
|
+
x = np.arange(256.0)
|
|
331
|
+
xx, yy = np.meshgrid(x, x)
|
|
332
|
+
zz = np.zeros_like(xx)
|
|
333
|
+
texture_host = np.stack((xx, yy, zz), axis=2) / 255.0
|
|
334
|
+
|
|
335
|
+
# set anti-aliasing
|
|
336
|
+
self.num_samples = 1
|
|
337
|
+
|
|
338
|
+
# set render mode
|
|
339
|
+
self.render_mode = RenderMode.texture
|
|
340
|
+
|
|
341
|
+
# set training iterations
|
|
342
|
+
self.train_rate = 5.00e-8
|
|
343
|
+
self.momentum = 0.5
|
|
344
|
+
self.dampening = 0.1
|
|
345
|
+
self.weight_decay = 0.0
|
|
346
|
+
self.train_iters = train_iters
|
|
347
|
+
self.period = 10 # Training iterations between render() calls
|
|
348
|
+
self.iter = 0
|
|
349
|
+
|
|
350
|
+
# storage for training animation
|
|
351
|
+
self.images = np.zeros((self.height, self.width, 3, max(int(self.train_iters / self.period), 1)))
|
|
352
|
+
self.image_counter = 0
|
|
353
|
+
|
|
354
|
+
# construct RenderMesh
|
|
355
|
+
self.render_mesh = RenderMesh()
|
|
356
|
+
self.mesh = wp.Mesh(
|
|
357
|
+
points=wp.array(points, dtype=wp.vec3, requires_grad=True), indices=wp.array(indices, dtype=int)
|
|
358
|
+
)
|
|
359
|
+
self.render_mesh.id = self.mesh.id
|
|
360
|
+
self.render_mesh.vertices = self.mesh.points
|
|
361
|
+
self.render_mesh.indices = self.mesh.indices
|
|
362
|
+
self.render_mesh.tex_coords = wp.array(tex_coords, dtype=wp.vec2, requires_grad=True)
|
|
363
|
+
self.render_mesh.tex_indices = wp.array(tex_indices, dtype=int)
|
|
364
|
+
self.normal_sums = wp.zeros(num_points, dtype=wp.vec3, requires_grad=True)
|
|
365
|
+
self.render_mesh.vertex_normals = wp.zeros(num_points, dtype=wp.vec3, requires_grad=True)
|
|
366
|
+
self.render_mesh.pos = wp.zeros(1, dtype=wp.vec3, requires_grad=True)
|
|
367
|
+
self.render_mesh.rot = wp.array(np.array(rot_array), dtype=wp.quat, requires_grad=True)
|
|
368
|
+
|
|
369
|
+
# compute vertex normals
|
|
370
|
+
wp.launch(
|
|
371
|
+
kernel=vertex_normal_sum_kernel,
|
|
372
|
+
dim=num_faces,
|
|
373
|
+
inputs=[self.render_mesh.vertices, self.render_mesh.indices, self.normal_sums],
|
|
374
|
+
)
|
|
375
|
+
wp.launch(
|
|
376
|
+
kernel=normalize_kernel,
|
|
377
|
+
dim=num_points,
|
|
378
|
+
inputs=[self.normal_sums, self.render_mesh.vertex_normals],
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# construct camera
|
|
382
|
+
self.camera = Camera()
|
|
383
|
+
self.camera.horizontal = horizontal_aperture
|
|
384
|
+
self.camera.vertical = vertical_aperture
|
|
385
|
+
self.camera.aspect = aspect
|
|
386
|
+
self.camera.e = focal_length
|
|
387
|
+
self.camera.tan = vertical_aperture / (2.0 * focal_length)
|
|
388
|
+
self.camera.pos = cam_pos
|
|
389
|
+
self.camera.rot = cam_rot
|
|
390
|
+
|
|
391
|
+
# construct texture
|
|
392
|
+
self.texture = wp.array2d(texture_host, dtype=wp.vec3, requires_grad=True)
|
|
393
|
+
|
|
394
|
+
# construct lights
|
|
395
|
+
self.lights = DirectionalLights()
|
|
396
|
+
self.lights.dirs = wp.array(np.array([[1.0, 0.0, 0.0], [0.0, 0.0, 1.0]]), dtype=wp.vec3, requires_grad=True)
|
|
397
|
+
self.lights.intensities = wp.array(np.array([2.0, 0.2]), dtype=float, requires_grad=True)
|
|
398
|
+
self.lights.num_lights = 2
|
|
399
|
+
|
|
400
|
+
# construct rays
|
|
401
|
+
self.rays_width = self.width * pow(2, self.num_samples)
|
|
402
|
+
self.rays_height = self.height * pow(2, self.num_samples)
|
|
403
|
+
self.num_rays = self.rays_width * self.rays_height
|
|
404
|
+
self.rays = wp.zeros(self.num_rays, dtype=wp.vec3, requires_grad=True)
|
|
405
|
+
|
|
406
|
+
# construct pixels
|
|
407
|
+
self.pixels = wp.zeros(self.num_pixels, dtype=wp.vec3, requires_grad=True)
|
|
408
|
+
self.target_pixels = wp.zeros(self.num_pixels, dtype=wp.vec3)
|
|
409
|
+
|
|
410
|
+
# loss array
|
|
411
|
+
self.loss = wp.zeros(1, dtype=float, requires_grad=True)
|
|
412
|
+
|
|
413
|
+
# capture graph
|
|
414
|
+
self.use_cuda_graph = wp.get_device().is_cuda
|
|
415
|
+
if self.use_cuda_graph:
|
|
416
|
+
with wp.ScopedCapture() as capture:
|
|
417
|
+
self.tape = wp.Tape()
|
|
418
|
+
with self.tape:
|
|
419
|
+
self.forward()
|
|
420
|
+
self.tape.backward(self.loss)
|
|
421
|
+
self.graph = capture.graph
|
|
422
|
+
|
|
423
|
+
self.optimizer = SGD(
|
|
424
|
+
[self.render_mesh.rot],
|
|
425
|
+
self.train_rate,
|
|
426
|
+
momentum=self.momentum,
|
|
427
|
+
dampening=self.dampening,
|
|
428
|
+
weight_decay=self.weight_decay,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
def ray_cast(self):
|
|
432
|
+
# raycast
|
|
433
|
+
wp.launch(
|
|
434
|
+
kernel=draw_kernel,
|
|
435
|
+
dim=self.num_rays,
|
|
436
|
+
inputs=[
|
|
437
|
+
self.render_mesh,
|
|
438
|
+
self.camera,
|
|
439
|
+
self.texture,
|
|
440
|
+
self.rays_width,
|
|
441
|
+
self.rays_height,
|
|
442
|
+
self.rays,
|
|
443
|
+
self.lights,
|
|
444
|
+
self.render_mode,
|
|
445
|
+
],
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
# downsample
|
|
449
|
+
wp.launch(
|
|
450
|
+
kernel=downsample_kernel,
|
|
451
|
+
dim=self.num_pixels,
|
|
452
|
+
inputs=[self.rays, self.pixels, self.rays_width, pow(2, self.num_samples)],
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
def forward(self):
|
|
456
|
+
self.ray_cast()
|
|
457
|
+
|
|
458
|
+
# compute pixel loss
|
|
459
|
+
wp.launch(loss_kernel, dim=self.num_pixels, inputs=[self.pixels, self.target_pixels, self.loss])
|
|
460
|
+
|
|
461
|
+
def step(self):
|
|
462
|
+
with wp.ScopedTimer("step"):
|
|
463
|
+
if self.use_cuda_graph:
|
|
464
|
+
wp.capture_launch(self.graph)
|
|
465
|
+
else:
|
|
466
|
+
self.tape = wp.Tape()
|
|
467
|
+
with self.tape:
|
|
468
|
+
self.forward()
|
|
469
|
+
self.tape.backward(self.loss)
|
|
470
|
+
|
|
471
|
+
rot_grad = self.tape.gradients[self.render_mesh.rot]
|
|
472
|
+
self.optimizer.step([rot_grad])
|
|
473
|
+
wp.launch(normalize, dim=1, inputs=[self.render_mesh.rot])
|
|
474
|
+
|
|
475
|
+
if self.iter % self.period == 0:
|
|
476
|
+
print(f"Iter: {self.iter} Loss: {self.loss}")
|
|
477
|
+
|
|
478
|
+
self.tape.zero()
|
|
479
|
+
self.loss.zero_()
|
|
480
|
+
|
|
481
|
+
self.iter = self.iter + 1
|
|
482
|
+
|
|
483
|
+
def render(self):
|
|
484
|
+
with wp.ScopedTimer("render"):
|
|
485
|
+
self.images[:, :, :, self.image_counter] = self.get_image()
|
|
486
|
+
self.image_counter += 1
|
|
487
|
+
|
|
488
|
+
def get_image(self):
|
|
489
|
+
return self.pixels.numpy().reshape((self.height, self.width, 3))
|
|
490
|
+
|
|
491
|
+
def get_animation(self):
|
|
492
|
+
fig, ax = plt.subplots()
|
|
493
|
+
plt.axis("off")
|
|
494
|
+
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
|
|
495
|
+
plt.margins(0, 0)
|
|
496
|
+
|
|
497
|
+
frames = []
|
|
498
|
+
for i in range(self.images.shape[3]):
|
|
499
|
+
frame = ax.imshow(self.images[:, :, :, i], animated=True)
|
|
500
|
+
frames.append([frame])
|
|
501
|
+
|
|
502
|
+
ani = animation.ArtistAnimation(fig, frames, interval=50, blit=True, repeat_delay=1000)
|
|
503
|
+
return ani
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
if __name__ == "__main__":
|
|
507
|
+
import argparse
|
|
508
|
+
|
|
509
|
+
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
510
|
+
parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
|
|
511
|
+
parser.add_argument("--train_iters", type=int, default=150, help="Total number of training iterations.")
|
|
512
|
+
parser.add_argument("--height", type=int, default=1024, help="Height of rendered image in pixels.")
|
|
513
|
+
parser.add_argument(
|
|
514
|
+
"--headless",
|
|
515
|
+
action="store_true",
|
|
516
|
+
help="Run in headless mode, suppressing the opening of any graphical windows.",
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
args = parser.parse_known_args()[0]
|
|
520
|
+
|
|
521
|
+
with wp.ScopedDevice(args.device):
|
|
522
|
+
reference_example = Example(height=args.height)
|
|
523
|
+
|
|
524
|
+
# render target rotation
|
|
525
|
+
reference_example.ray_cast()
|
|
526
|
+
|
|
527
|
+
# offset mesh rotation
|
|
528
|
+
example = Example(
|
|
529
|
+
train_iters=args.train_iters,
|
|
530
|
+
height=args.height,
|
|
531
|
+
rot_array=[
|
|
532
|
+
0.0,
|
|
533
|
+
(math.sqrt(3) - 1) / (2.0 * math.sqrt(2.0)),
|
|
534
|
+
0.0,
|
|
535
|
+
(math.sqrt(3) + 1) / (2.0 * math.sqrt(2.0)),
|
|
536
|
+
],
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
wp.copy(example.target_pixels, reference_example.pixels)
|
|
540
|
+
|
|
541
|
+
# recover target rotation
|
|
542
|
+
for i in range(example.train_iters):
|
|
543
|
+
example.step()
|
|
544
|
+
|
|
545
|
+
if i % example.period == 0:
|
|
546
|
+
example.render()
|
|
547
|
+
|
|
548
|
+
if not args.headless:
|
|
549
|
+
import matplotlib.animation as animation
|
|
550
|
+
import matplotlib.image as img
|
|
551
|
+
import matplotlib.pyplot as plt
|
|
552
|
+
|
|
553
|
+
target_image = reference_example.get_image()
|
|
554
|
+
target_image_filename = "example_diffray_target_image.png"
|
|
555
|
+
img.imsave(target_image_filename, target_image)
|
|
556
|
+
print(f"Saved the target image at `{target_image_filename}`")
|
|
557
|
+
|
|
558
|
+
final_image = example.get_image()
|
|
559
|
+
final_image_filename = "example_diffray_final_image.png"
|
|
560
|
+
img.imsave(final_image_filename, final_image)
|
|
561
|
+
print(f"Saved the final image at `{final_image_filename}`")
|
|
562
|
+
|
|
563
|
+
anim = example.get_animation()
|
|
564
|
+
anim_filename = "example_diffray_animation.gif"
|
|
565
|
+
anim.save(anim_filename, dpi=300, writer=animation.PillowWriter(fps=5))
|
|
566
|
+
print(f"Saved the animation at `{anim_filename}`")
|