cgmath 1.0.4__tar.gz → 3.0.0__tar.gz
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.
- {cgmath-1.0.4/cgmath.egg-info → cgmath-3.0.0}/PKG-INFO +40 -9
- {cgmath-1.0.4 → cgmath-3.0.0}/README.md +39 -8
- {cgmath-1.0.4 → cgmath-3.0.0}/__init__.py +1 -1
- cgmath-3.0.0/_tests/__init__.py +1 -0
- cgmath-3.0.0/_tests/_examples_curves.py +198 -0
- cgmath-3.0.0/_tests/_examples_deform.py +171 -0
- cgmath-3.0.0/_tests/_examples_geometry.py +366 -0
- cgmath-3.0.0/_tests/_examples_hierarchy.py +280 -0
- cgmath-3.0.0/_tests/_examples_render.py +268 -0
- cgmath-3.0.0/_tests/_maya_rotate_order.py +64 -0
- cgmath-3.0.0/_tests/test_assets/maya_euler.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/mikktspace_deformed_data.json +1331 -0
- cgmath-3.0.0/_tests/test_assets/mikktspace_test_data.json +1836 -0
- cgmath-3.0.0/_tests/test_assets/test_data_module.curve.pkl +0 -0
- cgmath-3.0.0/_tests/test_assets/test_data_module.mesh.pkl +0 -0
- cgmath-3.0.0/_tests/test_assets/test_data_module.patch.pkl +0 -0
- cgmath-3.0.0/_tests/test_assets/test_data_module.saved_by_2_0_0.zip +0 -0
- cgmath-3.0.0/_tests/test_assets/test_geometry.bspline_best_fit_params.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_geometry.bspline_maya_curves.json +67 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.json +136 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node.pkl +0 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.legacy_parent_node_clip.json +331 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.results.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_hierarchy.skeleton.json +1064 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.bitmap_buffer.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.source_mesh_data.json +1547 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.source_uv_list.json +2349 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_ngons_only.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_mesh_data_preserve_order_ngons_only.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_ngons_only.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_ngon.triangulate_uv_list_preserve_order_ngons_only.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.dst_bs_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.dst_mesh_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.dst_skin_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.dst_uv_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.overlap.pkl +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.src_bs_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.src_mesh_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.src_skin_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_resample.src_uv_data.npz +0 -0
- cgmath-3.0.0/_tests/test_assets/test_sdf.igloo.npz +0 -0
- cgmath-3.0.0/_tests/test_base.py +1689 -0
- cgmath-3.0.0/_tests/test_base_setattr.py +1144 -0
- cgmath-3.0.0/_tests/test_bspline_kernels.py +333 -0
- cgmath-3.0.0/_tests/test_clip.py +12395 -0
- cgmath-3.0.0/_tests/test_constraints.py +96 -0
- cgmath-3.0.0/_tests/test_curves_empty.py +90 -0
- cgmath-3.0.0/_tests/test_curves_types.py +538 -0
- cgmath-3.0.0/_tests/test_data_module.py +390 -0
- cgmath-3.0.0/_tests/test_deform_files.py +314 -0
- cgmath-3.0.0/_tests/test_deform_utils.py +349 -0
- cgmath-3.0.0/_tests/test_delta_mush.py +538 -0
- cgmath-3.0.0/_tests/test_euler_maya.py +210 -0
- cgmath-3.0.0/_tests/test_fbx_export.py +1216 -0
- cgmath-3.0.0/_tests/test_fbx_import.py +983 -0
- cgmath-3.0.0/_tests/test_fbx_labels.py +1284 -0
- cgmath-3.0.0/_tests/test_fbx_lifetime.py +1026 -0
- cgmath-3.0.0/_tests/test_ffd.py +573 -0
- cgmath-3.0.0/_tests/test_file_routes.py +1031 -0
- cgmath-3.0.0/_tests/test_geometry.py +7428 -0
- cgmath-3.0.0/_tests/test_geometry_io.py +215 -0
- cgmath-3.0.0/_tests/test_geometry_utils.py +360 -0
- cgmath-3.0.0/_tests/test_glb.py +336 -0
- cgmath-3.0.0/_tests/test_glb_materials.py +182 -0
- cgmath-3.0.0/_tests/test_hierarchy.py +6688 -0
- cgmath-3.0.0/_tests/test_hierarchy_io.py +317 -0
- cgmath-3.0.0/_tests/test_import_order.py +116 -0
- cgmath-3.0.0/_tests/test_imports.py +520 -0
- cgmath-3.0.0/_tests/test_list_item_class.py +368 -0
- cgmath-3.0.0/_tests/test_map.py +91 -0
- cgmath-3.0.0/_tests/test_mesh_usd.py +58 -0
- cgmath-3.0.0/_tests/test_morph_target.py +1106 -0
- cgmath-3.0.0/_tests/test_namespaces.py +235 -0
- cgmath-3.0.0/_tests/test_ngon.py +163 -0
- cgmath-3.0.0/_tests/test_normals_quadmatch_utils.py +287 -0
- cgmath-3.0.0/_tests/test_object_skin.py +1312 -0
- cgmath-3.0.0/_tests/test_pack.py +206 -0
- cgmath-3.0.0/_tests/test_parent_lookups.py +393 -0
- cgmath-3.0.0/_tests/test_patch_relax.py +607 -0
- cgmath-3.0.0/_tests/test_procrustes_rotation.py +189 -0
- cgmath-3.0.0/_tests/test_quadrangulate.py +517 -0
- cgmath-3.0.0/_tests/test_raycast.py +1157 -0
- cgmath-3.0.0/_tests/test_raycast_bvh.py +193 -0
- cgmath-3.0.0/_tests/test_rbf.py +540 -0
- cgmath-3.0.0/_tests/test_render_cache.py +220 -0
- cgmath-3.0.0/_tests/test_render_fit_padding.py +343 -0
- cgmath-3.0.0/_tests/test_render_roundtrip_extra.py +143 -0
- cgmath-3.0.0/_tests/test_render_serialization.py +512 -0
- cgmath-3.0.0/_tests/test_render_threads.py +1684 -0
- cgmath-3.0.0/_tests/test_resample.py +1112 -0
- cgmath-3.0.0/_tests/test_resample_bezier.py +218 -0
- cgmath-3.0.0/_tests/test_robust_skinweights_transfer_bilinear.py +310 -0
- cgmath-3.0.0/_tests/test_roundtrip.py +1073 -0
- cgmath-3.0.0/_tests/test_saddle_surface.py +480 -0
- cgmath-3.0.0/_tests/test_scene.py +4068 -0
- cgmath-3.0.0/_tests/test_scene_animate.py +702 -0
- cgmath-3.0.0/_tests/test_sdf.py +379 -0
- cgmath-3.0.0/_tests/test_short_names.py +1329 -0
- cgmath-3.0.0/_tests/test_skin_deform.py +1506 -0
- cgmath-3.0.0/_tests/test_skin_fbx.py +322 -0
- cgmath-3.0.0/_tests/test_skin_glb.py +538 -0
- cgmath-3.0.0/_tests/test_skin_kernels.py +323 -0
- cgmath-3.0.0/_tests/test_skin_weights.py +1174 -0
- cgmath-3.0.0/_tests/test_symmetry.py +157 -0
- cgmath-3.0.0/_tests/test_triangulation.py +108 -0
- cgmath-3.0.0/_tests/test_usd_prim.py +47 -0
- cgmath-3.0.0/_tests/test_utils.py +686 -0
- cgmath-3.0.0/_tests/test_wrap.py +299 -0
- {cgmath-1.0.4 → cgmath-3.0.0/cgmath.egg-info}/PKG-INFO +40 -9
- cgmath-3.0.0/cgmath.egg-info/SOURCES.txt +410 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/constraints/procrustes.py +36 -22
- cgmath-3.0.0/data.py +3292 -0
- cgmath-3.0.0/formats/_fbx_io.py +186 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/fbx.py +748 -171
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/glb.py +50 -4
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/__init__.py +1 -1
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/_saddle_surface.py +109 -63
- cgmath-3.0.0/geometry/bspline.py +2544 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/bspline_patch.py +941 -112
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/delta_mush.py +101 -98
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/ffd.py +63 -28
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/patch_relax.py +59 -52
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/skin_deform.py +182 -72
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/wrap.py +56 -28
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/map.py +18 -16
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/mesh.py +887 -278
- cgmath-3.0.0/geometry/morph_target.py +674 -0
- cgmath-3.0.0/geometry/resample.py +707 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/sdf.py +88 -19
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/skin_weights.py +285 -169
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/__init__.py +1 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_bilinear.py +1095 -254
- cgmath-3.0.0/geometry/utils/_numba/_bspline.py +4161 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_cdt.py +17 -2
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_ffd.py +1 -1
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_main.py +2 -0
- cgmath-3.0.0/geometry/utils/_numba/_skin_deform.py +831 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_skin_weights.py +2 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_topology.py +44 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/main.py +186 -8
- {cgmath-1.0.4 → cgmath-3.0.0}/hierarchy/__init__.py +8 -3
- cgmath-3.0.0/hierarchy/hierarchy.py +13058 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/pyproject.toml +14 -4
- cgmath-3.0.0/render/_tiles.py +757 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/raytracer.py +76 -11
- {cgmath-1.0.4 → cgmath-3.0.0}/render/scene.py +1017 -419
- cgmath-3.0.0/transforms/_numba/__init__.py +116 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_axis.py +2 -2
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_euler.py +69 -4
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_matrix.py +8 -8
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/_numba/_quaternion.py +142 -43
- cgmath-3.0.0/transforms/_numba/_vector.py +413 -0
- cgmath-3.0.0/transforms/_tests/__init__.py +1 -0
- cgmath-3.0.0/transforms/_tests/test_axis.py +167 -0
- cgmath-3.0.0/transforms/_tests/test_broadcasting.py +357 -0
- cgmath-3.0.0/transforms/_tests/test_euler.py +411 -0
- cgmath-3.0.0/transforms/_tests/test_exports.py +43 -0
- cgmath-3.0.0/transforms/_tests/test_matrix.py +125 -0
- cgmath-3.0.0/transforms/_tests/test_quaternion.py +137 -0
- cgmath-3.0.0/transforms/_tests/test_rotation_conversions.py +403 -0
- cgmath-3.0.0/transforms/_tests/test_slerp.py +909 -0
- cgmath-3.0.0/transforms/_tests/test_threads.py +392 -0
- cgmath-3.0.0/transforms/_tests/test_vector.py +183 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/main.py +248 -93
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/utils.py +1 -1
- {cgmath-1.0.4 → cgmath-3.0.0}/utils.py +252 -33
- cgmath-1.0.4/cgmath.egg-info/SOURCES.txt +0 -178
- cgmath-1.0.4/geometry/_base.py +0 -890
- cgmath-1.0.4/geometry/bspline.py +0 -1225
- cgmath-1.0.4/geometry/camera.py +0 -38
- cgmath-1.0.4/geometry/delta_mush.py +0 -29
- cgmath-1.0.4/geometry/ffd.py +0 -29
- cgmath-1.0.4/geometry/morph_target.py +0 -494
- cgmath-1.0.4/geometry/patch_relax.py +0 -29
- cgmath-1.0.4/geometry/raytracer.py +0 -38
- cgmath-1.0.4/geometry/resample.py +0 -393
- cgmath-1.0.4/geometry/surface_plotting.py +0 -1077
- cgmath-1.0.4/geometry/texture.py +0 -29
- cgmath-1.0.4/geometry/utils/_numba/_bspline.py +0 -2350
- cgmath-1.0.4/geometry/utils/_numba/_skin_deform.py +0 -535
- cgmath-1.0.4/hierarchy/hierarchy.py +0 -3841
- cgmath-1.0.4/transforms/_numba/__init__.py +0 -15
- cgmath-1.0.4/transforms/_numba/_vector.py +0 -266
- {cgmath-1.0.4 → cgmath-3.0.0}/LICENSE +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/dependency_links.txt +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/requires.txt +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/cgmath.egg-info/top_level.txt +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/constraints/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/prim.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/formats/usd/stage.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/_cdt.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/deform/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/pack.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/robust_skinweights_transfer_bilinear.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_blur.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_bvh.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_connectivity.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_delta_mush.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_normals.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_pack.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_patch_relax.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_rasterize.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_sdf.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_subdivide.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_subdivision.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_tangent_space.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/geometry/utils/_numba/_wrap.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/rbf/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_kernels.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/_kernels.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/rbf/_numba/_lu.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/_numba/__init__.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/_numba/_texture.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/camera.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/frame.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/render/texture.py +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/setup.cfg +0 -0
- {cgmath-1.0.4 → cgmath-3.0.0}/transforms/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cgmath
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: A DCC-agnostic CG math library: batched matrix, quaternion and euler math, mesh topology, deformers, resampling, skeletal hierarchies, SDFs, a software raytracer and asset IO, all numpy-native.
|
|
5
5
|
Author-email: Eric Vignola <eric.vignola@gmail.com>
|
|
6
6
|
License: ## License
|
|
@@ -133,8 +133,9 @@ for it) and a **CHEATSHEET** (every public name, with a runnable example).
|
|
|
133
133
|
| `cgmath.constraints` | `ProcrustesData` — rivet a transform to a deforming patch | [README](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/README.md) · [CHEATSHEET](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/CHEATSHEET.md) |
|
|
134
134
|
|
|
135
135
|
[`REFERENCE.md`](https://github.com/Eric-Vignola/cgmath/blob/main/REFERENCE.md), a flat API listing, also sits in this
|
|
136
|
-
directory. It is generated from the live code by `gen_reference.py` (kept
|
|
137
|
-
|
|
136
|
+
directory. It is generated from the live code by `gen_reference.py` (kept
|
|
137
|
+
outside this repository, in the maintainer's own tools folder; the
|
|
138
|
+
repository's `tools/` holds only the Maya fixture generator): every public
|
|
138
139
|
name with its real signature and first docstring line.
|
|
139
140
|
|
|
140
141
|
---
|
|
@@ -146,6 +147,7 @@ name with its real signature and first docstring line.
|
|
|
146
147
|
|
|
147
148
|
```
|
|
148
149
|
cgmath/
|
|
150
|
+
├── data.py Data / DataList / Array / ImmutableArray + serialization
|
|
149
151
|
├── utils.py info() / docstring(), pretty_json, profile(), run_tests()
|
|
150
152
|
│
|
|
151
153
|
├── hierarchy/ TransformData, TransformList, HierarchyData, ClipData
|
|
@@ -153,15 +155,12 @@ cgmath/
|
|
|
153
155
|
│ └── hierarchy.py the four types, the fbx / glb readers, the batched clip evaluator
|
|
154
156
|
│
|
|
155
157
|
├── geometry/ meshes, UVs, curves, fields, transfer
|
|
156
|
-
│ ├── _base.py Data / DataList / ImmutableArray + serialization
|
|
157
158
|
│ ├── mesh.py MeshData, MeshList, UVData, UVList, the loaders
|
|
158
159
|
│ ├── map.py morph_target.py skin_weights.py MapData, MorphData, SkinData
|
|
159
160
|
│ ├── bspline.py bspline_patch.py _saddle_surface.py _cdt.py
|
|
160
161
|
│ ├── sdf.py SDF primitives + dual marching cubes
|
|
161
|
-
│ ├── pack.py resample.py
|
|
162
|
+
│ ├── pack.py resample.py
|
|
162
163
|
│ ├── robust_skinweights_transfer_bilinear.py
|
|
163
|
-
│ ├── camera.py delta_mush.py ffd.py patch_relax.py raytracer.py texture.py
|
|
164
|
-
│ │ one-release deprecation shims -- they warn and re-export
|
|
165
164
|
│ ├── deform/ FFDData, DeltaMushData, PatchRelaxData,
|
|
166
165
|
│ │ SkinDeformData, WrapData
|
|
167
166
|
│ └── utils/ main.py + _numba/ -- the kernel floor
|
|
@@ -170,7 +169,10 @@ cgmath/
|
|
|
170
169
|
├── render/ scene.py raytracer.py camera.py frame.py texture.py
|
|
171
170
|
├── formats/ fbx.py, glb.py, usd/prim.py, usd/stage.py
|
|
172
171
|
├── rbf/ _kernels.py + _numba/ (__init__.py is a docstring, on purpose)
|
|
173
|
-
|
|
172
|
+
├── constraints/ procrustes.py
|
|
173
|
+
│
|
|
174
|
+
└── _tests/ the test suite + test_assets/, the fixtures it reads;
|
|
175
|
+
transforms/_tests/ holds the transforms suite
|
|
174
176
|
```
|
|
175
177
|
|
|
176
178
|
The batched matrix / quaternion / euler / axis / vector functions that all
|
|
@@ -225,6 +227,13 @@ If you know Maya, nothing below will surprise you.
|
|
|
225
227
|
face and a raycast miss.
|
|
226
228
|
- **A mesh is a face-vertex stream**, `indices` + `counts` + `points`.
|
|
227
229
|
Mixed triangles, quads and n-gons in one mesh are normal.
|
|
230
|
+
- **Arrays have fixed dtypes.** Indices and counts are `int32`; points,
|
|
231
|
+
normals, offsets, weights and values are `float64`; masks are `bool`. A
|
|
232
|
+
value is converted when it is set or loaded.
|
|
233
|
+
- **One saved form.** `.pkl`, `.npz` and `.json` hold the same tree and
|
|
234
|
+
load as the class they name. A file written by an older cgmath raises
|
|
235
|
+
`LegacyFileError` — details in
|
|
236
|
+
[`geometry/README.md`](https://github.com/Eric-Vignola/cgmath/blob/main/geometry/README.md#saving-and-loading).
|
|
228
237
|
- **Camera is OpenGL**: `-Z` forward, `+Y` up, `+X` right. `look_at()`
|
|
229
238
|
and `Frame.camera_matrix` are **column**-major (eye at `M[:3, 3]`)
|
|
230
239
|
while node matrices are row-major (eye at `M[3, :3]`).
|
|
@@ -275,7 +284,7 @@ Each block below builds on the `cube` from the top of this page.
|
|
|
275
284
|
```python
|
|
276
285
|
print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
|
|
277
286
|
print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
|
|
278
|
-
print(cube.get_border_vertices(flatten=True)) # [] -- closed
|
|
287
|
+
print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
|
|
279
288
|
print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
|
|
280
289
|
```
|
|
281
290
|
|
|
@@ -399,6 +408,28 @@ second `pxr` on `sys.path` conflicts with the one the host has loaded.
|
|
|
399
408
|
The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
|
|
400
409
|
|
|
401
410
|
|
|
411
|
+
## Tests
|
|
412
|
+
|
|
413
|
+
Both test suites ship in the wheel, `cgmath._tests` with the fixtures it
|
|
414
|
+
reads and `cgmath.transforms._tests`, so an installed copy tests itself as a
|
|
415
|
+
checkout does. `run_tests()` with no target runs both suites; a module, a
|
|
416
|
+
class, one test or a filename glob narrows it, found in whichever suite
|
|
417
|
+
holds it:
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
from cgmath.utils import run_tests
|
|
421
|
+
|
|
422
|
+
result = run_tests("test_exports", verbosity=0) # one module of the transforms suite
|
|
423
|
+
assert result.wasSuccessful()
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
From a shell, `python -m cgmath.utils` runs everything and exits 0 when it
|
|
427
|
+
all passes. A test that needs an optional dependency the install lacks,
|
|
428
|
+
such as the FBX SDK, `pxr`, Pillow or pygltflib, is skipped, so a plain
|
|
429
|
+
`pip install cgmath` passes too, with more tests skipped than under
|
|
430
|
+
`cgmath[all]`.
|
|
431
|
+
|
|
432
|
+
|
|
402
433
|
## Author
|
|
403
434
|
|
|
404
435
|
* **Eric Vignola** (eric.vignola@gmail.com)
|
|
@@ -61,8 +61,9 @@ for it) and a **CHEATSHEET** (every public name, with a runnable example).
|
|
|
61
61
|
| `cgmath.constraints` | `ProcrustesData` — rivet a transform to a deforming patch | [README](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/README.md) · [CHEATSHEET](https://github.com/Eric-Vignola/cgmath/blob/main/constraints/CHEATSHEET.md) |
|
|
62
62
|
|
|
63
63
|
[`REFERENCE.md`](https://github.com/Eric-Vignola/cgmath/blob/main/REFERENCE.md), a flat API listing, also sits in this
|
|
64
|
-
directory. It is generated from the live code by `gen_reference.py` (kept
|
|
65
|
-
|
|
64
|
+
directory. It is generated from the live code by `gen_reference.py` (kept
|
|
65
|
+
outside this repository, in the maintainer's own tools folder; the
|
|
66
|
+
repository's `tools/` holds only the Maya fixture generator): every public
|
|
66
67
|
name with its real signature and first docstring line.
|
|
67
68
|
|
|
68
69
|
---
|
|
@@ -74,6 +75,7 @@ name with its real signature and first docstring line.
|
|
|
74
75
|
|
|
75
76
|
```
|
|
76
77
|
cgmath/
|
|
78
|
+
├── data.py Data / DataList / Array / ImmutableArray + serialization
|
|
77
79
|
├── utils.py info() / docstring(), pretty_json, profile(), run_tests()
|
|
78
80
|
│
|
|
79
81
|
├── hierarchy/ TransformData, TransformList, HierarchyData, ClipData
|
|
@@ -81,15 +83,12 @@ cgmath/
|
|
|
81
83
|
│ └── hierarchy.py the four types, the fbx / glb readers, the batched clip evaluator
|
|
82
84
|
│
|
|
83
85
|
├── geometry/ meshes, UVs, curves, fields, transfer
|
|
84
|
-
│ ├── _base.py Data / DataList / ImmutableArray + serialization
|
|
85
86
|
│ ├── mesh.py MeshData, MeshList, UVData, UVList, the loaders
|
|
86
87
|
│ ├── map.py morph_target.py skin_weights.py MapData, MorphData, SkinData
|
|
87
88
|
│ ├── bspline.py bspline_patch.py _saddle_surface.py _cdt.py
|
|
88
89
|
│ ├── sdf.py SDF primitives + dual marching cubes
|
|
89
|
-
│ ├── pack.py resample.py
|
|
90
|
+
│ ├── pack.py resample.py
|
|
90
91
|
│ ├── robust_skinweights_transfer_bilinear.py
|
|
91
|
-
│ ├── camera.py delta_mush.py ffd.py patch_relax.py raytracer.py texture.py
|
|
92
|
-
│ │ one-release deprecation shims -- they warn and re-export
|
|
93
92
|
│ ├── deform/ FFDData, DeltaMushData, PatchRelaxData,
|
|
94
93
|
│ │ SkinDeformData, WrapData
|
|
95
94
|
│ └── utils/ main.py + _numba/ -- the kernel floor
|
|
@@ -98,7 +97,10 @@ cgmath/
|
|
|
98
97
|
├── render/ scene.py raytracer.py camera.py frame.py texture.py
|
|
99
98
|
├── formats/ fbx.py, glb.py, usd/prim.py, usd/stage.py
|
|
100
99
|
├── rbf/ _kernels.py + _numba/ (__init__.py is a docstring, on purpose)
|
|
101
|
-
|
|
100
|
+
├── constraints/ procrustes.py
|
|
101
|
+
│
|
|
102
|
+
└── _tests/ the test suite + test_assets/, the fixtures it reads;
|
|
103
|
+
transforms/_tests/ holds the transforms suite
|
|
102
104
|
```
|
|
103
105
|
|
|
104
106
|
The batched matrix / quaternion / euler / axis / vector functions that all
|
|
@@ -153,6 +155,13 @@ If you know Maya, nothing below will surprise you.
|
|
|
153
155
|
face and a raycast miss.
|
|
154
156
|
- **A mesh is a face-vertex stream**, `indices` + `counts` + `points`.
|
|
155
157
|
Mixed triangles, quads and n-gons in one mesh are normal.
|
|
158
|
+
- **Arrays have fixed dtypes.** Indices and counts are `int32`; points,
|
|
159
|
+
normals, offsets, weights and values are `float64`; masks are `bool`. A
|
|
160
|
+
value is converted when it is set or loaded.
|
|
161
|
+
- **One saved form.** `.pkl`, `.npz` and `.json` hold the same tree and
|
|
162
|
+
load as the class they name. A file written by an older cgmath raises
|
|
163
|
+
`LegacyFileError` — details in
|
|
164
|
+
[`geometry/README.md`](https://github.com/Eric-Vignola/cgmath/blob/main/geometry/README.md#saving-and-loading).
|
|
156
165
|
- **Camera is OpenGL**: `-Z` forward, `+Y` up, `+X` right. `look_at()`
|
|
157
166
|
and `Frame.camera_matrix` are **column**-major (eye at `M[:3, 3]`)
|
|
158
167
|
while node matrices are row-major (eye at `M[3, :3]`).
|
|
@@ -203,7 +212,7 @@ Each block below builds on the `cube` from the top of this page.
|
|
|
203
212
|
```python
|
|
204
213
|
print(cube.point_count, cube.face_count, cube.edge_count) # 8 6 12
|
|
205
214
|
print(cube.closed, cube.quads, round(cube.area, 4)) # True 6 6.0
|
|
206
|
-
print(cube.get_border_vertices(flatten=True)) # [] -- closed
|
|
215
|
+
print(cube.get_border_vertices(flatten=True)) # [] -- closed, an empty int32 array
|
|
207
216
|
print(cube.e2v.shape, cube.ue2v.shape) # (12, 2) deduped vs (24, 2) raw
|
|
208
217
|
```
|
|
209
218
|
|
|
@@ -327,6 +336,28 @@ second `pxr` on `sys.path` conflicts with the one the host has loaded.
|
|
|
327
336
|
The Autodesk FBX SDK (FBX read and write) is not on PyPI; install it by hand.
|
|
328
337
|
|
|
329
338
|
|
|
339
|
+
## Tests
|
|
340
|
+
|
|
341
|
+
Both test suites ship in the wheel, `cgmath._tests` with the fixtures it
|
|
342
|
+
reads and `cgmath.transforms._tests`, so an installed copy tests itself as a
|
|
343
|
+
checkout does. `run_tests()` with no target runs both suites; a module, a
|
|
344
|
+
class, one test or a filename glob narrows it, found in whichever suite
|
|
345
|
+
holds it:
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
from cgmath.utils import run_tests
|
|
349
|
+
|
|
350
|
+
result = run_tests("test_exports", verbosity=0) # one module of the transforms suite
|
|
351
|
+
assert result.wasSuccessful()
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
From a shell, `python -m cgmath.utils` runs everything and exits 0 when it
|
|
355
|
+
all passes. A test that needs an optional dependency the install lacks,
|
|
356
|
+
such as the FBX SDK, `pxr`, Pillow or pygltflib, is skipped, so a plain
|
|
357
|
+
`pip install cgmath` passes too, with more tests skipped than under
|
|
358
|
+
`cgmath[all]`.
|
|
359
|
+
|
|
360
|
+
|
|
330
361
|
## Author
|
|
331
362
|
|
|
332
363
|
* **Eric Vignola** (eric.vignola@gmail.com)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Unit tests for the :mod:`cgmath` package."""
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Round-trip builders for the curve and surface data: BSplineData and its
|
|
3
|
+
sample, BSplinePatchData and its sample and raycast, the saddle surface's
|
|
4
|
+
sample and raycast, and ProcrustesData.
|
|
5
|
+
|
|
6
|
+
Each builder makes a new object the way users do, through the public
|
|
7
|
+
constructors, fit, sample and raycast, with every saved field away from its
|
|
8
|
+
default where that is valid. ``test_roundtrip`` saves and loads each one.
|
|
9
|
+
None of these classes has a name or nested data. Their arrays share one
|
|
10
|
+
length, so an empty one leaves them all empty: ``test_curves_empty`` round
|
|
11
|
+
trips those.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from cgmath.constraints.procrustes import ProcrustesData
|
|
16
|
+
from cgmath.geometry._saddle_surface import RaycastData as SaddleRaycastData
|
|
17
|
+
from cgmath.geometry._saddle_surface import SampleData as SaddleSampleData
|
|
18
|
+
from cgmath.geometry.bspline import BSplineData
|
|
19
|
+
from cgmath.geometry.bspline import SampleData as CurveSampleData
|
|
20
|
+
from cgmath.geometry.bspline_patch import (
|
|
21
|
+
BSplinePatchData,
|
|
22
|
+
PatchRaycastData,
|
|
23
|
+
PatchSampleData,
|
|
24
|
+
)
|
|
25
|
+
from cgmath.geometry.mesh import MeshData
|
|
26
|
+
|
|
27
|
+
# ---------------------------------- SHAPES ---------------------------------- #
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def arm(n=6):
|
|
31
|
+
"""the joint positions of a bending arm chain"""
|
|
32
|
+
t = np.linspace(0.0, 1.0, n)
|
|
33
|
+
return np.column_stack([t * 10.0, np.sin(t * 3.0) * 2.0, np.cos(t * 2.0)])
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def ring(n=8):
|
|
37
|
+
"""a closed loop of n points, an ellipse that rises and falls twice"""
|
|
38
|
+
a = np.linspace(0.0, 2.0 * np.pi, n, endpoint=False)
|
|
39
|
+
return np.column_stack([np.cos(a) * 4.0, np.sin(a) * 2.5, np.sin(a * 2.0) * 0.5])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def tube(nu=6, nv=5):
|
|
43
|
+
"""the control grid of a tube: u closes around it, v runs along it"""
|
|
44
|
+
a = np.linspace(0.0, 2.0 * np.pi, nu, endpoint=False)[:, None]
|
|
45
|
+
height = np.linspace(0.0, 6.0, nv)[None, :]
|
|
46
|
+
radius = 2.0 + 0.3 * np.sin(height)
|
|
47
|
+
return np.stack(
|
|
48
|
+
np.broadcast_arrays(np.cos(a) * radius, np.sin(a) * radius, height), axis=-1
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def sheet(nu=5, nv=6):
|
|
53
|
+
"""the control grid of a wavy sheet in the xy plane, facing +z"""
|
|
54
|
+
u, v = np.meshgrid(np.linspace(-4, 4, nu), np.linspace(-5, 5, nv), indexing="ij")
|
|
55
|
+
return np.stack([u, v, np.sin(u * 0.5) * np.cos(v * 0.5)], axis=-1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def strip():
|
|
59
|
+
"""a mesh of one quad and two triangles, facing +z"""
|
|
60
|
+
points = np.array(
|
|
61
|
+
[
|
|
62
|
+
[0.0, 0.0, 0.0],
|
|
63
|
+
[1.0, 0.0, 0.0],
|
|
64
|
+
[2.0, 0.0, 0.2],
|
|
65
|
+
[0.0, 1.0, 0.0],
|
|
66
|
+
[1.0, 1.0, 0.0],
|
|
67
|
+
[2.0, 1.0, 0.2],
|
|
68
|
+
]
|
|
69
|
+
)
|
|
70
|
+
return MeshData(
|
|
71
|
+
points = points,
|
|
72
|
+
indices = np.array([0, 1, 4, 3, 1, 2, 5, 1, 5, 4]),
|
|
73
|
+
counts = np.array([4, 3, 3]),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# --------------------------------- BUILDERS --------------------------------- #
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def curve() -> BSplineData:
|
|
81
|
+
"""a closed quadratic through a ring of edit points, every setting changed"""
|
|
82
|
+
return BSplineData.from_edit_points(
|
|
83
|
+
ring(),
|
|
84
|
+
degree = 2,
|
|
85
|
+
periodic = True,
|
|
86
|
+
uniform = True,
|
|
87
|
+
registered = True,
|
|
88
|
+
use_numba = False,
|
|
89
|
+
arc_length_samples = 257,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def curve_sample() -> CurveSampleData:
|
|
94
|
+
"""points beside a spine with stacked ends and Maya's knots, projected onto it"""
|
|
95
|
+
spine = BSplineData.from_edit_points(arm(), collapse=(2, 2))
|
|
96
|
+
offsets = np.array(
|
|
97
|
+
[
|
|
98
|
+
[0.0, 0.5, 0.0],
|
|
99
|
+
[0.2, -0.4, 0.3],
|
|
100
|
+
[0.0, 0.0, -0.6],
|
|
101
|
+
[-0.3, 0.2, 0.1],
|
|
102
|
+
[0.4, 0.4, 0.4], # past the stacked end, where there is no tangent
|
|
103
|
+
]
|
|
104
|
+
)
|
|
105
|
+
return spine.sample(arm(5) + offsets)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def patch() -> BSplinePatchData:
|
|
109
|
+
"""a tube closed in u, open in v, every setting changed"""
|
|
110
|
+
return BSplinePatchData(
|
|
111
|
+
points = tube(),
|
|
112
|
+
degree_u = 2,
|
|
113
|
+
degree_v = 3,
|
|
114
|
+
periodic_u = True,
|
|
115
|
+
periodic_v = False,
|
|
116
|
+
uniform_u = True,
|
|
117
|
+
uniform_v = True,
|
|
118
|
+
use_numba = False,
|
|
119
|
+
registered_u = True,
|
|
120
|
+
registered_v = True,
|
|
121
|
+
arc_length_samples = 300,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def patch_sample() -> PatchSampleData:
|
|
126
|
+
"""points inside and outside a tube, projected onto it"""
|
|
127
|
+
surface = BSplinePatchData(
|
|
128
|
+
points=tube(), degree_u=2, degree_v=3, periodic_u=True, periodic_v=False
|
|
129
|
+
)
|
|
130
|
+
queries = np.array(
|
|
131
|
+
[[3.0, 0.0, 1.0], [0.0, 1.0, 2.5], [-2.5, -2.5, 4.0], [0.5, -3.0, 5.5]]
|
|
132
|
+
)
|
|
133
|
+
return surface.sample(queries)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def patch_raycast() -> PatchRaycastData:
|
|
137
|
+
"""rays down onto a sheet, one up into it from below, and one that misses (NaN)"""
|
|
138
|
+
surface = BSplinePatchData(
|
|
139
|
+
points=sheet(), degree_u=3, degree_v=3, periodic_u=False, periodic_v=False
|
|
140
|
+
)
|
|
141
|
+
origins = np.array(
|
|
142
|
+
[[0.0, 0.0, 5.0], [1.0, -2.0, 5.0], [-1.0, 1.0, -5.0], [40.0, 40.0, 5.0]]
|
|
143
|
+
)
|
|
144
|
+
directions = np.array(
|
|
145
|
+
[[0.0, 0.0, -1.0], [0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, 0.0, -1.0]]
|
|
146
|
+
)
|
|
147
|
+
return surface.raycast(origins, directions, forward_only=False)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def saddle_sample() -> SaddleSampleData:
|
|
151
|
+
"""points above, below and on a quad-and-triangles mesh, sampled on it"""
|
|
152
|
+
queries = np.array(
|
|
153
|
+
[
|
|
154
|
+
[0.5, 0.5, 0.5], # above the quad
|
|
155
|
+
[0.3, 0.6, -0.4], # below it: occluded
|
|
156
|
+
[1.6, 0.4, 0.3], # above a triangle: its geometry is -1 padded
|
|
157
|
+
[2.0, 1.0, 0.2], # on a vertex: matched exactly
|
|
158
|
+
]
|
|
159
|
+
)
|
|
160
|
+
return strip().sample(queries)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def saddle_raycast() -> SaddleRaycastData:
|
|
164
|
+
"""a ray down onto a quad, one up into a triangle, and one that misses (NaN, -1)"""
|
|
165
|
+
origins = np.array([[0.5, 0.5, 2.0], [1.7, 0.5, -2.0], [9.0, 9.0, 2.0]])
|
|
166
|
+
directions = np.array([[0.0, 0.0, -1.0], [0.0, 0.0, 1.0], [0.0, 0.0, -1.0]])
|
|
167
|
+
return strip().raycast(origins, directions, forward_only=False)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def procrustes() -> ProcrustesData:
|
|
171
|
+
"""a cube held by two clusters, one of half its points, no scale offset"""
|
|
172
|
+
cube = np.array(
|
|
173
|
+
[[x, y, z] for z in (0.5, -0.5) for y in (-0.5, 0.5) for x in (-0.5, 0.5)]
|
|
174
|
+
)
|
|
175
|
+
lid = np.eye(4)
|
|
176
|
+
lid[3, :3] = [0.0, 0.5, 0.0]
|
|
177
|
+
|
|
178
|
+
constraint = ProcrustesData(cube)
|
|
179
|
+
constraint.attach(lid, [2, 3, 4, 5]) # the shorter cluster is -1 padded
|
|
180
|
+
constraint.attach(np.eye(4))
|
|
181
|
+
constraint.scale_offset = False
|
|
182
|
+
|
|
183
|
+
moved = cube * 1.2
|
|
184
|
+
moved[:2, 2] += 0.3
|
|
185
|
+
constraint.update(moved) # the per-frame target and results are not saved
|
|
186
|
+
return constraint
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
EXAMPLES = {
|
|
190
|
+
BSplineData: curve,
|
|
191
|
+
CurveSampleData: curve_sample,
|
|
192
|
+
BSplinePatchData: patch,
|
|
193
|
+
PatchSampleData: patch_sample,
|
|
194
|
+
PatchRaycastData: patch_raycast,
|
|
195
|
+
SaddleSampleData: saddle_sample,
|
|
196
|
+
SaddleRaycastData: saddle_raycast,
|
|
197
|
+
ProcrustesData: procrustes,
|
|
198
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""Filled-in deformers, for test_roundtrip.
|
|
2
|
+
|
|
3
|
+
Each builder makes a deformer the way a user does -- from a mesh, a skin, a
|
|
4
|
+
rig or a lattice -- changes every setting from its default and binds it, so
|
|
5
|
+
every saved field holds a value of its own. The meshes are small: a few dozen
|
|
6
|
+
points.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from cgmath.geometry.deform import (
|
|
11
|
+
DeltaMushData,
|
|
12
|
+
FFDData,
|
|
13
|
+
PatchRelaxData,
|
|
14
|
+
SkinDeformData,
|
|
15
|
+
WrapData,
|
|
16
|
+
)
|
|
17
|
+
from cgmath.geometry.mesh import MeshData
|
|
18
|
+
from cgmath.geometry.skin_weights import SkinData
|
|
19
|
+
from cgmath.hierarchy import HierarchyData, TransformData
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _grid(n: int = 6, height: float = 0.3, name: str = "grid") -> MeshData:
|
|
23
|
+
"""an open quad grid on XY with a sine bump in Z: it has a border"""
|
|
24
|
+
t = np.linspace(0.0, 1.0, n)
|
|
25
|
+
points = np.array([[x, y, 0.0] for y in t for x in t])
|
|
26
|
+
points[:, 2] = height * np.sin(np.pi * points[:, 0]) * np.sin(np.pi * points[:, 1])
|
|
27
|
+
|
|
28
|
+
indices = []
|
|
29
|
+
for j in range(n - 1):
|
|
30
|
+
for i in range(n - 1):
|
|
31
|
+
a = j * n + i
|
|
32
|
+
indices.extend([a, a + 1, a + n + 1, a + n])
|
|
33
|
+
|
|
34
|
+
return MeshData(
|
|
35
|
+
points = points,
|
|
36
|
+
indices = np.asarray(indices, dtype=np.int32),
|
|
37
|
+
counts = np.full((n - 1) ** 2, 4, dtype=np.int32),
|
|
38
|
+
name = name,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _torus(around: int = 8, across: int = 6, name: str = "torus") -> MeshData:
|
|
43
|
+
"""a closed quad torus: it has no border"""
|
|
44
|
+
u = np.linspace(0.0, 2.0 * np.pi, around, endpoint=False)
|
|
45
|
+
v = np.linspace(0.0, 2.0 * np.pi, across, endpoint=False)
|
|
46
|
+
uu, vv = np.meshgrid(u, v, indexing="ij")
|
|
47
|
+
ring = 1.0 + 0.35 * np.cos(vv)
|
|
48
|
+
points = np.stack(
|
|
49
|
+
[ring * np.cos(uu), ring * np.sin(uu), 0.35 * np.sin(vv)], axis=-1
|
|
50
|
+
).reshape(-1, 3)
|
|
51
|
+
|
|
52
|
+
indices = []
|
|
53
|
+
for i in range(around):
|
|
54
|
+
for j in range(across):
|
|
55
|
+
k, l = (i + 1) % around, (j + 1) % across
|
|
56
|
+
indices.extend(
|
|
57
|
+
[i * across + j, k * across + j, k * across + l, i * across + l]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return MeshData(
|
|
61
|
+
points = points,
|
|
62
|
+
indices = np.asarray(indices, dtype=np.int32),
|
|
63
|
+
counts = np.full(around * across, 4, dtype=np.int32),
|
|
64
|
+
name = name,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def delta_mush() -> DeltaMushData:
|
|
69
|
+
"""bound with DDM on an open mesh; pinning turned off after the border was read"""
|
|
70
|
+
mush = DeltaMushData(
|
|
71
|
+
_grid(),
|
|
72
|
+
smooth_iterations = 6,
|
|
73
|
+
smooth_step_size = 0.4,
|
|
74
|
+
weight = 0.7,
|
|
75
|
+
method = "ddm",
|
|
76
|
+
)
|
|
77
|
+
# the border read at construction stays saved, pinned or not
|
|
78
|
+
mush.pin_borders = False
|
|
79
|
+
mush.bind()
|
|
80
|
+
return mush
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def patch_relax() -> PatchRelaxData:
|
|
84
|
+
"""bound on a closed mesh, so its border is an empty array, with a painted mask"""
|
|
85
|
+
mesh = _torus()
|
|
86
|
+
relaxer = PatchRelaxData(
|
|
87
|
+
mesh,
|
|
88
|
+
iterations = 12,
|
|
89
|
+
alpha = 0.8,
|
|
90
|
+
surface_blend = 0.3,
|
|
91
|
+
step_size = 0.4,
|
|
92
|
+
pin_borders = False,
|
|
93
|
+
mask = np.linspace(0.0, 1.0, len(mesh.points)),
|
|
94
|
+
)
|
|
95
|
+
relaxer.bind()
|
|
96
|
+
return relaxer
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def ffd() -> FFDData:
|
|
100
|
+
"""a lattice over part of a mesh, bound, with falloff past its edge"""
|
|
101
|
+
lattice = FFDData.create_lattice(
|
|
102
|
+
(3, 4, 3), bbox_min=[-0.1, -0.1, -0.5], bbox_max=[0.7, 1.1, 0.5], name="ffd_box"
|
|
103
|
+
)
|
|
104
|
+
ffd = FFDData.from_mesh(lattice, divisions=(3, 4, 3))
|
|
105
|
+
ffd.local_influence = (3, 4, 2)
|
|
106
|
+
ffd.outside = "falloff"
|
|
107
|
+
ffd.falloff_radius = 1.5
|
|
108
|
+
|
|
109
|
+
# the grid runs to x = 1, past the lattice: those points fall off
|
|
110
|
+
ffd.bind(_grid())
|
|
111
|
+
|
|
112
|
+
deformed = ffd.lattice.copy()
|
|
113
|
+
deformed[:, :, -1, 2] += 0.4
|
|
114
|
+
ffd.update(deformed)
|
|
115
|
+
return ffd
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def skin_deform() -> SkinDeformData:
|
|
119
|
+
"""dual quaternion, bound, its matrices from a bind rig, joints reordered"""
|
|
120
|
+
root = TransformData(name="A:root", translate=(0.0, 0.0, 0.0))
|
|
121
|
+
spine = TransformData(name="A:spine", translate=(0.5, 0.0, 0.0))
|
|
122
|
+
tip = TransformData(name="A:tip", translate=(0.5, 0.0, 0.0), rotate=(0.0, 0.0, 15.0))
|
|
123
|
+
rig = HierarchyData([root, spine, tip])
|
|
124
|
+
|
|
125
|
+
spine.parent_uuid = root.uuid
|
|
126
|
+
tip.parent_uuid = spine.uuid
|
|
127
|
+
|
|
128
|
+
mesh = _grid(name="A:body")
|
|
129
|
+
x = mesh.points[:, 0]
|
|
130
|
+
# at most two influences per vertex: root fades into spine, spine into tip
|
|
131
|
+
weights = np.zeros((len(x), 3))
|
|
132
|
+
low, high = x <= 0.5, x > 0.5
|
|
133
|
+
weights[low, 0] = 1.0 - 2.0 * x[low]
|
|
134
|
+
weights[low, 1] = 2.0 * x[low]
|
|
135
|
+
weights[high, 1] = 2.0 - 2.0 * x[high]
|
|
136
|
+
weights[high, 2] = 2.0 * x[high] - 1.0
|
|
137
|
+
skin = SkinData(weights=weights, influences=["A:root", "A:spine", "A:tip"], name="A:skin")
|
|
138
|
+
|
|
139
|
+
deformer = SkinDeformData(
|
|
140
|
+
mesh,
|
|
141
|
+
skin,
|
|
142
|
+
bind_rig = rig,
|
|
143
|
+
joints = ["A:tip", "A:root", "A:spine"],
|
|
144
|
+
method = "dqs",
|
|
145
|
+
name = "A:body_skin",
|
|
146
|
+
)
|
|
147
|
+
deformer.bind()
|
|
148
|
+
return deformer
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def wrap() -> WrapData:
|
|
152
|
+
"""a geodesic cage wrap with a compact kernel, solved, so its pseudo-inverse is saved"""
|
|
153
|
+
cage = _grid(4, height=0.4, name="cage")
|
|
154
|
+
moved = cage.points + np.random.default_rng(5).normal(scale=0.05, size=cage.points.shape)
|
|
155
|
+
|
|
156
|
+
wrap = WrapData(kernel="wendland_c2", name="cage_wrap")
|
|
157
|
+
wrap.set_source(cage)
|
|
158
|
+
wrap.set_target(moved)
|
|
159
|
+
wrap.set_radius(0.9)
|
|
160
|
+
wrap.set_geodesic_radius(1.0)
|
|
161
|
+
wrap.deform(_grid().points)
|
|
162
|
+
return wrap
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
EXAMPLES = {
|
|
166
|
+
DeltaMushData: delta_mush,
|
|
167
|
+
FFDData: ffd,
|
|
168
|
+
PatchRelaxData: patch_relax,
|
|
169
|
+
SkinDeformData: skin_deform,
|
|
170
|
+
WrapData: wrap,
|
|
171
|
+
}
|