2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2011-02-27 20:40:57 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
2011-02-27 20:40:57 +00:00
|
|
|
*/
|
|
|
|
|
|
2025-01-26 20:07:57 +01:00
|
|
|
#include <algorithm>
|
2022-10-06 15:15:49 -05:00
|
|
|
#include <cfloat>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <ctime>
|
2008-06-17 19:00:21 +00:00
|
|
|
#include <memory.h>
|
2008-04-25 18:22:20 +00:00
|
|
|
|
2021-12-13 17:09:22 +01:00
|
|
|
#include "DNA_gpencil_modifier_types.h"
|
2008-08-14 03:05:13 +00:00
|
|
|
#include "DNA_mesh_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
2008-04-25 18:22:20 +00:00
|
|
|
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_geom.h"
|
|
|
|
|
#include "BLI_math_matrix.h"
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
#include "BLI_math_solvers.h"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_vector.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_task.h"
|
|
|
|
|
#include "BLI_utildefines.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
|
2024-03-28 14:45:52 -04:00
|
|
|
#include "BKE_attribute.hh"
|
2024-05-20 12:53:28 -04:00
|
|
|
#include "BKE_mesh_legacy_derived_mesh.hh"
|
2023-11-14 09:30:40 +01:00
|
|
|
#include "BKE_modifier.hh"
|
2023-11-28 16:05:12 -05:00
|
|
|
#include "BKE_shrinkwrap.hh"
|
2011-01-07 19:18:31 +00:00
|
|
|
|
2024-01-29 18:57:16 -05:00
|
|
|
#include "BKE_deform.hh"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_editmesh.hh"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh" /* for OMP limits. */
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_mesh_wrapper.hh"
|
|
|
|
|
#include "BKE_subsurf.hh"
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph_query.hh"
|
2018-12-07 15:45:53 +01:00
|
|
|
|
2025-01-26 20:07:57 +01:00
|
|
|
#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
|
2014-02-03 18:55:59 +11:00
|
|
|
|
2012-11-09 04:01:19 +00:00
|
|
|
/* for timing... */
|
|
|
|
|
#if 0
|
2024-01-19 14:32:28 +01:00
|
|
|
# include "BLI_time_utildefines.h"
|
2008-05-01 01:00:01 +00:00
|
|
|
#else
|
2012-11-09 04:01:19 +00:00
|
|
|
# define TIMEIT_BENCH(expr, id) (expr)
|
2008-05-01 01:00:01 +00:00
|
|
|
#endif
|
|
|
|
|
|
2012-11-09 04:01:19 +00:00
|
|
|
/* Util macros */
|
|
|
|
|
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
struct ShrinkwrapCalcData {
|
2019-05-01 11:09:22 +10:00
|
|
|
ShrinkwrapModifierData *smd; /* shrinkwrap modifier data */
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
Object *ob; /* object we are applying shrinkwrap to */
|
2018-10-03 19:09:43 +03:00
|
|
|
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
float (*vert_positions)[3]; /* Array of verts being projected. */
|
2023-03-15 14:00:40 -04:00
|
|
|
blender::Span<blender::float3> vert_normals;
|
2022-10-07 10:32:02 +11:00
|
|
|
/* Vertices being shrink-wrapped. */
|
|
|
|
|
float (*vertexCos)[3];
|
2018-10-03 19:09:43 +03:00
|
|
|
int numVerts;
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
const MDeformVert *dvert; /* Pointer to mdeform array */
|
|
|
|
|
int vgroup; /* Vertex group num */
|
|
|
|
|
bool invert_vgroup; /* invert vertex group influence */
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
Mesh *target; /* mesh we are shrinking to */
|
|
|
|
|
SpaceTransform local2target; /* transform to move between local and target space */
|
|
|
|
|
ShrinkwrapTreeData *tree; /* mesh BVH tree data */
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
Object *aux_target;
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2019-05-01 11:09:22 +10:00
|
|
|
float keepDist; /* Distance to keep above target surface (units are in local space) */
|
2022-10-06 15:15:49 -05:00
|
|
|
};
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
struct ShrinkwrapCalcCBData {
|
2016-05-30 17:30:06 +02:00
|
|
|
ShrinkwrapCalcData *calc;
|
|
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
ShrinkwrapTreeData *tree;
|
|
|
|
|
ShrinkwrapTreeData *aux_tree;
|
2016-05-30 17:30:06 +02:00
|
|
|
|
|
|
|
|
float *proj_axis;
|
|
|
|
|
SpaceTransform *local2aux;
|
2022-10-06 15:15:49 -05:00
|
|
|
};
|
2016-05-30 17:30:06 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
bool BKE_shrinkwrap_needs_normals(int shrinkType, int shrinkMode)
|
|
|
|
|
{
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
return (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) ||
|
|
|
|
|
(shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX &&
|
|
|
|
|
shrinkMode == MOD_SHRINKWRAP_ABOVE_SURFACE);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BKE_shrinkwrap_init_tree(
|
|
|
|
|
ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
|
|
|
|
|
{
|
2024-03-28 14:45:52 -04:00
|
|
|
using namespace blender::bke;
|
2023-11-28 16:40:43 -05:00
|
|
|
*data = {};
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
if (mesh == nullptr) {
|
2020-06-15 23:17:42 +10:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We could create a BVH tree from the edit mesh,
|
|
|
|
|
* however accessing normals from the face/loop normals gets more involved.
|
|
|
|
|
* Convert mesh data since this isn't typically used in edit-mode. */
|
|
|
|
|
BKE_mesh_wrapper_ensure_mdata(mesh);
|
|
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (mesh->verts_num <= 0) {
|
2018-10-03 19:09:43 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->mesh = mesh;
|
2024-12-04 00:17:17 +01:00
|
|
|
data->edges = mesh->edges();
|
2023-11-28 16:40:43 -05:00
|
|
|
data->faces = mesh->faces();
|
|
|
|
|
data->corner_edges = mesh->corner_edges();
|
|
|
|
|
data->vert_normals = mesh->vert_normals();
|
2024-03-28 14:45:52 -04:00
|
|
|
const AttributeAccessor attributes = mesh->attributes();
|
|
|
|
|
data->sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
|
2018-10-03 19:09:43 +03:00
|
|
|
|
|
|
|
|
if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
|
2024-12-04 00:17:17 +01:00
|
|
|
data->treeData = mesh->bvh_verts();
|
|
|
|
|
data->bvh = data->treeData.tree;
|
2022-10-06 15:15:49 -05:00
|
|
|
return data->bvh != nullptr;
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
if (mesh->faces_num <= 0) {
|
2020-08-07 12:30:43 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2024-12-04 00:17:17 +01:00
|
|
|
data->treeData = mesh->bvh_corner_tris();
|
|
|
|
|
data->bvh = data->treeData.tree;
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
if (data->bvh == nullptr) {
|
2020-08-07 12:30:43 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2020-08-07 12:30:43 +02:00
|
|
|
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
|
2023-11-28 16:40:43 -05:00
|
|
|
data->face_normals = mesh->face_normals();
|
Mesh: Replace auto smooth with node group
Design task: #93551
This PR replaces the auto smooth option with a geometry nodes modifier
that sets the sharp edge attribute. This solves a fair number of long-
standing problems related to auto smooth, simplifies the process of
normal computation, and allows Blender to automatically choose between
face, vertex, and face corner normals based on the sharp edge and face
attributes.
Versioning adds a geometry node group to objects with meshes that had
auto-smooth enabled. The modifier can be applied, which also improves
performance.
Auto smooth is now unnecessary to get a combination of sharp and smooth
edges. In general workflows are changed a bit. Separate procedural and
destructive workflows are available. Custom normals can be used
immediately without turning on the removed auto smooth option.
**Procedural**
The node group asset "Smooth by Angle" is the main way to set sharp
normals based on the edge angle. It can be accessed directly in the add
modifier menu. Of course the modifier can be reordered, muted, or
applied like any other, or changed internally like any geometry nodes
modifier.
**Destructive**
Often the sharp edges don't need to be dynamic. This can give better
performance since edge angles don't need to be recalculated. In edit
mode the two operators "Select Sharp Edges" and "Mark Sharp" can be
used. In other modes, the "Shade Smooth by Angle" controls the edge
sharpness directly.
### Breaking API Changes
- `use_auto_smooth` is removed. Face corner normals are now used
automatically if there are mixed smooth vs. not smooth tags. Meshes
now always use custom normals if they exist.
- In Cycles, the lack of the separate auto smooth state makes normals look
triangulated when all faces are shaded smooth.
- `auto_smooth_angle` is removed. Replaced by a modifier (or operator)
controlling the sharp edge attribute. This means the mesh itself
(without an object) doesn't know anything about automatically smoothing
by angle anymore.
- `create_normals_split`, `calc_normals_split`, and `free_normals_split`
are removed, and are replaced by the simpler `Mesh.corner_normals`
collection property. Since it gives access to the normals cache, it
is automatically updated when relevant data changes.
Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609
### Tests
- `geo_node_curves_test_deform_curves_on_surface` has slightly different
results because face corner normals are used instead of interpolated
vertex normals.
- `bf_wavefront_obj_tests` has different export results for one file
which mixed sharp and smooth faces without turning on auto smooth.
- `cycles_mesh_cpu` has one object which is completely flat shaded.
Previously every edge was split before rendering, now it looks triangulated.
Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
|
|
|
if (mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner) {
|
2023-11-28 16:40:43 -05:00
|
|
|
data->corner_normals = mesh->corner_normals();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
}
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2020-08-07 12:30:43 +02:00
|
|
|
if (shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
|
2024-03-27 22:09:51 -04:00
|
|
|
data->boundary = &blender::bke::shrinkwrap::boundary_cache_ensure(*mesh);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
return true;
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
|
|
|
|
|
2024-12-04 00:17:17 +01:00
|
|
|
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData * /*data*/) {}
|
2018-10-03 19:09:43 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
namespace blender::bke::shrinkwrap {
|
|
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Accumulate edge for average boundary edge direction. */
|
|
|
|
|
static void merge_vert_dir(ShrinkwrapBoundaryVertData *vdata,
|
2024-03-27 21:48:23 -04:00
|
|
|
MutableSpan<int8_t> status,
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
int index,
|
|
|
|
|
const float edge_dir[3],
|
|
|
|
|
signed char side)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(index >= 0);
|
|
|
|
|
float *direction = vdata[index].direction;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Invert the direction vector if either:
|
|
|
|
|
* - This is the second edge and both edges have the vertex as start or end.
|
|
|
|
|
* - For third and above, if it points in the wrong direction.
|
|
|
|
|
*/
|
|
|
|
|
if (status[index] >= 0 ? status[index] == side : dot_v3v3(direction, edge_dir) < 0) {
|
|
|
|
|
sub_v3_v3(direction, edge_dir);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
add_v3_v3(direction, edge_dir);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
status[index] = (status[index] == 0) ? side : -1;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 22:09:51 -04:00
|
|
|
static ShrinkwrapBoundaryData shrinkwrap_build_boundary_data(const Mesh &mesh)
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
{
|
2024-03-27 22:09:51 -04:00
|
|
|
const Span<float3> positions = mesh.vert_positions();
|
|
|
|
|
const Span<int2> edges = mesh.edges();
|
|
|
|
|
const Span<int> corner_verts = mesh.corner_verts();
|
|
|
|
|
const Span<int> corner_edges = mesh.corner_edges();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
/* Count faces per edge (up to 2). */
|
2024-03-27 21:48:23 -04:00
|
|
|
Array<int8_t> edge_mode(edges.size(), 0);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
for (const int edge : corner_edges) {
|
|
|
|
|
if (edge_mode[edge] < 2) {
|
|
|
|
|
edge_mode[edge]++;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Build the boundary edge bitmask. */
|
2024-03-27 22:09:51 -04:00
|
|
|
BitVector<> edge_is_boundary(mesh.edges_num, false);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
int num_boundary_edges = 0;
|
|
|
|
|
for (const int64_t i : edges.index_range()) {
|
|
|
|
|
if (edge_mode[i] == 1) {
|
2023-12-04 15:22:00 -05:00
|
|
|
edge_is_boundary[i].set();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
num_boundary_edges++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
/* If no boundary, return nullptr. */
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
if (num_boundary_edges == 0) {
|
2023-12-04 15:22:00 -05:00
|
|
|
return {};
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate the data object. */
|
2024-03-27 22:09:51 -04:00
|
|
|
ShrinkwrapBoundaryData data;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2023-12-19 14:57:49 +01:00
|
|
|
/* Build the boundary corner_tris bit-mask. */
|
2024-03-27 22:09:51 -04:00
|
|
|
const Span<int3> corner_tris = mesh.corner_tris();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
BitVector<> tri_has_boundary(corner_tris.size(), false);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2023-12-19 14:57:49 +01:00
|
|
|
for (const int64_t i : corner_tris.index_range()) {
|
|
|
|
|
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
|
|
|
|
edges, corner_verts, corner_edges, corner_tris[i]);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
for (int j = 0; j < 3; j++) {
|
2024-03-27 21:48:23 -04:00
|
|
|
if (real_edges[j] >= 0 && edge_is_boundary[real_edges[j]]) {
|
2023-12-19 14:57:49 +01:00
|
|
|
tri_has_boundary[i].set();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find boundary vertices and build a mapping table for compact storage of data. */
|
2024-03-27 22:09:51 -04:00
|
|
|
Array<int> vert_boundary_id(mesh.verts_num, 0);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
for (const int64_t i : edges.index_range()) {
|
|
|
|
|
if (edge_is_boundary[i]) {
|
|
|
|
|
const int2 &edge = edges[i];
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
vert_boundary_id[edge[0]] = 1;
|
|
|
|
|
vert_boundary_id[edge[1]] = 1;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
int boundary_verts_num = 0;
|
|
|
|
|
for (const int64_t i : positions.index_range()) {
|
|
|
|
|
vert_boundary_id[i] = (vert_boundary_id[i] != 0) ? boundary_verts_num++ : -1;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Compute average directions. */
|
2024-03-27 21:48:23 -04:00
|
|
|
Array<ShrinkwrapBoundaryVertData> boundary_verts(boundary_verts_num);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
Array<int8_t> vert_status(boundary_verts_num);
|
|
|
|
|
for (const int64_t i : edges.index_range()) {
|
|
|
|
|
if (edge_is_boundary[i]) {
|
|
|
|
|
const int2 &edge = edges[i];
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
float dir[3];
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
sub_v3_v3v3(dir, positions[edge[1]], positions[edge[0]]);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
normalize_v3(dir);
|
|
|
|
|
|
2023-12-04 15:22:00 -05:00
|
|
|
merge_vert_dir(boundary_verts.data(), vert_status, vert_boundary_id[edge[0]], dir, 1);
|
|
|
|
|
merge_vert_dir(boundary_verts.data(), vert_status, vert_boundary_id[edge[1]], dir, 2);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Finalize average direction and compute normal. */
|
2024-03-27 22:09:51 -04:00
|
|
|
const Span<float3> vert_normals = mesh.vert_normals();
|
2024-03-27 21:48:23 -04:00
|
|
|
for (const int64_t i : positions.index_range()) {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
int bidx = vert_boundary_id[i];
|
|
|
|
|
|
|
|
|
|
if (bidx >= 0) {
|
|
|
|
|
ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
float tmp[3];
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
normalize_v3(vdata->direction);
|
|
|
|
|
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
cross_v3_v3v3(tmp, vert_normals[i], vdata->direction);
|
|
|
|
|
cross_v3_v3v3(vdata->normal_plane, tmp, vert_normals[i]);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
normalize_v3(vdata->normal_plane);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 22:09:51 -04:00
|
|
|
data.edge_is_boundary = std::move(edge_is_boundary);
|
|
|
|
|
data.tri_has_boundary = std::move(tri_has_boundary);
|
|
|
|
|
data.vert_boundary_id = std::move(vert_boundary_id);
|
|
|
|
|
data.boundary_verts = std::move(boundary_verts);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-27 22:09:51 -04:00
|
|
|
const ShrinkwrapBoundaryData &boundary_cache_ensure(const Mesh &mesh)
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
{
|
2024-03-27 22:09:51 -04:00
|
|
|
mesh.runtime->shrinkwrap_boundary_cache.ensure(
|
|
|
|
|
[&](ShrinkwrapBoundaryData &r_data) { r_data = shrinkwrap_build_boundary_data(mesh); });
|
|
|
|
|
return mesh.runtime->shrinkwrap_boundary_cache.data();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
|
2024-03-27 21:48:23 -04:00
|
|
|
} // namespace blender::bke::shrinkwrap
|
|
|
|
|
|
2020-10-14 14:43:54 +11:00
|
|
|
/**
|
|
|
|
|
* Shrink-wrap to the nearest vertex
|
2008-05-02 00:16:48 +00:00
|
|
|
*
|
2022-10-07 10:32:02 +11:00
|
|
|
* it builds a BVH-tree of vertices we can attach to and then
|
|
|
|
|
* for each vertex performs a nearest vertex search on the tree.
|
2008-05-02 00:16:48 +00:00
|
|
|
*/
|
2016-05-30 17:30:06 +02:00
|
|
|
static void shrinkwrap_calc_nearest_vertex_cb_ex(void *__restrict userdata,
|
2018-01-10 12:49:51 +01:00
|
|
|
const int i,
|
2019-07-30 14:56:47 +02:00
|
|
|
const TaskParallelTLS *__restrict tls)
|
2008-05-01 01:00:01 +00:00
|
|
|
{
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
ShrinkwrapCalcData *calc = data->calc;
|
2024-12-17 18:22:00 -05:00
|
|
|
blender::bke::BVHTreeFromMesh *treeData = &data->tree->treeData;
|
2022-10-06 15:15:49 -05:00
|
|
|
BVHTreeNearest *nearest = static_cast<BVHTreeNearest *>(tls->userdata_chunk);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
float *co = calc->vertexCos[i];
|
|
|
|
|
float tmp_co[3];
|
2025-02-26 15:56:08 +01:00
|
|
|
float weight = BKE_defvert_array_find_weight_safe(
|
|
|
|
|
calc->dvert, i, calc->vgroup, calc->invert_vgroup);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
if (weight == 0.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Convert the vertex to tree coordinates */
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
if (calc->vert_positions) {
|
|
|
|
|
copy_v3_v3(tmp_co, calc->vert_positions[i]);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(tmp_co, co);
|
|
|
|
|
}
|
|
|
|
|
BLI_space_transform_apply(&calc->local2target, tmp_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Use local proximity heuristics (to reduce the nearest search)
|
|
|
|
|
*
|
2019-04-27 12:07:07 +10:00
|
|
|
* If we already had an hit before.. we assume this vertex is going to have a close hit to that
|
|
|
|
|
* other vertex so we can initiate the "nearest.dist" with the expected value to that last hit.
|
2016-05-30 17:30:06 +02:00
|
|
|
* This will lead in pruning of the search tree. */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (nearest->index != -1) {
|
2016-05-30 17:30:06 +02:00
|
|
|
nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-30 17:30:06 +02:00
|
|
|
nearest->dist_sq = FLT_MAX;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
BLI_bvhtree_find_nearest(treeData->tree, tmp_co, nearest, treeData->nearest_callback, treeData);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Found the nearest vertex */
|
|
|
|
|
if (nearest->index != -1) {
|
|
|
|
|
/* Adjusting the vertex weight,
|
|
|
|
|
* so that after interpolating it keeps a certain distance from the nearest position */
|
|
|
|
|
if (nearest->dist_sq > FLT_EPSILON) {
|
|
|
|
|
const float dist = sqrtf(nearest->dist_sq);
|
|
|
|
|
weight *= (dist - calc->keepDist) / dist;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Convert the coordinates back to mesh coordinates */
|
|
|
|
|
copy_v3_v3(tmp_co, nearest->co);
|
|
|
|
|
BLI_space_transform_invert(&calc->local2target, tmp_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-05-01 01:00:01 +00:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
|
|
|
|
|
{
|
2012-05-11 08:05:47 +00:00
|
|
|
BVHTreeNearest nearest = NULL_BVHTreeNearest;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Setup nearest */
|
2008-05-25 15:43:18 +00:00
|
|
|
nearest.index = -1;
|
2014-02-03 02:46:45 +11:00
|
|
|
nearest.dist_sq = FLT_MAX;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData data{};
|
|
|
|
|
data.calc = calc;
|
|
|
|
|
data.tree = calc->tree;
|
2019-07-30 14:56:47 +02:00
|
|
|
TaskParallelSettings settings;
|
2018-01-08 11:35:48 +01:00
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
2023-04-27 16:23:42 -04:00
|
|
|
settings.use_threading = (calc->numVerts > 10000);
|
2018-01-08 11:35:48 +01:00
|
|
|
settings.userdata_chunk = &nearest;
|
|
|
|
|
settings.userdata_chunk_size = sizeof(nearest);
|
|
|
|
|
BLI_task_parallel_range(
|
2018-01-21 11:41:28 +11:00
|
|
|
0, calc->numVerts, &data, shrinkwrap_calc_nearest_vertex_cb_ex, &settings);
|
2008-05-01 01:00:01 +00:00
|
|
|
}
|
2008-04-30 17:55:26 +00:00
|
|
|
|
2014-03-20 22:56:28 +11:00
|
|
|
bool BKE_shrinkwrap_project_normal(char options,
|
2018-05-04 07:39:07 -03:00
|
|
|
const float vert[3],
|
|
|
|
|
const float dir[3],
|
|
|
|
|
const float ray_radius,
|
|
|
|
|
const SpaceTransform *transf,
|
2018-10-03 19:09:43 +03:00
|
|
|
ShrinkwrapTreeData *tree,
|
|
|
|
|
BVHTreeRayHit *hit)
|
2008-07-18 22:24:20 +00:00
|
|
|
{
|
2012-11-05 05:07:57 +00:00
|
|
|
/* don't use this because this dist value could be incompatible
|
2020-05-09 17:15:25 +10:00
|
|
|
* this value used by the callback for comparing previous/new dist values.
|
2012-11-05 05:07:57 +00:00
|
|
|
* also, at the moment there is no need to have a corrected 'dist' value */
|
|
|
|
|
// #define USE_DIST_CORRECT
|
|
|
|
|
|
2008-07-18 22:24:20 +00:00
|
|
|
float tmp_co[3], tmp_no[3];
|
2008-07-19 15:22:38 +00:00
|
|
|
const float *co, *no;
|
2008-07-18 22:24:20 +00:00
|
|
|
BVHTreeRayHit hit_tmp;
|
2008-08-04 14:27:25 +00:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Copy from hit (we need to convert hit rays from one space coordinates to the other */
|
2012-04-29 17:11:40 +00:00
|
|
|
memcpy(&hit_tmp, hit, sizeof(hit_tmp));
|
2008-07-18 22:24:20 +00:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Apply space transform (TODO readjust dist) */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (transf) {
|
2012-04-29 17:11:40 +00:00
|
|
|
copy_v3_v3(tmp_co, vert);
|
2014-08-01 16:28:31 +02:00
|
|
|
BLI_space_transform_apply(transf, tmp_co);
|
2008-07-19 15:22:38 +00:00
|
|
|
co = tmp_co;
|
2008-07-18 22:24:20 +00:00
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
copy_v3_v3(tmp_no, dir);
|
2014-08-01 16:28:31 +02:00
|
|
|
BLI_space_transform_apply_normal(transf, tmp_no);
|
2008-07-19 15:22:38 +00:00
|
|
|
no = tmp_no;
|
|
|
|
|
|
2012-11-05 05:07:57 +00:00
|
|
|
#ifdef USE_DIST_CORRECT
|
2012-05-11 08:05:47 +00:00
|
|
|
hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
|
2012-11-05 05:07:57 +00:00
|
|
|
#endif
|
2008-07-19 15:22:38 +00:00
|
|
|
}
|
2012-03-06 18:40:15 +00:00
|
|
|
else {
|
2008-07-19 15:22:38 +00:00
|
|
|
co = vert;
|
|
|
|
|
no = dir;
|
2008-07-18 22:24:20 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-07-18 22:24:20 +00:00
|
|
|
hit_tmp.index = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
BLI_bvhtree_ray_cast(
|
|
|
|
|
tree->bvh, co, no, ray_radius, &hit_tmp, tree->treeData.raycast_callback, &tree->treeData);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (hit_tmp.index != -1) {
|
2011-02-19 09:01:28 +00:00
|
|
|
/* invert the normal first so face culling works on rotated objects */
|
2012-03-24 06:18:31 +00:00
|
|
|
if (transf) {
|
2014-08-01 16:28:31 +02:00
|
|
|
BLI_space_transform_invert_normal(transf, hit_tmp.no);
|
2011-02-19 09:01:28 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-08 13:47:26 +03:00
|
|
|
if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Apply back-face. */
|
2012-05-11 08:05:47 +00:00
|
|
|
const float dot = dot_v3v3(dir, hit_tmp.no);
|
|
|
|
|
if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
|
2012-11-05 04:19:30 +00:00
|
|
|
((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f))
|
|
|
|
|
{
|
2014-03-20 22:56:28 +11:00
|
|
|
return false; /* Ignore hit */
|
2011-02-19 09:01:28 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (transf) {
|
2021-07-05 12:47:46 +10:00
|
|
|
/* Inverting space transform (TODO: make coherent with the initial dist readjust). */
|
2014-08-01 16:28:31 +02:00
|
|
|
BLI_space_transform_invert(transf, hit_tmp.co);
|
2012-11-05 05:07:57 +00:00
|
|
|
#ifdef USE_DIST_CORRECT
|
2012-11-05 04:19:30 +00:00
|
|
|
hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
|
2012-11-05 05:07:57 +00:00
|
|
|
#endif
|
2008-07-18 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-05 05:07:57 +00:00
|
|
|
BLI_assert(hit_tmp.dist <= hit->dist);
|
|
|
|
|
|
2012-04-29 17:55:54 +00:00
|
|
|
memcpy(hit, &hit_tmp, sizeof(hit_tmp));
|
2014-03-20 22:56:28 +11:00
|
|
|
return true;
|
2008-07-18 22:24:20 +00:00
|
|
|
}
|
2014-03-20 22:56:28 +11:00
|
|
|
return false;
|
2008-07-18 22:24:20 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
|
2018-01-10 12:49:51 +01:00
|
|
|
const int i,
|
2019-07-30 14:56:47 +02:00
|
|
|
const TaskParallelTLS *__restrict tls)
|
2016-05-30 17:30:06 +02:00
|
|
|
{
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
ShrinkwrapCalcData *calc = data->calc;
|
2018-10-03 19:09:43 +03:00
|
|
|
ShrinkwrapTreeData *tree = data->tree;
|
|
|
|
|
ShrinkwrapTreeData *aux_tree = data->aux_tree;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
float *proj_axis = data->proj_axis;
|
|
|
|
|
SpaceTransform *local2aux = data->local2aux;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
BVHTreeRayHit *hit = static_cast<BVHTreeRayHit *>(tls->userdata_chunk);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
|
|
|
|
|
float *co = calc->vertexCos[i];
|
2023-06-09 18:38:35 +02:00
|
|
|
const float *tmp_co, *tmp_no;
|
2025-02-26 15:56:08 +01:00
|
|
|
float weight = BKE_defvert_array_find_weight_safe(
|
|
|
|
|
calc->dvert, i, calc->vgroup, calc->invert_vgroup);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
if (weight == 0.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
if (calc->vert_positions != nullptr && calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL)
|
|
|
|
|
{
|
|
|
|
|
/* calc->vert_positions contains verts from evaluated mesh. */
|
2019-04-27 12:07:07 +10:00
|
|
|
/* These coordinates are deformed by vertexCos only for normal projection
|
|
|
|
|
* (to get correct normals) for other cases calc->verts contains undeformed coordinates and
|
|
|
|
|
* vertexCos should be used */
|
2023-06-09 18:38:35 +02:00
|
|
|
tmp_co = calc->vert_positions[i];
|
|
|
|
|
tmp_no = calc->vert_normals[i];
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2023-06-09 18:38:35 +02:00
|
|
|
tmp_co = co;
|
|
|
|
|
tmp_no = proj_axis;
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
hit->index = -1;
|
2019-04-27 12:07:07 +10:00
|
|
|
|
2022-10-07 10:32:02 +11:00
|
|
|
/* TODO: we should use FLT_MAX here, but sweep-sphere code isn't prepared for that. */
|
2019-04-27 12:07:07 +10:00
|
|
|
hit->dist = BVH_RAYCAST_DIST_MAX;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
bool is_aux = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-07 10:32:02 +11:00
|
|
|
/* Project over positive direction of axis. */
|
2016-05-30 17:30:06 +02:00
|
|
|
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {
|
|
|
|
|
if (aux_tree) {
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no, 0.0, local2aux, aux_tree, hit)) {
|
|
|
|
|
is_aux = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_project_normal(
|
2018-10-18 12:03:04 +11:00
|
|
|
calc->smd->shrinkOpts, tmp_co, tmp_no, 0.0, &calc->local2target, tree, hit))
|
|
|
|
|
{
|
2018-10-03 19:09:43 +03:00
|
|
|
is_aux = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Project over negative direction of axis */
|
|
|
|
|
if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
|
|
|
|
|
float inv_no[3];
|
|
|
|
|
negate_v3_v3(inv_no, tmp_no);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-08 13:47:26 +03:00
|
|
|
char options = calc->smd->shrinkOpts;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-08 13:47:26 +03:00
|
|
|
if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) &&
|
2024-01-02 18:12:54 +01:00
|
|
|
(options & MOD_SHRINKWRAP_CULL_TARGET_MASK))
|
|
|
|
|
{
|
2018-07-08 13:47:26 +03:00
|
|
|
options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
if (aux_tree) {
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_project_normal(0, tmp_co, inv_no, 0.0, local2aux, aux_tree, hit)) {
|
|
|
|
|
is_aux = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_project_normal(
|
2024-01-02 18:12:54 +01:00
|
|
|
options, tmp_co, inv_no, 0.0, &calc->local2target, tree, hit))
|
|
|
|
|
{
|
2018-10-03 19:09:43 +03:00
|
|
|
is_aux = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* don't set the initial dist (which is more efficient),
|
2016-05-30 17:30:06 +02:00
|
|
|
* because its calculated in the targets space, we want the dist in our own space */
|
|
|
|
|
if (proj_limit_squared != 0.0f) {
|
|
|
|
|
if (hit->index != -1 && len_squared_v3v3(hit->co, co) > proj_limit_squared) {
|
2018-06-22 12:07:48 +02:00
|
|
|
hit->index = -1;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-22 12:07:48 +02:00
|
|
|
if (hit->index != -1) {
|
2016-05-30 17:30:06 +02:00
|
|
|
if (is_aux) {
|
|
|
|
|
BKE_shrinkwrap_snap_point_to_surface(aux_tree,
|
2018-10-03 19:09:43 +03:00
|
|
|
local2aux,
|
2018-10-18 12:03:04 +11:00
|
|
|
calc->smd->shrinkMode,
|
|
|
|
|
hit->index,
|
|
|
|
|
hit->co,
|
|
|
|
|
hit->no,
|
|
|
|
|
calc->keepDist,
|
|
|
|
|
tmp_co,
|
|
|
|
|
hit->co);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BKE_shrinkwrap_snap_point_to_surface(tree,
|
2018-10-18 12:03:04 +11:00
|
|
|
&calc->local2target,
|
|
|
|
|
calc->smd->shrinkMode,
|
|
|
|
|
hit->index,
|
|
|
|
|
hit->co,
|
|
|
|
|
hit->no,
|
|
|
|
|
calc->keepDist,
|
|
|
|
|
tmp_co,
|
|
|
|
|
hit->co);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
interp_v3_v3v3(co, co, hit->co, weight);
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-05-02 00:16:48 +00:00
|
|
|
|
2018-05-30 11:34:08 +02:00
|
|
|
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc)
|
2008-07-09 19:43:09 +00:00
|
|
|
{
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Options about projection direction */
|
2012-05-11 08:05:47 +00:00
|
|
|
float proj_axis[3] = {0.0f, 0.0f, 0.0f};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-18 11:16:24 +11:00
|
|
|
/* Ray-cast and tree stuff. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-05 05:07:57 +00:00
|
|
|
/** \note 'hit.dist' is kept in the targets space, this is only used
|
|
|
|
|
* for finding the best hit, to get the real dist,
|
|
|
|
|
* measure the len_v3v3() from the input coord to hit.co */
|
2008-08-12 20:43:10 +00:00
|
|
|
BVHTreeRayHit hit;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* auxiliary target */
|
2022-10-06 15:15:49 -05:00
|
|
|
Mesh *auxMesh = nullptr;
|
|
|
|
|
ShrinkwrapTreeData *aux_tree = nullptr;
|
2018-10-03 19:09:43 +03:00
|
|
|
ShrinkwrapTreeData aux_tree_stack;
|
2008-08-12 20:43:10 +00:00
|
|
|
SpaceTransform local2aux;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* If the user doesn't allows to project in any direction of projection axis
|
2018-09-24 17:27:41 +02:00
|
|
|
* then there's nothing todo. */
|
2014-02-03 18:55:59 +11:00
|
|
|
if ((calc->smd->shrinkOpts &
|
2019-04-22 09:39:35 +10:00
|
|
|
(MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
|
|
|
|
|
{
|
2009-05-23 03:24:15 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Prepare data to retrieve the direction in which we should project each vertex */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
if (calc->vert_positions == nullptr) {
|
2012-03-24 06:18:31 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2008-08-12 20:43:10 +00:00
|
|
|
}
|
2012-03-06 18:40:15 +00:00
|
|
|
else {
|
2012-10-20 20:20:02 +00:00
|
|
|
/* The code supports any axis that is a combination of X,Y,Z
|
|
|
|
|
* although currently UI only allows to set the 3 different axis */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) {
|
2012-03-24 06:18:31 +00:00
|
|
|
proj_axis[0] = 1.0f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) {
|
2012-03-24 06:18:31 +00:00
|
|
|
proj_axis[1] = 1.0f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) {
|
2012-03-24 06:18:31 +00:00
|
|
|
proj_axis[2] = 1.0f;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-10 20:43:45 +00:00
|
|
|
normalize_v3(proj_axis);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Invalid projection direction */
|
2012-11-05 04:19:30 +00:00
|
|
|
if (len_squared_v3(proj_axis) < FLT_EPSILON) {
|
|
|
|
|
return;
|
2008-07-25 18:48:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-12-07 15:45:53 +01:00
|
|
|
if (calc->aux_target) {
|
2022-07-20 15:57:16 +02:00
|
|
|
auxMesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(calc->aux_target);
|
2019-04-22 09:39:35 +10:00
|
|
|
if (!auxMesh) {
|
2010-12-17 20:13:54 +00:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2018-12-07 15:45:53 +01:00
|
|
|
BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->aux_target);
|
2008-07-18 22:24:20 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_init_tree(
|
|
|
|
|
&aux_tree_stack, auxMesh, calc->smd->shrinkType, calc->smd->shrinkMode, false))
|
|
|
|
|
{
|
|
|
|
|
aux_tree = &aux_tree_stack;
|
2008-07-09 19:43:09 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* After successfully build the trees, start projection vertices. */
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData data{};
|
|
|
|
|
data.calc = calc;
|
|
|
|
|
data.tree = calc->tree;
|
|
|
|
|
data.aux_tree = aux_tree;
|
|
|
|
|
data.proj_axis = proj_axis;
|
|
|
|
|
data.local2aux = &local2aux;
|
2019-07-30 14:56:47 +02:00
|
|
|
TaskParallelSettings settings;
|
2018-10-03 19:09:43 +03:00
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
2023-04-27 16:23:42 -04:00
|
|
|
settings.use_threading = (calc->numVerts > 10000);
|
2018-10-03 19:09:43 +03:00
|
|
|
settings.userdata_chunk = &hit;
|
|
|
|
|
settings.userdata_chunk_size = sizeof(hit);
|
|
|
|
|
BLI_task_parallel_range(
|
|
|
|
|
0, calc->numVerts, &data, shrinkwrap_calc_normal_projection_cb_ex, &settings);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* free data structures */
|
|
|
|
|
if (aux_tree) {
|
|
|
|
|
BKE_shrinkwrap_free_tree(aux_tree);
|
2016-05-06 04:49:21 +10:00
|
|
|
}
|
2008-07-09 19:43:09 +00:00
|
|
|
}
|
|
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/*
|
|
|
|
|
* Shrinkwrap Target Surface Project mode
|
|
|
|
|
*
|
|
|
|
|
* It uses Newton's method to find a surface location with its
|
|
|
|
|
* smooth normal pointing at the original point.
|
|
|
|
|
*
|
|
|
|
|
* The equation system on barycentric weights and normal multiplier:
|
|
|
|
|
*
|
|
|
|
|
* (w0*V0 + w1*V1 + w2*V2) + l * (w0*N0 + w1*N1 + w2*N2) - CO = 0
|
|
|
|
|
* w0 + w1 + w2 = 1
|
|
|
|
|
*
|
|
|
|
|
* The actual solution vector is [ w0, w1, l ], with w2 eliminated.
|
|
|
|
|
*/
|
|
|
|
|
|
2024-01-02 18:12:54 +01:00
|
|
|
// #define TRACE_TARGET_PROJECT
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
struct TargetProjectTriData {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
const float **vtri_co;
|
|
|
|
|
const float (*vtri_no)[3];
|
|
|
|
|
const float *point_co;
|
|
|
|
|
|
|
|
|
|
float n0_minus_n2[3], n1_minus_n2[3];
|
|
|
|
|
float c0_minus_c2[3], c1_minus_c2[3];
|
|
|
|
|
|
|
|
|
|
/* Current interpolated position and normal. */
|
|
|
|
|
float co_interp[3], no_interp[3];
|
2022-10-06 15:15:49 -05:00
|
|
|
};
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
/* Computes the deviation of the equation system from goal. */
|
|
|
|
|
static void target_project_tri_deviation(void *userdata, const float x[3], float r_delta[3])
|
|
|
|
|
{
|
2022-10-06 15:15:49 -05:00
|
|
|
TargetProjectTriData *data = static_cast<TargetProjectTriData *>(userdata);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
2020-08-07 22:36:11 +10:00
|
|
|
const float w[3] = {x[0], x[1], 1.0f - x[0] - x[1]};
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
interp_v3_v3v3v3(data->co_interp, data->vtri_co[0], data->vtri_co[1], data->vtri_co[2], w);
|
|
|
|
|
interp_v3_v3v3v3(data->no_interp, data->vtri_no[0], data->vtri_no[1], data->vtri_no[2], w);
|
|
|
|
|
|
|
|
|
|
madd_v3_v3v3fl(r_delta, data->co_interp, data->no_interp, x[2]);
|
|
|
|
|
sub_v3_v3(r_delta, data->point_co);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Computes the Jacobian matrix of the equation system. */
|
|
|
|
|
static void target_project_tri_jacobian(void *userdata, const float x[3], float r_jacobian[3][3])
|
|
|
|
|
{
|
2022-10-06 15:15:49 -05:00
|
|
|
TargetProjectTriData *data = static_cast<TargetProjectTriData *>(userdata);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
madd_v3_v3v3fl(r_jacobian[0], data->c0_minus_c2, data->n0_minus_n2, x[2]);
|
|
|
|
|
madd_v3_v3v3fl(r_jacobian[1], data->c1_minus_c2, data->n1_minus_n2, x[2]);
|
|
|
|
|
|
|
|
|
|
copy_v3_v3(r_jacobian[2], data->vtri_no[2]);
|
|
|
|
|
madd_v3_v3fl(r_jacobian[2], data->n0_minus_n2, x[0]);
|
|
|
|
|
madd_v3_v3fl(r_jacobian[2], data->n1_minus_n2, x[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clamp barycentric weights to the triangle. */
|
|
|
|
|
static void target_project_tri_clamp(float x[3])
|
|
|
|
|
{
|
2025-01-26 20:07:57 +01:00
|
|
|
x[0] = std::max(x[0], 0.0f);
|
|
|
|
|
x[1] = std::max(x[1], 0.0f);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
if (x[0] + x[1] > 1.0f) {
|
|
|
|
|
x[0] = x[0] / (x[0] + x[1]);
|
|
|
|
|
x[1] = 1.0f - x[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Correct the Newton's method step to keep the coordinates within the triangle. */
|
2022-10-06 15:15:49 -05:00
|
|
|
static bool target_project_tri_correct(void * /*userdata*/,
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
const float x[3],
|
|
|
|
|
float step[3],
|
|
|
|
|
float x_next[3])
|
|
|
|
|
{
|
|
|
|
|
/* Insignificant correction threshold */
|
2019-12-25 13:08:06 +03:00
|
|
|
const float epsilon = 1e-5f;
|
|
|
|
|
/* Dot product threshold for checking if step is 'clearly' pointing outside. */
|
|
|
|
|
const float dir_epsilon = 0.5f;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
bool fixed = false, locked = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-25 13:08:06 +03:00
|
|
|
/* The barycentric coordinate domain is a triangle bounded by
|
|
|
|
|
* the X and Y axes, plus the x+y=1 diagonal. First, clamp the
|
|
|
|
|
* movement against the diagonal. Note that step is subtracted. */
|
|
|
|
|
float sum = x[0] + x[1];
|
|
|
|
|
float sstep = -(step[0] + step[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-25 13:08:06 +03:00
|
|
|
if (sum + sstep > 1.0f) {
|
|
|
|
|
float ldist = 1.0f - sum;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-25 13:08:06 +03:00
|
|
|
/* If already at the boundary, slide along it. */
|
2022-10-06 15:15:49 -05:00
|
|
|
if (ldist < epsilon * float(M_SQRT2)) {
|
2019-12-25 13:08:06 +03:00
|
|
|
float step_len = len_v2(step);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Abort if the solution is clearly outside the domain. */
|
2022-10-06 15:15:49 -05:00
|
|
|
if (step_len > epsilon && sstep > step_len * dir_epsilon * float(M_SQRT2)) {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-12-25 13:08:06 +03:00
|
|
|
/* Project the new position onto the diagonal. */
|
|
|
|
|
add_v2_fl(step, (sum + sstep - 1.0f) * 0.5f);
|
|
|
|
|
fixed = locked = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Scale a significant step down to arrive at the boundary. */
|
2019-12-25 13:08:06 +03:00
|
|
|
mul_v3_fl(step, ldist / sstep);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
fixed = true;
|
|
|
|
|
}
|
2019-12-25 13:08:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Weight 0 and 1 boundary checks - along axis. */
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
|
if (step[i] > x[i]) {
|
|
|
|
|
/* If already at the boundary, slide along it. */
|
|
|
|
|
if (x[i] < epsilon) {
|
|
|
|
|
float step_len = len_v2(step);
|
|
|
|
|
|
|
|
|
|
/* Abort if the solution is clearly outside the domain. */
|
|
|
|
|
if (step_len > epsilon && (locked || step[i] > step_len * dir_epsilon)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Reset precision errors to stay at the boundary. */
|
|
|
|
|
step[i] = x[i];
|
|
|
|
|
fixed = true;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
|
|
|
|
else {
|
2019-12-25 13:08:06 +03:00
|
|
|
/* Scale a significant step down to arrive at the boundary. */
|
|
|
|
|
mul_v3_fl(step, x[i] / step[i]);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
fixed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Recompute and clamp the new coordinates after step correction. */
|
|
|
|
|
if (fixed) {
|
|
|
|
|
sub_v3_v3v3(x_next, x, step);
|
|
|
|
|
target_project_tri_clamp(x_next);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool target_project_solve_point_tri(const float *vtri_co[3],
|
|
|
|
|
const float vtri_no[3][3],
|
|
|
|
|
const float point_co[3],
|
|
|
|
|
const float hit_co[3],
|
|
|
|
|
float hit_dist_sq,
|
|
|
|
|
float r_hit_co[3],
|
|
|
|
|
float r_hit_no[3])
|
|
|
|
|
{
|
|
|
|
|
float x[3], tmp[3];
|
|
|
|
|
float dist = sqrtf(hit_dist_sq);
|
2019-10-20 00:15:10 +03:00
|
|
|
float magnitude_estimate = dist + len_manhattan_v3(vtri_co[0]) + len_manhattan_v3(vtri_co[1]) +
|
|
|
|
|
len_manhattan_v3(vtri_co[2]);
|
|
|
|
|
float epsilon = magnitude_estimate * 1.0e-6f;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
/* Initial solution vector: barycentric weights plus distance along normal. */
|
|
|
|
|
interp_weights_tri_v3(x, UNPACK3(vtri_co), hit_co);
|
|
|
|
|
|
|
|
|
|
interp_v3_v3v3v3(r_hit_no, UNPACK3(vtri_no), x);
|
|
|
|
|
sub_v3_v3v3(tmp, point_co, hit_co);
|
|
|
|
|
|
|
|
|
|
x[2] = (dot_v3v3(tmp, r_hit_no) < 0) ? -dist : dist;
|
|
|
|
|
|
|
|
|
|
/* Solve the equations iteratively. */
|
2022-10-06 15:15:49 -05:00
|
|
|
TargetProjectTriData tri_data{};
|
|
|
|
|
tri_data.vtri_co = vtri_co;
|
|
|
|
|
tri_data.vtri_no = vtri_no;
|
|
|
|
|
tri_data.point_co = point_co;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
sub_v3_v3v3(tri_data.n0_minus_n2, vtri_no[0], vtri_no[2]);
|
|
|
|
|
sub_v3_v3v3(tri_data.n1_minus_n2, vtri_no[1], vtri_no[2]);
|
|
|
|
|
sub_v3_v3v3(tri_data.c0_minus_c2, vtri_co[0], vtri_co[2]);
|
|
|
|
|
sub_v3_v3v3(tri_data.c1_minus_c2, vtri_co[1], vtri_co[2]);
|
|
|
|
|
|
|
|
|
|
target_project_tri_clamp(x);
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
|
|
|
|
const bool trace = true;
|
|
|
|
|
#else
|
|
|
|
|
const bool trace = false;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool ok = BLI_newton3d_solve(target_project_tri_deviation,
|
|
|
|
|
target_project_tri_jacobian,
|
|
|
|
|
target_project_tri_correct,
|
|
|
|
|
&tri_data,
|
|
|
|
|
epsilon,
|
|
|
|
|
20,
|
|
|
|
|
trace,
|
|
|
|
|
x,
|
|
|
|
|
x);
|
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
copy_v3_v3(r_hit_co, tri_data.co_interp);
|
|
|
|
|
copy_v3_v3(r_hit_no, tri_data.no_interp);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool update_hit(BVHTreeNearest *nearest,
|
|
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
|
|
|
|
const float hit_co[3],
|
|
|
|
|
const float hit_no[3])
|
|
|
|
|
{
|
|
|
|
|
float dist_sq = len_squared_v3v3(hit_co, co);
|
|
|
|
|
|
|
|
|
|
if (dist_sq < nearest->dist_sq) {
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
|
|
|
|
printf(
|
2019-10-20 00:15:10 +03:00
|
|
|
"#=#=#> %d (%.3f,%.3f,%.3f) %g < %g\n", index, UNPACK3(hit_co), dist_sq, nearest->dist_sq);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
#endif
|
|
|
|
|
nearest->index = index;
|
|
|
|
|
nearest->dist_sq = dist_sq;
|
|
|
|
|
copy_v3_v3(nearest->co, hit_co);
|
|
|
|
|
normalize_v3_v3(nearest->no, hit_no);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-27 12:07:07 +10:00
|
|
|
/* Target projection on a non-manifold boundary edge -
|
|
|
|
|
* treats it like an infinitely thin cylinder. */
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
static void target_project_edge(const ShrinkwrapTreeData *tree,
|
|
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
|
|
|
|
BVHTreeNearest *nearest,
|
|
|
|
|
int eidx)
|
|
|
|
|
{
|
2024-12-17 18:22:00 -05:00
|
|
|
const blender::bke::BVHTreeFromMesh *data = &tree->treeData;
|
2024-12-04 00:17:17 +01:00
|
|
|
const blender::int2 &edge = tree->edges[eidx];
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
const float *vedge_co[2] = {data->vert_positions[edge[0]], data->vert_positions[edge[1]]};
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
|
|
|
|
printf("EDGE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f)\n",
|
|
|
|
|
eidx,
|
|
|
|
|
UNPACK3(vedge_co[0]),
|
|
|
|
|
UNPACK3(vedge_co[1]));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Retrieve boundary vertex IDs */
|
2023-12-04 15:22:00 -05:00
|
|
|
const int *vert_boundary_id = tree->boundary->vert_boundary_id.data();
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
int bid1 = vert_boundary_id[edge[0]], bid2 = vert_boundary_id[edge[1]];
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
if (bid1 < 0 || bid2 < 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve boundary vertex normals and align them to direction. */
|
2023-12-04 15:22:00 -05:00
|
|
|
const ShrinkwrapBoundaryVertData *boundary_verts = tree->boundary->boundary_verts.data();
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
float vedge_dir[2][3], dir[3];
|
|
|
|
|
|
|
|
|
|
copy_v3_v3(vedge_dir[0], boundary_verts[bid1].normal_plane);
|
|
|
|
|
copy_v3_v3(vedge_dir[1], boundary_verts[bid2].normal_plane);
|
|
|
|
|
|
|
|
|
|
sub_v3_v3v3(dir, vedge_co[1], vedge_co[0]);
|
|
|
|
|
|
|
|
|
|
if (dot_v3v3(boundary_verts[bid1].direction, dir) < 0) {
|
|
|
|
|
negate_v3(vedge_dir[0]);
|
|
|
|
|
}
|
|
|
|
|
if (dot_v3v3(boundary_verts[bid2].direction, dir) < 0) {
|
|
|
|
|
negate_v3(vedge_dir[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Solve a quadratic equation: lerp(d0,d1,x) * (co - lerp(v0,v1,x)) = 0 */
|
|
|
|
|
float d0v0 = dot_v3v3(vedge_dir[0], vedge_co[0]), d0v1 = dot_v3v3(vedge_dir[0], vedge_co[1]);
|
|
|
|
|
float d1v0 = dot_v3v3(vedge_dir[1], vedge_co[0]), d1v1 = dot_v3v3(vedge_dir[1], vedge_co[1]);
|
|
|
|
|
float d0co = dot_v3v3(vedge_dir[0], co);
|
|
|
|
|
|
|
|
|
|
float a = d0v1 - d0v0 + d1v0 - d1v1;
|
|
|
|
|
float b = 2 * d0v0 - d0v1 - d0co - d1v0 + dot_v3v3(vedge_dir[1], co);
|
|
|
|
|
float c = d0co - d0v0;
|
|
|
|
|
float det = b * b - 4 * a * c;
|
|
|
|
|
|
2025-01-20 10:05:34 +01:00
|
|
|
if (det >= 0 && a != 0) {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
const float epsilon = 1e-6f;
|
|
|
|
|
float sdet = sqrtf(det);
|
|
|
|
|
float hit_co[3], hit_no[3];
|
|
|
|
|
|
|
|
|
|
for (int i = (det > 0 ? 2 : 0); i >= 0; i -= 2) {
|
2022-10-06 15:15:49 -05:00
|
|
|
float x = (-b + (float(i) - 1) * sdet) / (2 * a);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
if (x >= -epsilon && x <= 1.0f + epsilon) {
|
|
|
|
|
CLAMP(x, 0, 1);
|
|
|
|
|
|
|
|
|
|
float vedge_no[2][3];
|
Mesh: Move edges to a generic attribute
Implements #95966, as the final step of #95965.
This commit changes the storage of mesh edge vertex indices from the
`MEdge` type to the generic `int2` attribute type. This follows the
general design for geometry and the attribute system, where the data
storage type and the usage semantics are separated.
The main benefit of the change is reduced memory usage-- the
requirements of storing mesh edges is reduced by 1/3. For example,
this saves 8MB on a 1 million vertex grid. This also gives performance
benefits to any memory-bound mesh processing algorithm that uses edges.
Another benefit is that all of the edge's vertex indices are
contiguous. In a few cases, it's helpful to process all of them as
`Span<int>` rather than `Span<int2>`. Similarly, the type is more
likely to match a generic format used by a library, or code that
shouldn't know about specific Blender `Mesh` types.
Various Notes:
- The `.edge_verts` name is used to reflect a mapping between domains,
similar to `.corner_verts`, etc. The period means that it the data
shouldn't change arbitrarily by the user or procedural operations.
- `edge[0]` is now used instead of `edge.v1`
- Signed integers are used instead of unsigned to reduce the mixing
of signed-ness, which can be error prone.
- All of the previously used core mesh data types (`MVert`, `MEdge`,
`MLoop`, `MPoly` are now deprecated. Only generic types are used).
- The `vec2i` DNA type is used in the few C files where necessary.
Pull Request: https://projects.blender.org/blender/blender/pulls/106638
2023-04-17 13:47:41 +02:00
|
|
|
copy_v3_v3(vedge_no[0], tree->vert_normals[edge[0]]);
|
|
|
|
|
copy_v3_v3(vedge_no[1], tree->vert_normals[edge[1]]);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
|
|
|
|
|
interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
|
|
|
|
|
|
|
|
|
|
update_hit(nearest, index, co, hit_co, hit_no);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 14:57:49 +01:00
|
|
|
/* Target normal projection BVH callback - based on mesh_corner_tri_nearest_point. */
|
|
|
|
|
static void mesh_corner_tris_target_project(void *userdata,
|
|
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
|
|
|
|
BVHTreeNearest *nearest)
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
{
|
2023-11-28 16:40:43 -05:00
|
|
|
using namespace blender;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
const ShrinkwrapTreeData *tree = (ShrinkwrapTreeData *)userdata;
|
2024-12-17 18:22:00 -05:00
|
|
|
const blender::bke::BVHTreeFromMesh *data = &tree->treeData;
|
2023-12-19 14:57:49 +01:00
|
|
|
const int3 &tri = data->corner_tris[index];
|
2023-12-14 12:08:21 +11:00
|
|
|
const int tri_verts[3] = {
|
2023-12-19 14:57:49 +01:00
|
|
|
data->corner_verts[tri[0]],
|
|
|
|
|
data->corner_verts[tri[1]],
|
|
|
|
|
data->corner_verts[tri[2]],
|
2023-12-14 12:08:21 +11:00
|
|
|
};
|
|
|
|
|
const float *vtri_co[3] = {
|
|
|
|
|
data->vert_positions[tri_verts[0]],
|
|
|
|
|
data->vert_positions[tri_verts[1]],
|
|
|
|
|
data->vert_positions[tri_verts[2]],
|
|
|
|
|
};
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
float raw_hit_co[3], hit_co[3], hit_no[3], dist_sq, vtri_no[3][3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* First find the closest point and bail out if it's worse than the current solution. */
|
|
|
|
|
closest_on_tri_to_point_v3(raw_hit_co, co, UNPACK3(vtri_co));
|
|
|
|
|
dist_sq = len_squared_v3v3(co, raw_hit_co);
|
|
|
|
|
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
|
|
|
|
printf("TRIANGLE %d (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f) %g %g\n",
|
|
|
|
|
index,
|
|
|
|
|
UNPACK3(vtri_co[0]),
|
|
|
|
|
UNPACK3(vtri_co[1]),
|
|
|
|
|
UNPACK3(vtri_co[2]),
|
|
|
|
|
dist_sq,
|
|
|
|
|
nearest->dist_sq);
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (dist_sq >= nearest->dist_sq) {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
return;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Decode normals */
|
Mesh: Replace MLoop struct with generic attributes
Implements #102359.
Split the `MLoop` struct into two separate integer arrays called
`corner_verts` and `corner_edges`, referring to the vertex each corner
is attached to and the next edge around the face at each corner. These
arrays can be sliced to give access to the edges or vertices in a face.
Then they are often referred to as "poly_verts" or "poly_edges".
The main benefits are halving the necessary memory bandwidth when only
one array is used and simplifications from using regular integer indices
instead of a special-purpose struct.
The commit also starts a renaming from "loop" to "corner" in mesh code.
Like the other mesh struct of array refactors, forward compatibility is
kept by writing files with the older format. This will be done until 4.0
to ease the transition process.
Looking at a small portion of the patch should give a good impression
for the rest of the changes. I tried to make the changes as small as
possible so it's easy to tell the correctness from the diff. Though I
found Blender developers have been very inventive over the last decade
when finding different ways to loop over the corners in a face.
For performance, nearly every piece of code that deals with `Mesh` is
slightly impacted. Any algorithm that is memory bottle-necked should
see an improvement. For example, here is a comparison of interpolating
a vertex float attribute to face corners (Ryzen 3700x):
**Before** (Average: 3.7 ms, Min: 3.4 ms)
```
threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) {
for (const int64_t i : range) {
dst[i] = src[loops[i].v];
}
});
```
**After** (Average: 2.9 ms, Min: 2.6 ms)
```
array_utils::gather(src, corner_verts, dst);
```
That's an improvement of 28% to the average timings, and it's also a
simplification, since an index-based routine can be used instead.
For more examples using the new arrays, see the design task.
Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
|
|
|
copy_v3_v3(vtri_no[0], tree->vert_normals[tri_verts[0]]);
|
|
|
|
|
copy_v3_v3(vtri_no[1], tree->vert_normals[tri_verts[1]]);
|
|
|
|
|
copy_v3_v3(vtri_no[2], tree->vert_normals[tri_verts[2]]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
/* Solve the equations for the triangle */
|
|
|
|
|
if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
|
|
|
|
|
update_hit(nearest, index, co, hit_co, hit_no);
|
|
|
|
|
}
|
|
|
|
|
/* Boundary edges */
|
2024-03-29 11:43:15 +01:00
|
|
|
else if (tree->boundary && tree->boundary->has_boundary() &&
|
|
|
|
|
tree->boundary->tri_has_boundary[index])
|
|
|
|
|
{
|
2023-12-04 15:22:00 -05:00
|
|
|
const BitSpan is_boundary = tree->boundary->edge_is_boundary;
|
2023-12-19 14:57:49 +01:00
|
|
|
const int3 edges = bke::mesh::corner_tri_get_real_edges(
|
2024-12-04 00:17:17 +01:00
|
|
|
tree->edges, data->corner_verts, tree->corner_edges, tri);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2023-12-04 15:22:00 -05:00
|
|
|
if (edges[i] >= 0 && is_boundary[edges[i]]) {
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
target_project_edge(tree, index, co, nearest, edges[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
void BKE_shrinkwrap_find_nearest_surface(ShrinkwrapTreeData *tree,
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
BVHTreeNearest *nearest,
|
|
|
|
|
float co[3],
|
|
|
|
|
int type)
|
|
|
|
|
{
|
2024-12-17 18:22:00 -05:00
|
|
|
blender::bke::BVHTreeFromMesh *treeData = &tree->treeData;
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
if (type == MOD_SHRINKWRAP_TARGET_PROJECT) {
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
2019-10-20 00:15:10 +03:00
|
|
|
printf("\n====== TARGET PROJECT START ======\n");
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
BLI_bvhtree_find_nearest_ex(
|
2023-12-19 14:57:49 +01:00
|
|
|
tree->bvh, co, nearest, mesh_corner_tris_target_project, tree, BVH_NEAREST_OPTIMAL_ORDER);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
2019-10-20 00:15:10 +03:00
|
|
|
printf("====== TARGET PROJECT END: %d %g ======\n\n", nearest->index, nearest->dist_sq);
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (nearest->index < 0) {
|
|
|
|
|
/* fallback to simple nearest */
|
|
|
|
|
BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BLI_bvhtree_find_nearest(tree->bvh, co, nearest, treeData->nearest_callback, treeData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-07 10:32:02 +11:00
|
|
|
/**
|
|
|
|
|
* Shrink-wrap moving vertices to the nearest surface point on the target.
|
2008-05-26 21:57:53 +00:00
|
|
|
*
|
2022-10-07 10:32:02 +11:00
|
|
|
* It builds a #BVHTree from the target mesh and then performs a
|
2012-03-01 12:20:18 +00:00
|
|
|
* NN matches for each vertex
|
2008-05-26 21:57:53 +00:00
|
|
|
*/
|
2016-05-30 17:30:06 +02:00
|
|
|
static void shrinkwrap_calc_nearest_surface_point_cb_ex(void *__restrict userdata,
|
2018-01-10 12:49:51 +01:00
|
|
|
const int i,
|
2019-07-30 14:56:47 +02:00
|
|
|
const TaskParallelTLS *__restrict tls)
|
2008-05-26 21:57:53 +00:00
|
|
|
{
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData *data = static_cast<ShrinkwrapCalcCBData *>(userdata);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
ShrinkwrapCalcData *calc = data->calc;
|
2022-10-06 15:15:49 -05:00
|
|
|
BVHTreeNearest *nearest = static_cast<BVHTreeNearest *>(tls->userdata_chunk);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
float *co = calc->vertexCos[i];
|
|
|
|
|
float tmp_co[3];
|
2025-02-26 15:56:08 +01:00
|
|
|
float weight = BKE_defvert_array_find_weight_safe(
|
|
|
|
|
calc->dvert, i, calc->vgroup, calc->invert_vgroup);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
if (weight == 0.0f) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Convert the vertex to tree coordinates */
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
if (calc->vert_positions) {
|
|
|
|
|
copy_v3_v3(tmp_co, calc->vert_positions[i]);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(tmp_co, co);
|
|
|
|
|
}
|
|
|
|
|
BLI_space_transform_apply(&calc->local2target, tmp_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Use local proximity heuristics (to reduce the nearest search)
|
|
|
|
|
*
|
2019-04-27 12:07:07 +10:00
|
|
|
* If we already had an hit before.. we assume this vertex is going to have a close hit to that
|
|
|
|
|
* other vertex so we can initiate the "nearest.dist" with the expected value to that last hit.
|
2016-05-30 17:30:06 +02:00
|
|
|
* This will lead in pruning of the search tree. */
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
if (nearest->index != -1) {
|
|
|
|
|
if (calc->smd->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {
|
|
|
|
|
/* Heuristic doesn't work because of additional restrictions. */
|
|
|
|
|
nearest->index = -1;
|
|
|
|
|
nearest->dist_sq = FLT_MAX;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
nearest->dist_sq = len_squared_v3v3(tmp_co, nearest->co);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
else {
|
2016-05-30 17:30:06 +02:00
|
|
|
nearest->dist_sq = FLT_MAX;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
BKE_shrinkwrap_find_nearest_surface(data->tree, nearest, tmp_co, calc->smd->shrinkType);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-30 17:30:06 +02:00
|
|
|
/* Found the nearest vertex */
|
|
|
|
|
if (nearest->index != -1) {
|
2018-10-03 19:09:43 +03:00
|
|
|
BKE_shrinkwrap_snap_point_to_surface(data->tree,
|
2022-10-06 15:15:49 -05:00
|
|
|
nullptr,
|
2018-10-18 12:03:04 +11:00
|
|
|
calc->smd->shrinkMode,
|
|
|
|
|
nearest->index,
|
|
|
|
|
nearest->co,
|
|
|
|
|
nearest->no,
|
|
|
|
|
calc->keepDist,
|
|
|
|
|
tmp_co,
|
|
|
|
|
tmp_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
/* Convert the coordinates back to mesh coordinates */
|
|
|
|
|
BLI_space_transform_invert(&calc->local2target, tmp_co);
|
|
|
|
|
interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
|
|
|
|
|
const SpaceTransform *transform,
|
2023-12-19 14:57:49 +01:00
|
|
|
int corner_tri_idx,
|
2018-10-03 19:09:43 +03:00
|
|
|
const float hit_co[3],
|
|
|
|
|
const float hit_no[3],
|
|
|
|
|
float r_no[3])
|
|
|
|
|
{
|
2023-12-19 14:57:49 +01:00
|
|
|
using namespace blender;
|
2024-12-17 18:22:00 -05:00
|
|
|
const blender::bke::BVHTreeFromMesh *treeData = &tree->treeData;
|
2023-12-19 14:57:49 +01:00
|
|
|
const int3 &tri = treeData->corner_tris[corner_tri_idx];
|
|
|
|
|
const int face_i = tree->mesh->corner_tri_faces()[corner_tri_idx];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* Interpolate smooth normals if enabled. */
|
2024-03-28 14:45:52 -04:00
|
|
|
if (tree->sharp_faces.is_empty() || tree->sharp_faces[face_i]) {
|
2023-12-19 14:57:49 +01:00
|
|
|
const int vert_indices[3] = {treeData->corner_verts[tri[0]],
|
|
|
|
|
treeData->corner_verts[tri[1]],
|
|
|
|
|
treeData->corner_verts[tri[2]]};
|
2018-10-03 19:09:43 +03:00
|
|
|
float w[3], no[3][3], tmp_co[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* Custom and auto smooth split normals. */
|
2023-11-28 16:40:43 -05:00
|
|
|
if (!tree->corner_normals.is_empty()) {
|
2023-12-19 14:57:49 +01:00
|
|
|
copy_v3_v3(no[0], tree->corner_normals[tri[0]]);
|
|
|
|
|
copy_v3_v3(no[1], tree->corner_normals[tri[1]]);
|
|
|
|
|
copy_v3_v3(no[2], tree->corner_normals[tri[2]]);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
|
|
|
|
/* Ordinary vertex normals. */
|
|
|
|
|
else {
|
2023-11-28 16:40:43 -05:00
|
|
|
copy_v3_v3(no[0], tree->vert_normals[vert_indices[0]]);
|
|
|
|
|
copy_v3_v3(no[1], tree->vert_normals[vert_indices[1]]);
|
|
|
|
|
copy_v3_v3(no[2], tree->vert_normals[vert_indices[2]]);
|
2018-10-03 19:09:43 +03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* Barycentric weights from hit point. */
|
|
|
|
|
copy_v3_v3(tmp_co, hit_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (transform) {
|
|
|
|
|
BLI_space_transform_apply(transform, tmp_co);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
interp_weights_tri_v3(w,
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
treeData->vert_positions[vert_indices[0]],
|
|
|
|
|
treeData->vert_positions[vert_indices[1]],
|
|
|
|
|
treeData->vert_positions[vert_indices[2]],
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
tmp_co);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
/* Interpolate using weights. */
|
|
|
|
|
interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (transform) {
|
|
|
|
|
BLI_space_transform_invert_normal(transform, r_no);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
normalize_v3(r_no);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Use the face normal if flat. */
|
2023-11-28 16:40:43 -05:00
|
|
|
else if (!tree->face_normals.is_empty()) {
|
2023-07-24 22:06:55 +02:00
|
|
|
copy_v3_v3(r_no, tree->face_normals[face_i]);
|
2024-03-28 13:41:03 -04:00
|
|
|
if (transform) {
|
|
|
|
|
BLI_space_transform_invert_normal(transform, r_no);
|
|
|
|
|
}
|
2018-12-05 20:24:05 +03:00
|
|
|
}
|
2023-12-19 14:57:49 +01:00
|
|
|
/* Finally fallback to the corner_tris normal. */
|
2018-10-03 19:09:43 +03:00
|
|
|
else {
|
|
|
|
|
copy_v3_v3(r_no, hit_no);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */
|
|
|
|
|
static void shrinkwrap_snap_with_side(float r_point_co[3],
|
|
|
|
|
const float point_co[3],
|
|
|
|
|
const float hit_co[3],
|
|
|
|
|
const float hit_no[3],
|
|
|
|
|
float goal_dist,
|
|
|
|
|
float forcesign,
|
|
|
|
|
bool forcesnap)
|
|
|
|
|
{
|
2019-10-20 00:15:10 +03:00
|
|
|
float delta[3];
|
|
|
|
|
sub_v3_v3v3(delta, point_co, hit_co);
|
|
|
|
|
|
|
|
|
|
float dist = len_v3(delta);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
/* If exactly on the surface, push out along normal */
|
|
|
|
|
if (dist < FLT_EPSILON) {
|
2019-01-10 11:55:09 +03:00
|
|
|
if (forcesnap || goal_dist > 0) {
|
|
|
|
|
madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(r_point_co, hit_co);
|
|
|
|
|
}
|
2018-07-07 18:39:45 +03:00
|
|
|
}
|
|
|
|
|
/* Move to the correct side if needed */
|
|
|
|
|
else {
|
2019-10-20 00:15:10 +03:00
|
|
|
float dsign = signf(dot_v3v3(delta, hit_no));
|
|
|
|
|
|
|
|
|
|
if (forcesign == 0.0f) {
|
|
|
|
|
forcesign = dsign;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
/* If on the wrong side or too close, move to correct */
|
2019-10-20 00:15:10 +03:00
|
|
|
if (forcesnap || dsign * dist * forcesign < goal_dist) {
|
|
|
|
|
mul_v3_fl(delta, dsign / dist);
|
|
|
|
|
|
|
|
|
|
/* At very small distance, blend in the hit normal to stabilize math. */
|
|
|
|
|
float dist_epsilon = (fabsf(goal_dist) + len_manhattan_v3(hit_co)) * 1e-4f;
|
|
|
|
|
|
|
|
|
|
if (dist < dist_epsilon) {
|
|
|
|
|
#ifdef TRACE_TARGET_PROJECT
|
|
|
|
|
printf("zero_factor %g = %g / %g\n", dist / dist_epsilon, dist, dist_epsilon);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
interp_v3_v3v3(delta, hit_no, delta, dist / dist_epsilon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
madd_v3_v3v3fl(r_point_co, hit_co, delta, goal_dist * forcesign);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2018-07-07 18:39:45 +03:00
|
|
|
copy_v3_v3(r_point_co, point_co);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
void BKE_shrinkwrap_snap_point_to_surface(const ShrinkwrapTreeData *tree,
|
|
|
|
|
const SpaceTransform *transform,
|
2018-10-03 19:09:43 +03:00
|
|
|
int mode,
|
|
|
|
|
int hit_idx,
|
|
|
|
|
const float hit_co[3],
|
|
|
|
|
const float hit_no[3],
|
|
|
|
|
float goal_dist,
|
2018-07-07 18:39:45 +03:00
|
|
|
const float point_co[3],
|
|
|
|
|
float r_point_co[3])
|
|
|
|
|
{
|
2019-10-20 00:15:10 +03:00
|
|
|
float tmp[3];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
switch (mode) {
|
|
|
|
|
/* Offsets along the line between point_co and hit_co. */
|
|
|
|
|
case MOD_SHRINKWRAP_ON_SURFACE:
|
2019-10-20 00:15:10 +03:00
|
|
|
if (goal_dist != 0) {
|
|
|
|
|
shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, 0, true);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2018-07-07 18:39:45 +03:00
|
|
|
copy_v3_v3(r_point_co, hit_co);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
2018-07-07 18:39:45 +03:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
case MOD_SHRINKWRAP_INSIDE:
|
|
|
|
|
shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false);
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
case MOD_SHRINKWRAP_OUTSIDE:
|
|
|
|
|
shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false);
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
case MOD_SHRINKWRAP_OUTSIDE_SURFACE:
|
2019-01-10 11:55:09 +03:00
|
|
|
if (goal_dist != 0) {
|
2018-07-07 18:39:45 +03:00
|
|
|
shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(r_point_co, hit_co);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
/* Offsets along the normal */
|
|
|
|
|
case MOD_SHRINKWRAP_ABOVE_SURFACE:
|
2019-01-10 11:55:09 +03:00
|
|
|
if (goal_dist != 0) {
|
2018-10-03 19:09:43 +03:00
|
|
|
BKE_shrinkwrap_compute_smooth_normal(tree, transform, hit_idx, hit_co, hit_no, tmp);
|
|
|
|
|
madd_v3_v3v3fl(r_point_co, hit_co, tmp, goal_dist);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
copy_v3_v3(r_point_co, hit_co);
|
|
|
|
|
}
|
2018-07-07 18:39:45 +03:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-07-07 18:39:45 +03:00
|
|
|
default:
|
|
|
|
|
printf("Unknown Shrinkwrap surface snap mode: %d\n", mode);
|
|
|
|
|
copy_v3_v3(r_point_co, hit_co);
|
2016-05-30 17:30:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
|
|
|
|
|
{
|
2012-05-11 08:05:47 +00:00
|
|
|
BVHTreeNearest nearest = NULL_BVHTreeNearest;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Setup nearest */
|
2008-05-26 21:57:53 +00:00
|
|
|
nearest.index = -1;
|
2014-02-03 02:46:45 +11:00
|
|
|
nearest.dist_sq = FLT_MAX;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Find the nearest vertex */
|
2022-10-06 15:15:49 -05:00
|
|
|
ShrinkwrapCalcCBData data{};
|
|
|
|
|
data.calc = calc;
|
|
|
|
|
data.tree = calc->tree;
|
2019-07-30 14:56:47 +02:00
|
|
|
TaskParallelSettings settings;
|
2018-01-08 11:35:48 +01:00
|
|
|
BLI_parallel_range_settings_defaults(&settings);
|
2023-04-27 16:23:42 -04:00
|
|
|
settings.use_threading = (calc->numVerts > 10000);
|
2018-01-08 11:35:48 +01:00
|
|
|
settings.userdata_chunk = &nearest;
|
|
|
|
|
settings.userdata_chunk_size = sizeof(nearest);
|
|
|
|
|
BLI_task_parallel_range(
|
|
|
|
|
0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
|
2008-05-26 21:57:53 +00:00
|
|
|
}
|
2008-05-02 00:16:48 +00:00
|
|
|
|
2018-12-07 15:45:53 +01:00
|
|
|
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
|
|
|
|
|
const ModifierEvalContext *ctx,
|
2022-10-06 15:15:49 -05:00
|
|
|
Scene *scene,
|
2018-12-07 15:45:53 +01:00
|
|
|
Object *ob,
|
|
|
|
|
Mesh *mesh,
|
Mesh: Remove redundant custom data pointers
For copy-on-write, we want to share attribute arrays between meshes
where possible. Mutable pointers like `Mesh.mvert` make that difficult
by making ownership vague. They also make code more complex by adding
redundancy.
The simplest solution is just removing them and retrieving layers from
`CustomData` as needed. Similar changes have already been applied to
curves and point clouds (e9f82d3dc7ee, 410a6efb747f). Removing use of
the pointers generally makes code more obvious and more reusable.
Mesh data is now accessed with a C++ API (`Mesh::edges()` or
`Mesh::edges_for_write()`), and a C API (`BKE_mesh_edges(mesh)`).
The CoW changes this commit makes possible are described in T95845
and T95842, and started in D14139 and D14140. The change also simplifies
the ongoing mesh struct-of-array refactors from T95965.
**RNA/Python Access Performance**
Theoretically, accessing mesh elements with the RNA API may become
slower, since the layer needs to be found on every random access.
However, overhead is already high enough that this doesn't make a
noticible differenc, and performance is actually improved in some
cases. Random access can be up to 10% faster, but other situations
might be a bit slower. Generally using `foreach_get/set` are the best
way to improve performance. See the differential revision for more
discussion about Python performance.
Cycles has been updated to use raw pointers and the internal Blender
mesh types, mostly because there is no sense in having this overhead
when it's already compiled with Blender. In my tests this roughly
halves the Cycles mesh creation time (0.19s to 0.10s for a 1 million
face grid).
Differential Revision: https://developer.blender.org/D15488
2022-09-05 11:56:34 -05:00
|
|
|
const MDeformVert *dvert,
|
2018-12-07 15:45:53 +01:00
|
|
|
const int defgrp_index,
|
|
|
|
|
float (*vertexCos)[3],
|
|
|
|
|
int numVerts)
|
2009-01-04 14:14:06 +00:00
|
|
|
{
|
2009-05-23 03:24:15 +00:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
DerivedMesh *ss_mesh = nullptr;
|
2009-01-04 14:14:06 +00:00
|
|
|
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-03-18 18:29:16 +11:00
|
|
|
/* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (smd->target == ob) {
|
2022-10-06 15:15:49 -05:00
|
|
|
smd->target = nullptr;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
if (smd->auxTarget == ob) {
|
2022-10-06 15:15:49 -05:00
|
|
|
smd->auxTarget = nullptr;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Configure Shrinkwrap calc data */
|
2009-01-04 14:14:06 +00:00
|
|
|
calc.smd = smd;
|
|
|
|
|
calc.ob = ob;
|
|
|
|
|
calc.numVerts = numVerts;
|
|
|
|
|
calc.vertexCos = vertexCos;
|
2018-11-26 20:43:35 +01:00
|
|
|
calc.dvert = dvert;
|
|
|
|
|
calc.vgroup = defgrp_index;
|
2016-03-07 11:24:03 +11:00
|
|
|
calc.invert_vgroup = (smd->shrinkOpts & MOD_SHRINKWRAP_INVERT_VGROUP) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
if (smd->target != nullptr) {
|
2025-05-02 15:08:29 +02:00
|
|
|
Object *ob_target = DEG_get_evaluated(ctx->depsgraph, smd->target);
|
2022-07-20 15:57:16 +02:00
|
|
|
calc.target = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_target);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: there might be several "bugs" with non-uniform scales matrices
|
2012-10-20 20:20:02 +00:00
|
|
|
* because it will no longer be nearest surface, not sphere projection
|
|
|
|
|
* because space has been deformed */
|
2018-12-07 15:45:53 +01:00
|
|
|
BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, ob_target);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* TODO: smd->keepDist is in global units.. must change to local */
|
2009-05-23 03:24:15 +00:00
|
|
|
calc.keepDist = smd->keepDist;
|
|
|
|
|
}
|
2025-05-02 15:08:29 +02:00
|
|
|
calc.aux_target = DEG_get_evaluated(ctx->depsgraph, smd->auxTarget);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
if (mesh != nullptr && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
|
2023-02-27 20:54:27 +11:00
|
|
|
/* Setup arrays to get vertex positions, normals and deform weights */
|
2023-07-25 21:59:47 -04:00
|
|
|
calc.vert_positions = reinterpret_cast<float(*)[3]>(mesh->vert_positions_for_write().data());
|
2023-03-15 14:00:40 -04:00
|
|
|
calc.vert_normals = mesh->vert_normals();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-10-07 10:32:02 +11:00
|
|
|
/* Using vertices positions/normals as if a subsurface was applied */
|
2012-04-28 06:31:57 +00:00
|
|
|
if (smd->subsurfLevels) {
|
2022-10-06 15:15:49 -05:00
|
|
|
SubsurfModifierData ssmd = {{nullptr}};
|
2012-10-20 20:20:02 +00:00
|
|
|
ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
|
|
|
|
|
ssmd.levels = smd->subsurfLevels; /* levels */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: to be moved to Mesh once we are done with changes in subsurf code. */
|
2018-05-08 19:04:12 +02:00
|
|
|
DerivedMesh *dm = CDDM_from_mesh(mesh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-18 11:51:02 +02:00
|
|
|
ss_mesh = subsurf_make_derived_from_derived(
|
2022-10-06 15:15:49 -05:00
|
|
|
dm,
|
|
|
|
|
&ssmd,
|
|
|
|
|
scene,
|
|
|
|
|
nullptr,
|
|
|
|
|
(ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : SubsurfFlags(0));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
if (ss_mesh) {
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
calc.vert_positions = reinterpret_cast<float(*)[3]>(ss_mesh->getVertArray(ss_mesh));
|
|
|
|
|
if (calc.vert_positions) {
|
2012-04-28 06:31:57 +00:00
|
|
|
/* TRICKY: this code assumes subsurface will have the transformed original vertices
|
|
|
|
|
* in their original order at the end of the vert array. */
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
calc.vert_positions = calc.vert_positions + ss_mesh->getNumVerts(ss_mesh) -
|
|
|
|
|
dm->getNumVerts(dm);
|
2009-05-23 03:24:15 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Just to make sure we are not leaving any memory behind */
|
2022-10-06 15:15:49 -05:00
|
|
|
BLI_assert(ssmd.emCache == nullptr);
|
|
|
|
|
BLI_assert(ssmd.mCache == nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-08 19:04:12 +02:00
|
|
|
dm->release(dm);
|
2009-01-04 14:14:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* Projecting target defined - lets work! */
|
2018-10-03 19:09:43 +03:00
|
|
|
ShrinkwrapTreeData tree;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
if (BKE_shrinkwrap_init_tree(&tree, calc.target, smd->shrinkType, smd->shrinkMode, false)) {
|
|
|
|
|
calc.tree = &tree;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-28 06:31:57 +00:00
|
|
|
switch (smd->shrinkType) {
|
2009-01-04 14:14:06 +00:00
|
|
|
case MOD_SHRINKWRAP_NEAREST_SURFACE:
|
Shrinkwrap: new mode that projects along the target normal.
The Nearest Surface Point shrink method, while fast, is neither
smooth nor continuous: as the source point moves, the projected
point can both stop and jump. This causes distortions in the
deformation of the shrinkwrap modifier, and the motion of an
animated object with a shrinkwrap constraint.
This patch implements a new mode, which, instead of using the simple
nearest point search, iteratively solves an equation for each triangle
to find a point which has its interpolated normal point to or from the
original vertex. Non-manifold boundary edges are treated as infinitely
thin cylinders that cast normals in all perpendicular directions.
Since this is useful for the constraint, and having multiple
objects with constraints targeting the same guide mesh is a quite
reasonable use case, rather than calculating the mesh boundary edge
data over and over again, it is precomputed and cached in the mesh.
Reviewers: mont29
Differential Revision: https://developer.blender.org/D3836
2018-11-06 21:04:53 +03:00
|
|
|
case MOD_SHRINKWRAP_TARGET_PROJECT:
|
2012-11-09 04:01:19 +00:00
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), deform_surface);
|
2012-05-11 08:05:47 +00:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-04 14:14:06 +00:00
|
|
|
case MOD_SHRINKWRAP_PROJECT:
|
2018-05-30 11:34:08 +02:00
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
|
2012-05-11 08:05:47 +00:00
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-01-04 14:14:06 +00:00
|
|
|
case MOD_SHRINKWRAP_NEAREST_VERTEX:
|
2012-11-09 04:01:19 +00:00
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), deform_vertex);
|
2012-05-11 08:05:47 +00:00
|
|
|
break;
|
2009-01-04 14:14:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-03 19:09:43 +03:00
|
|
|
BKE_shrinkwrap_free_tree(&tree);
|
2009-01-04 14:14:06 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* free memory */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (ss_mesh) {
|
2009-05-23 03:24:15 +00:00
|
|
|
ss_mesh->release(ss_mesh);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-01-04 14:14:06 +00:00
|
|
|
}
|
2019-09-10 15:18:51 +02:00
|
|
|
|
2024-03-06 12:05:00 +01:00
|
|
|
void shrinkwrapParams_deform(const ShrinkwrapParams ¶ms,
|
|
|
|
|
Object &object,
|
|
|
|
|
ShrinkwrapTreeData &tree,
|
|
|
|
|
const blender::Span<MDeformVert> dvert,
|
|
|
|
|
const int defgrp_index,
|
|
|
|
|
const blender::MutableSpan<blender::float3> positions)
|
|
|
|
|
{
|
|
|
|
|
using namespace blender::bke;
|
|
|
|
|
|
|
|
|
|
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
|
|
|
|
|
/* Convert params struct to use the same struct and function used with meshes. */
|
|
|
|
|
ShrinkwrapModifierData smd;
|
|
|
|
|
smd.target = params.target;
|
|
|
|
|
smd.auxTarget = params.aux_target;
|
|
|
|
|
smd.keepDist = params.keep_distance;
|
|
|
|
|
smd.shrinkType = params.shrink_type;
|
|
|
|
|
smd.shrinkOpts = params.shrink_options;
|
|
|
|
|
smd.shrinkMode = params.shrink_mode;
|
|
|
|
|
smd.projLimit = params.projection_limit;
|
|
|
|
|
smd.projAxis = params.projection_axis;
|
|
|
|
|
|
|
|
|
|
/* Configure Shrinkwrap calc data. */
|
|
|
|
|
calc.smd = &smd;
|
|
|
|
|
calc.ob = &object;
|
|
|
|
|
calc.numVerts = int(positions.size());
|
|
|
|
|
calc.vertexCos = reinterpret_cast<float(*)[3]>(positions.data());
|
|
|
|
|
calc.dvert = dvert.is_empty() ? nullptr : dvert.data();
|
|
|
|
|
calc.vgroup = defgrp_index;
|
|
|
|
|
calc.invert_vgroup = params.invert_vertex_weights;
|
|
|
|
|
|
|
|
|
|
BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, &object, params.target);
|
|
|
|
|
calc.keepDist = params.keep_distance;
|
|
|
|
|
calc.tree = &tree;
|
|
|
|
|
|
|
|
|
|
switch (params.shrink_type) {
|
|
|
|
|
case MOD_SHRINKWRAP_NEAREST_SURFACE:
|
|
|
|
|
case MOD_SHRINKWRAP_TARGET_PROJECT:
|
|
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_nearest_surface_point(&calc), gpdeform_surface);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MOD_SHRINKWRAP_PROJECT:
|
|
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), gpdeform_project);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case MOD_SHRINKWRAP_NEAREST_VERTEX:
|
|
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_nearest_vertex(&calc), gpdeform_vertex);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-04 15:29:40 -05:00
|
|
|
void BKE_shrinkwrap_mesh_nearest_surface_deform(Depsgraph *depsgraph,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Object *ob_source,
|
|
|
|
|
Object *ob_target)
|
2019-09-10 15:18:51 +02:00
|
|
|
{
|
2022-12-29 12:01:32 -05:00
|
|
|
ShrinkwrapModifierData ssmd = {{nullptr}};
|
2022-10-06 15:15:49 -05:00
|
|
|
ModifierEvalContext ctx = {depsgraph, ob_source, ModifierApplyFlag(0)};
|
2019-09-10 15:18:51 +02:00
|
|
|
|
|
|
|
|
ssmd.target = ob_target;
|
|
|
|
|
ssmd.shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE;
|
|
|
|
|
ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
|
|
|
|
|
ssmd.keepDist = 0.0f;
|
|
|
|
|
|
2022-10-06 15:15:49 -05:00
|
|
|
Mesh *src_me = static_cast<Mesh *>(ob_source->data);
|
2019-09-10 15:18:51 +02:00
|
|
|
|
2023-07-25 21:59:47 -04:00
|
|
|
shrinkwrapModifier_deform(
|
|
|
|
|
&ssmd,
|
|
|
|
|
&ctx,
|
2023-12-04 15:29:40 -05:00
|
|
|
scene,
|
2023-07-25 21:59:47 -04:00
|
|
|
ob_source,
|
|
|
|
|
src_me,
|
|
|
|
|
nullptr,
|
|
|
|
|
-1,
|
|
|
|
|
reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data()),
|
2023-12-20 02:21:48 +01:00
|
|
|
src_me->verts_num);
|
2023-12-12 15:38:42 -05:00
|
|
|
src_me->tag_positions_changed();
|
2019-09-10 15:18:51 +02:00
|
|
|
}
|
2019-09-26 16:28:56 +02:00
|
|
|
|
|
|
|
|
void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object *ob_target)
|
|
|
|
|
{
|
2022-12-29 12:01:32 -05:00
|
|
|
ShrinkwrapModifierData ssmd = {{nullptr}};
|
2019-09-26 16:28:56 +02:00
|
|
|
|
|
|
|
|
ssmd.target = ob_target;
|
2019-11-05 15:01:51 +01:00
|
|
|
ssmd.shrinkType = MOD_SHRINKWRAP_PROJECT;
|
2019-09-26 16:28:56 +02:00
|
|
|
ssmd.shrinkMode = MOD_SHRINKWRAP_ON_SURFACE;
|
2019-11-05 15:01:51 +01:00
|
|
|
ssmd.shrinkOpts = MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR;
|
2019-09-26 16:28:56 +02:00
|
|
|
ssmd.keepDist = 0.0f;
|
2020-10-22 17:08:37 -04:00
|
|
|
|
|
|
|
|
/* Tolerance value to prevent artifacts on sharp edges of a mesh.
|
2020-10-15 18:48:18 +02:00
|
|
|
* This constant and based on experimenting with different values. */
|
|
|
|
|
const float projLimitTolerance = 5.0f;
|
|
|
|
|
ssmd.projLimit = target_me->remesh_voxel_size * projLimitTolerance;
|
2019-09-26 16:28:56 +02:00
|
|
|
|
|
|
|
|
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
|
|
|
|
|
|
|
|
|
|
calc.smd = &ssmd;
|
2023-12-20 02:21:48 +01:00
|
|
|
calc.numVerts = src_me->verts_num;
|
2023-07-25 21:59:47 -04:00
|
|
|
calc.vertexCos = reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data());
|
2023-03-15 14:00:40 -04:00
|
|
|
calc.vert_normals = src_me->vert_normals();
|
2019-09-26 16:28:56 +02:00
|
|
|
calc.vgroup = -1;
|
|
|
|
|
calc.target = target_me;
|
|
|
|
|
calc.keepDist = ssmd.keepDist;
|
2023-07-25 21:59:47 -04:00
|
|
|
calc.vert_positions = reinterpret_cast<float(*)[3]>(src_me->vert_positions_for_write().data());
|
2019-09-26 16:28:56 +02:00
|
|
|
BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob_target, ob_target);
|
|
|
|
|
|
|
|
|
|
ShrinkwrapTreeData tree;
|
|
|
|
|
if (BKE_shrinkwrap_init_tree(&tree, calc.target, ssmd.shrinkType, ssmd.shrinkMode, false)) {
|
|
|
|
|
calc.tree = &tree;
|
2019-11-05 15:01:51 +01:00
|
|
|
TIMEIT_BENCH(shrinkwrap_calc_normal_projection(&calc), deform_project);
|
2019-09-26 16:28:56 +02:00
|
|
|
BKE_shrinkwrap_free_tree(&tree);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-12 15:38:42 -05:00
|
|
|
src_me->tag_positions_changed();
|
2019-09-26 16:28:56 +02:00
|
|
|
}
|