2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2004 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edmesh
|
2012-12-19 04:49:32 +00:00
|
|
|
*
|
2023-07-31 11:50:54 +10:00
|
|
|
* `meshtools.cc`: no editmode (violated already :), mirror & join),
|
2012-12-19 04:49:32 +00:00
|
|
|
* tools operating on meshes
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
|
2024-01-22 15:58:18 +01:00
|
|
|
#include <algorithm>
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "MEM_guardedalloc.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_matrix.h"
|
2022-08-31 09:09:01 -05:00
|
|
|
#include "BLI_virtual_array.hh"
|
|
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
#include "DNA_key_types.h"
|
|
|
|
|
#include "DNA_material_types.h"
|
2018-06-21 19:05:10 +02:00
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
2012-06-24 20:18:32 +00:00
|
|
|
#include "DNA_modifier_types.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
2012-12-23 02:04:38 +00:00
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
|
#include "DNA_view3d_types.h"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2022-08-31 09:09:01 -05:00
|
|
|
#include "BKE_attribute.hh"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
|
|
|
|
#include "BKE_customdata.hh"
|
2024-01-29 18:57:16 -05:00
|
|
|
#include "BKE_deform.hh"
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_editmesh.hh"
|
2024-01-30 14:42:07 -05:00
|
|
|
#include "BKE_key.hh"
|
2024-01-15 12:44:04 -05:00
|
|
|
#include "BKE_lib_id.hh"
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_material.h"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_mesh_iterators.hh"
|
|
|
|
|
#include "BKE_mesh_runtime.hh"
|
|
|
|
|
#include "BKE_multires.hh"
|
2023-10-09 23:41:53 +02:00
|
|
|
#include "BKE_object.hh"
|
2018-03-06 09:57:41 +11:00
|
|
|
#include "BKE_object_deform.h"
|
2024-02-10 18:34:29 +01:00
|
|
|
#include "BKE_report.hh"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
|
|
|
|
#include "DEG_depsgraph_build.hh"
|
|
|
|
|
#include "DEG_depsgraph_query.hh"
|
2017-06-08 10:14:53 +02:00
|
|
|
|
2023-10-04 14:32:18 -03:00
|
|
|
#include "DRW_select_buffer.hh"
|
2019-08-07 12:43:04 -03:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_mesh.hh"
|
|
|
|
|
#include "ED_object.hh"
|
|
|
|
|
#include "ED_view3d.hh"
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2009-07-13 00:40:20 +00: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
|
|
|
using blender::float3;
|
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
|
|
|
using blender::int2;
|
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
|
|
|
using blender::MutableSpan;
|
|
|
|
|
using blender::Span;
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* * ********************** no editmode!!! *********** */
|
|
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/*********************** JOIN ***************************/
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* join selected meshes into the active mesh, context sensitive
|
2012-03-03 16:31:46 +00:00
|
|
|
* return 0 if no join is made (error) and 1 if the join is done */
|
2009-07-11 10:20:48 +00:00
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
static void join_mesh_single(Depsgraph *depsgraph,
|
2018-04-06 12:07:27 +02:00
|
|
|
Main *bmain,
|
|
|
|
|
Scene *scene,
|
2017-10-04 14:59:44 +05:00
|
|
|
Object *ob_dst,
|
|
|
|
|
Object *ob_src,
|
2019-09-14 08:10:50 +10:00
|
|
|
const float imat[4][4],
|
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
|
|
|
float3 **vert_positions_pp,
|
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
|
|
|
blender::int2 **medge_pp,
|
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
|
|
|
int **corner_verts_pp,
|
|
|
|
|
int **corner_edges_pp,
|
2023-07-24 22:06:55 +02:00
|
|
|
int *all_face_offsets,
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *vert_data,
|
|
|
|
|
CustomData *edge_data,
|
2017-02-02 21:37:53 +01:00
|
|
|
CustomData *ldata,
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *face_data,
|
2017-02-02 21:37:53 +01:00
|
|
|
int totvert,
|
|
|
|
|
int totedge,
|
|
|
|
|
int totloop,
|
2023-07-24 22:06:55 +02:00
|
|
|
int faces_num,
|
2017-02-02 21:37:53 +01:00
|
|
|
Key *key,
|
|
|
|
|
Key *nkey,
|
|
|
|
|
Material **matar,
|
|
|
|
|
int *matmap,
|
|
|
|
|
int totcol,
|
|
|
|
|
int *vertofs,
|
|
|
|
|
int *edgeofs,
|
|
|
|
|
int *loopofs,
|
|
|
|
|
int *polyofs)
|
|
|
|
|
{
|
|
|
|
|
int a, b;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob_src->data);
|
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
|
|
|
float3 *vert_positions = *vert_positions_pp;
|
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
|
|
|
blender::int2 *edge = *medge_pp;
|
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
|
|
|
int *corner_verts = *corner_verts_pp;
|
|
|
|
|
int *corner_edges = *corner_edges_pp;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (mesh->verts_num) {
|
2017-02-02 21:37:53 +01:00
|
|
|
/* standard data */
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData_merge_layout(
|
2023-12-08 16:40:06 -05:00
|
|
|
&mesh->vert_data, vert_data, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
|
2023-12-20 02:21:48 +01:00
|
|
|
CustomData_copy_data_named(&mesh->vert_data, vert_data, 0, *vertofs, mesh->verts_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
/* vertex groups */
|
2023-01-13 17:21:20 -06:00
|
|
|
MDeformVert *dvert = (MDeformVert *)CustomData_get_for_write(
|
2023-07-25 21:15:52 +02:00
|
|
|
vert_data, *vertofs, CD_MDEFORMVERT, totvert);
|
2023-12-08 16:40:06 -05:00
|
|
|
const MDeformVert *dvert_src = (const MDeformVert *)CustomData_get_layer(&mesh->vert_data,
|
2023-01-13 17:21:20 -06:00
|
|
|
CD_MDEFORMVERT);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-22 16:17:37 +02:00
|
|
|
/* Remap to correct new vgroup indices, if needed. */
|
|
|
|
|
if (dvert_src) {
|
2022-05-15 20:41:11 +02:00
|
|
|
BLI_assert(dvert != nullptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-05-22 16:17:37 +02:00
|
|
|
/* Build src to merged mapping of vgroup indices. */
|
2018-03-06 09:57:41 +11:00
|
|
|
int *vgroup_index_map;
|
|
|
|
|
int vgroup_index_map_len;
|
|
|
|
|
vgroup_index_map = BKE_object_defgroup_index_map_create(
|
|
|
|
|
ob_src, ob_dst, &vgroup_index_map_len);
|
|
|
|
|
BKE_object_defgroup_index_map_apply(
|
2023-12-20 02:21:48 +01:00
|
|
|
dvert, mesh->verts_num, vgroup_index_map, vgroup_index_map_len);
|
2022-05-15 20:41:11 +02:00
|
|
|
if (vgroup_index_map != nullptr) {
|
2018-03-06 09:57:41 +11:00
|
|
|
MEM_freeN(vgroup_index_map);
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
/* if this is the object we're merging into, no need to do anything */
|
2017-10-04 14:59:44 +05:00
|
|
|
if (ob_src != ob_dst) {
|
2017-02-02 21:37:53 +01:00
|
|
|
float cmat[4][4];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Watch this: switch matrix multiplication order really goes wrong. */
|
2024-02-14 16:14:49 +01:00
|
|
|
mul_m4_m4m4(cmat, imat, ob_src->object_to_world().ptr());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
/* transform vertex coordinates into new space */
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->verts_num; a++) {
|
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
|
|
|
mul_m4_v3(cmat, vert_positions[a]);
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* For each shape-key in destination mesh:
|
2019-04-22 00:18:34 +10:00
|
|
|
* - if there's a matching one, copy it across
|
|
|
|
|
* (will need to transform vertices into new space...).
|
2024-03-07 16:20:36 -05:00
|
|
|
* - otherwise, just copy its own coordinates of mesh
|
2019-04-22 00:18:34 +10:00
|
|
|
* (no need to transform vertex coordinates into new space).
|
2017-02-02 21:37:53 +01:00
|
|
|
*/
|
|
|
|
|
if (key) {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* if this mesh has any shape-keys, check first, otherwise just copy coordinates */
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* get pointer to where to write data for this mesh in shape-key's data array */
|
2017-02-02 21:37:53 +01:00
|
|
|
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Check if this mesh has such a shape-key. */
|
2023-12-08 16:40:06 -05:00
|
|
|
KeyBlock *okb = mesh->key ? BKE_keyblock_find_name(mesh->key, kb->name) : nullptr;
|
2017-02-02 21:37:53 +01:00
|
|
|
if (okb) {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* copy this mesh's shape-key to the destination shape-key
|
2019-01-15 23:24:20 +11:00
|
|
|
* (need to transform first) */
|
2022-05-15 20:41:11 +02:00
|
|
|
float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->verts_num; a++, cos++, ocos++) {
|
2017-02-02 21:37:53 +01:00
|
|
|
copy_v3_v3(*cos, *ocos);
|
|
|
|
|
mul_m4_v3(cmat, *cos);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-02-02 21:37:53 +01:00
|
|
|
else {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Copy this mesh's vertex coordinates to the destination shape-key. */
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->verts_num; a++, cos++) {
|
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
|
|
|
copy_v3_v3(*cos, vert_positions[a]);
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-02-02 21:37:53 +01:00
|
|
|
else {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* for each shape-key in destination mesh:
|
2018-11-14 12:53:15 +11:00
|
|
|
* - if it was an 'original', copy the appropriate data from nkey
|
|
|
|
|
* - otherwise, copy across plain coordinates (no need to transform coordinates)
|
2017-02-02 21:37:53 +01:00
|
|
|
*/
|
|
|
|
|
if (key) {
|
2020-04-03 19:15:01 +02:00
|
|
|
LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* get pointer to where to write data for this mesh in shape-key's data array */
|
2017-02-02 21:37:53 +01:00
|
|
|
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Check if this was one of the original shape-keys. */
|
2022-05-15 20:41:11 +02:00
|
|
|
KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : nullptr;
|
2017-02-02 21:37:53 +01:00
|
|
|
if (okb) {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* copy this mesh's shape-key to the destination shape-key */
|
2022-05-15 20:41:11 +02:00
|
|
|
float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->verts_num; a++, cos++, ocos++) {
|
2017-02-02 21:37:53 +01:00
|
|
|
copy_v3_v3(*cos, *ocos);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-02-02 21:37:53 +01:00
|
|
|
else {
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Copy base-coordinates to the destination shape-key. */
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->verts_num; a++, cos++) {
|
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
|
|
|
copy_v3_v3(*cos, vert_positions[a]);
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (mesh->edges_num) {
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData_merge_layout(
|
2023-12-08 16:40:06 -05:00
|
|
|
&mesh->edge_data, edge_data, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
|
2023-12-20 02:21:48 +01:00
|
|
|
CustomData_copy_data_named(&mesh->edge_data, edge_data, 0, *edgeofs, mesh->edges_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->edges_num; a++, edge++) {
|
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
|
|
|
(*edge) += *vertofs;
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (mesh->corners_num) {
|
2017-10-04 14:59:44 +05:00
|
|
|
if (ob_src != ob_dst) {
|
2017-02-02 21:37:53 +01:00
|
|
|
MultiresModifierData *mmd;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-06 12:07:27 +02:00
|
|
|
multiresModifier_prepare_join(depsgraph, scene, ob_src, ob_dst);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-04 14:59:44 +05:00
|
|
|
if ((mmd = get_multires_modifier(scene, ob_src, true))) {
|
2024-03-28 01:30:38 +01:00
|
|
|
blender::ed::object::iter_other(
|
|
|
|
|
bmain, ob_src, true, blender::ed::object::multires_update_totlevels, &mmd->totlvl);
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-19 20:38:59 -05:00
|
|
|
CustomData_merge_layout(
|
|
|
|
|
&mesh->corner_data, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
|
|
|
|
|
CustomData_copy_data_named(&mesh->corner_data, ldata, 0, *loopofs, mesh->corners_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
for (a = 0; a < mesh->corners_num; a++) {
|
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
|
|
|
corner_verts[a] += *vertofs;
|
|
|
|
|
corner_edges[a] += *edgeofs;
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh->faces_num) {
|
2017-02-02 21:37:53 +01:00
|
|
|
if (matmap) {
|
|
|
|
|
/* make mapping for materials */
|
2017-10-04 14:59:44 +05:00
|
|
|
for (a = 1; a <= ob_src->totcol; a++) {
|
2020-02-05 11:23:58 +01:00
|
|
|
Material *ma = BKE_object_material_get(ob_src, a);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
for (b = 0; b < totcol; b++) {
|
|
|
|
|
if (ma == matar[b]) {
|
|
|
|
|
matmap[a - 1] = b;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData_merge_layout(
|
2023-12-08 16:40:06 -05:00
|
|
|
&mesh->face_data, face_data, CD_MASK_MESH.pmask, CD_SET_DEFAULT, faces_num);
|
|
|
|
|
CustomData_copy_data_named(&mesh->face_data, face_data, 0, *polyofs, mesh->faces_num);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-09 15:37:33 +10:00
|
|
|
/* Apply matmap. In case we don't have material indices yet, create them if more than one
|
2022-09-05 12:22:51 +02:00
|
|
|
* material is the result of joining. */
|
2023-07-25 21:15:52 +02:00
|
|
|
int *material_indices = static_cast<int *>(CustomData_get_layer_named_for_write(
|
|
|
|
|
face_data, CD_PROP_INT32, "material_index", faces_num));
|
2022-09-05 12:22:51 +02:00
|
|
|
if (!material_indices && totcol > 1) {
|
|
|
|
|
material_indices = (int *)CustomData_add_layer_named(
|
2023-07-25 21:15:52 +02:00
|
|
|
face_data, CD_PROP_INT32, CD_SET_DEFAULT, faces_num, "material_index");
|
2022-09-05 12:22:51 +02:00
|
|
|
}
|
2022-08-31 09:09:01 -05:00
|
|
|
if (material_indices) {
|
2023-12-08 16:40:06 -05:00
|
|
|
for (a = 0; a < mesh->faces_num; a++) {
|
2022-09-05 12:22:51 +02:00
|
|
|
material_indices[a + *polyofs] = matmap ? matmap[material_indices[a + *polyofs]] : 0;
|
2022-08-31 09:09:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
const Span<int> src_face_offsets = mesh->face_offsets();
|
2023-07-24 22:06:55 +02:00
|
|
|
int *face_offsets = all_face_offsets + *polyofs;
|
2023-12-08 16:40:06 -05:00
|
|
|
for (const int i : blender::IndexRange(mesh->faces_num)) {
|
2023-07-24 22:06:55 +02:00
|
|
|
face_offsets[i] = src_face_offsets[i] + *loopofs;
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-02-02 21:37:53 +01:00
|
|
|
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
|
2023-12-20 02:21:48 +01:00
|
|
|
*vertofs += mesh->verts_num;
|
|
|
|
|
*vert_positions_pp += mesh->verts_num;
|
|
|
|
|
*edgeofs += mesh->edges_num;
|
|
|
|
|
*medge_pp += mesh->edges_num;
|
|
|
|
|
*loopofs += mesh->corners_num;
|
|
|
|
|
*corner_verts_pp += mesh->corners_num;
|
|
|
|
|
*corner_edges_pp += mesh->corners_num;
|
2023-12-08 16:40:06 -05:00
|
|
|
*polyofs += mesh->faces_num;
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-09 17:56:00 +02:00
|
|
|
/* Face Sets IDs are a sparse sequence, so this function offsets all the IDs by face_set_offset and
|
|
|
|
|
* updates face_set_offset with the maximum ID value. This way, when used in multiple meshes, all
|
|
|
|
|
* of them will have different IDs for their Face Sets. */
|
2023-01-13 17:21:20 -06:00
|
|
|
static void mesh_join_offset_face_sets_ID(Mesh *mesh, int *face_set_offset)
|
2020-07-09 17:56:00 +02:00
|
|
|
{
|
2023-11-20 13:14:16 -05:00
|
|
|
using namespace blender;
|
|
|
|
|
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
|
|
|
|
bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
|
|
|
|
|
".sculpt_face_set");
|
2020-07-09 17:56:00 +02:00
|
|
|
if (!face_sets) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int max_face_set = 0;
|
2023-11-20 13:14:16 -05:00
|
|
|
for (const int i : face_sets.span.index_range()) {
|
2020-07-10 11:41:14 +10:00
|
|
|
/* As face sets encode the visibility in the integer sign, the offset needs to be added or
|
|
|
|
|
* subtracted depending on the initial sign of the integer to get the new ID. */
|
2023-11-20 13:14:16 -05:00
|
|
|
if (face_sets.span[i] <= *face_set_offset) {
|
|
|
|
|
face_sets.span[i] += *face_set_offset;
|
2020-07-09 17:56:00 +02:00
|
|
|
}
|
2023-11-20 13:14:16 -05:00
|
|
|
max_face_set = max_ii(max_face_set, face_sets.span[i]);
|
2020-07-09 17:56:00 +02:00
|
|
|
}
|
|
|
|
|
*face_set_offset = max_face_set;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 17:07:11 +10:00
|
|
|
int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2012-03-26 02:56:48 +00:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
|
Scene *scene = CTX_data_scene(C);
|
2017-10-04 14:59:44 +05:00
|
|
|
Object *ob = CTX_data_active_object(C);
|
2022-05-15 20:41:11 +02:00
|
|
|
Material **matar = nullptr, *ma;
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh;
|
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
|
|
|
blender::int2 *edge = nullptr;
|
2022-05-15 20:41:11 +02:00
|
|
|
Key *key, *nkey = nullptr;
|
2017-02-02 21:37:53 +01:00
|
|
|
float imat[4][4];
|
2013-07-10 09:55:10 +00:00
|
|
|
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
|
2023-07-24 22:06:55 +02:00
|
|
|
int totloop = 0, faces_num = 0, vertofs, *matmap = nullptr;
|
2017-02-02 21:37:53 +01:00
|
|
|
int i, haskey = 0, edgeofs, loopofs, polyofs;
|
2020-05-13 15:21:30 -04:00
|
|
|
bool ok = false, join_parent = false;
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData vert_data, edge_data, ldata, face_data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob->mode & OB_MODE_EDIT) {
|
2012-10-26 17:32:50 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
|
2009-07-13 00:40:20 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2010-11-10 01:40:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/* ob is the object we are adding geometry to */
|
2012-03-26 02:56:48 +00:00
|
|
|
if (!ob || ob->type != OB_MESH) {
|
2010-12-21 15:10:09 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
|
2009-07-13 00:40:20 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2010-11-10 01:40:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* count & check */
|
2018-10-01 16:43:49 +10:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
|
|
|
|
if (ob_iter->type == OB_MESH) {
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh = static_cast<Mesh *>(ob_iter->data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
totvert += mesh->verts_num;
|
|
|
|
|
totedge += mesh->edges_num;
|
|
|
|
|
totloop += mesh->corners_num;
|
2023-12-08 16:40:06 -05:00
|
|
|
faces_num += mesh->faces_num;
|
2018-10-01 16:43:49 +10:00
|
|
|
totmat += ob_iter->totcol;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ob_iter == ob) {
|
2013-07-10 09:55:10 +00:00
|
|
|
ok = true;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
if ((ob->parent != nullptr) && (ob_iter == ob->parent)) {
|
2020-05-13 15:21:30 -04:00
|
|
|
join_parent = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Check for shape-keys. */
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh->key) {
|
2009-07-13 00:40:20 +00:00
|
|
|
haskey++;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2009-07-13 00:40:20 +00:00
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-05-13 15:21:30 -04:00
|
|
|
/* Apply parent transform if the active object's parent was joined to it.
|
2021-07-03 23:08:40 +10:00
|
|
|
* NOTE: This doesn't apply recursive parenting. */
|
2020-05-13 15:21:30 -04:00
|
|
|
if (join_parent) {
|
2022-05-15 20:41:11 +02:00
|
|
|
ob->parent = nullptr;
|
2024-02-14 16:14:49 +01:00
|
|
|
BKE_object_apply_mat4_ex(ob, ob->object_to_world().ptr(), ob->parent, ob->parentinv, false);
|
2020-05-13 15:21:30 -04:00
|
|
|
}
|
|
|
|
|
|
2018-06-04 09:31:30 +02:00
|
|
|
/* that way the active object is always selected */
|
2013-07-10 09:55:10 +00:00
|
|
|
if (ok == false) {
|
2010-12-21 15:10:09 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
|
2009-07-13 00:40:20 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2010-11-10 01:40:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 00:18:34 +10:00
|
|
|
/* Only join meshes if there are verts to join,
|
|
|
|
|
* there aren't too many, and we only had one mesh selected. */
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh = (Mesh *)ob->data;
|
|
|
|
|
key = mesh->key;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (ELEM(totvert, 0, mesh->verts_num)) {
|
2010-12-21 15:10:09 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
|
2009-07-13 00:40:20 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2010-11-10 01:40:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totvert > MESH_MAX_VERTS) {
|
2012-10-18 16:25:58 +00:00
|
|
|
BKE_reportf(op->reports,
|
|
|
|
|
RPT_WARNING,
|
|
|
|
|
"Joining results in %d vertices, limit is %ld",
|
|
|
|
|
totvert,
|
|
|
|
|
MESH_MAX_VERTS);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2010-11-10 01:40:24 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* new material indices and material array */
|
2017-02-02 21:37:53 +01:00
|
|
|
if (totmat) {
|
2022-05-15 20:41:11 +02:00
|
|
|
matar = static_cast<Material **>(MEM_callocN(sizeof(*matar) * totmat, __func__));
|
|
|
|
|
matmap = static_cast<int *>(MEM_callocN(sizeof(*matmap) * totmat, __func__));
|
2017-02-02 21:37:53 +01:00
|
|
|
}
|
2012-03-26 02:56:48 +00:00
|
|
|
totcol = ob->totcol;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-25 12:46:55 +10:00
|
|
|
/* Active object materials in new main array, is nicer start! */
|
2012-03-26 02:56:48 +00:00
|
|
|
for (a = 0; a < ob->totcol; a++) {
|
2020-02-05 11:23:58 +01:00
|
|
|
matar[a] = BKE_object_material_get(ob, a + 1);
|
2009-07-13 00:40:20 +00:00
|
|
|
id_us_plus((ID *)matar[a]);
|
2008-12-30 13:16:14 +00:00
|
|
|
/* increase id->us : will be lowered later */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* - If destination mesh had shape-keys, move them somewhere safe, and set up placeholders
|
|
|
|
|
* with arrays that are large enough to hold shape-key data for all meshes.
|
|
|
|
|
* - If destination mesh didn't have shape-keys, but we encountered some in the meshes we're
|
|
|
|
|
* joining, set up a new key-block and assign to the mesh.
|
2009-07-13 00:40:20 +00:00
|
|
|
*/
|
2012-03-24 06:38:07 +00:00
|
|
|
if (key) {
|
2009-07-13 00:40:20 +00:00
|
|
|
/* make a duplicate copy that will only be used here... (must remember to free it!) */
|
2020-10-07 18:01:25 +02:00
|
|
|
nkey = (Key *)BKE_id_copy(bmain, &key->id);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/* for all keys in old block, clear data-arrays */
|
2022-05-15 20:41:11 +02:00
|
|
|
LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (kb->data) {
|
2012-03-24 06:38:07 +00:00
|
|
|
MEM_freeN(kb->data);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-08-08 13:29:21 +10:00
|
|
|
kb->data = MEM_callocN(sizeof(float[3]) * totvert, "join_shapekey");
|
2012-03-26 02:56:48 +00:00
|
|
|
kb->totelem = totvert;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-07-13 00:40:20 +00:00
|
|
|
}
|
2012-03-24 06:38:07 +00:00
|
|
|
else if (haskey) {
|
2009-07-13 00:40:20 +00:00
|
|
|
/* add a new key-block and add to the mesh */
|
2023-12-08 16:40:06 -05:00
|
|
|
key = mesh->key = BKE_key_add(bmain, (ID *)mesh);
|
2009-07-13 00:40:20 +00:00
|
|
|
key->type = KEY_RELATIVE;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-07-09 17:56:00 +02:00
|
|
|
/* Update face_set_id_offset with the face set data in the active object first. This way the Face
|
|
|
|
|
* Sets IDs in the active object are not the ones that are modified. */
|
|
|
|
|
Mesh *mesh_active = BKE_mesh_from_object(ob);
|
|
|
|
|
int face_set_id_offset = 0;
|
|
|
|
|
mesh_join_offset_face_sets_ID(mesh_active, &face_set_id_offset);
|
|
|
|
|
|
|
|
|
|
/* Copy materials, vertex-groups, face sets & face-maps across objects. */
|
2018-10-01 16:43:49 +10:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
2009-07-13 00:40:20 +00:00
|
|
|
/* only act if a mesh, and not the one we're joining to */
|
2018-10-01 16:43:49 +10:00
|
|
|
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh = static_cast<Mesh *>(ob_iter->data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/* Join this object's vertex groups to the base one's */
|
2023-12-08 16:40:06 -05:00
|
|
|
LISTBASE_FOREACH (bDeformGroup *, dg, &mesh->vertex_group_names) {
|
2009-07-13 00:40:20 +00:00
|
|
|
/* See if this group exists in the object (if it doesn't, add it to the end) */
|
2020-03-06 12:50:56 +11:00
|
|
|
if (!BKE_object_defgroup_find_name(ob, dg->name)) {
|
2022-05-15 20:41:11 +02:00
|
|
|
bDeformGroup *odg = static_cast<bDeformGroup *>(
|
|
|
|
|
MEM_mallocN(sizeof(bDeformGroup), __func__));
|
2009-07-13 00:40:20 +00:00
|
|
|
memcpy(odg, dg, sizeof(bDeformGroup));
|
2021-07-13 12:10:34 -04:00
|
|
|
BLI_addtail(&mesh_active->vertex_group_names, odg);
|
2009-07-13 00:40:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-07-13 12:10:34 -04:00
|
|
|
if (!BLI_listbase_is_empty(&mesh_active->vertex_group_names) &&
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->vertex_group_active_index == 0)
|
|
|
|
|
{
|
|
|
|
|
mesh->vertex_group_active_index = 1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh_join_offset_face_sets_ID(mesh, &face_set_id_offset);
|
2020-07-09 17:56:00 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (mesh->verts_num) {
|
2012-03-24 06:38:07 +00:00
|
|
|
/* Add this object's materials to the base one's if they don't exist already
|
2019-01-15 23:24:20 +11:00
|
|
|
* (but only if limits not exceeded yet) */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totcol < MAXMAT) {
|
2019-01-15 23:24:20 +11:00
|
|
|
for (a = 1; a <= ob_iter->totcol; a++) {
|
2020-02-05 11:23:58 +01:00
|
|
|
ma = BKE_object_material_get(ob_iter, a);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
for (b = 0; b < totcol; b++) {
|
|
|
|
|
if (ma == matar[b]) {
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-03-26 02:56:48 +00:00
|
|
|
if (b == totcol) {
|
2017-02-02 21:37:53 +01:00
|
|
|
matar[b] = ma;
|
|
|
|
|
if (ma) {
|
2011-04-26 07:17:21 +00:00
|
|
|
id_us_plus(&ma->id);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-02-02 21:37:53 +01:00
|
|
|
totcol++;
|
|
|
|
|
}
|
2012-03-26 02:56:48 +00:00
|
|
|
if (totcol >= MAXMAT) {
|
|
|
|
|
break;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* If this mesh has shape-keys,
|
|
|
|
|
* check if destination mesh already has matching entries too. */
|
2023-12-08 16:40:06 -05:00
|
|
|
if (mesh->key && key) {
|
2017-02-02 21:37:53 +01:00
|
|
|
/* for remapping KeyBlock.relative */
|
2022-05-15 20:41:11 +02:00
|
|
|
int *index_map = static_cast<int *>(
|
2023-12-08 16:40:06 -05:00
|
|
|
MEM_mallocN(sizeof(int) * mesh->key->totkey, __func__));
|
2022-05-15 20:41:11 +02:00
|
|
|
KeyBlock **kb_map = static_cast<KeyBlock **>(
|
2023-12-08 16:40:06 -05:00
|
|
|
MEM_mallocN(sizeof(KeyBlock *) * mesh->key->totkey, __func__));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &mesh->key->block, i) {
|
|
|
|
|
BLI_assert(i < mesh->key->totkey);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
KeyBlock *kbn = BKE_keyblock_find_name(key, kb->name);
|
2019-01-15 23:24:20 +11:00
|
|
|
/* if key doesn't exist in destination mesh, add it */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (kbn) {
|
2012-09-19 12:11:28 +00:00
|
|
|
index_map[i] = BLI_findindex(&key->block, kbn);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-09-19 12:11:28 +00:00
|
|
|
else {
|
|
|
|
|
index_map[i] = key->totkey;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
kbn = BKE_keyblock_add(key, kb->name);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
BKE_keyblock_copy_settings(kbn, kb);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
/* adjust settings to fit (allocate a new data-array) */
|
2020-08-08 13:29:21 +10:00
|
|
|
kbn->data = MEM_callocN(sizeof(float[3]) * totvert, "joined_shapekey");
|
2012-09-19 12:11:28 +00:00
|
|
|
kbn->totelem = totvert;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
kb_map[i] = kbn;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
/* remap relative index values */
|
2023-12-08 16:40:06 -05:00
|
|
|
LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &mesh->key->block, i) {
|
2012-09-19 12:11:28 +00:00
|
|
|
/* sanity check, should always be true */
|
2023-12-08 16:40:06 -05:00
|
|
|
if (LIKELY(kb->relative < mesh->key->totkey)) {
|
2012-09-19 12:11:28 +00:00
|
|
|
kb_map[i]->relative = index_map[kb->relative];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
MEM_freeN(index_map);
|
2012-09-19 10:12:07 +00:00
|
|
|
MEM_freeN(kb_map);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-19 12:11:28 +00:00
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-12 11:50:43 +00:00
|
|
|
/* setup new data for destination mesh */
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData_reset(&vert_data);
|
|
|
|
|
CustomData_reset(&edge_data);
|
2012-10-31 09:50:24 +00:00
|
|
|
CustomData_reset(&ldata);
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData_reset(&face_data);
|
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
|
|
|
float3 *vert_positions = (float3 *)CustomData_add_layer_named(
|
2023-07-25 21:15:52 +02:00
|
|
|
&vert_data, CD_PROP_FLOAT3, CD_SET_DEFAULT, totvert, "position");
|
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
|
|
|
edge = (int2 *)CustomData_add_layer_named(
|
2023-07-25 21:15:52 +02:00
|
|
|
&edge_data, CD_PROP_INT32_2D, CD_CONSTRUCT, totedge, ".edge_verts");
|
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
|
|
|
int *corner_verts = (int *)CustomData_add_layer_named(
|
|
|
|
|
&ldata, CD_PROP_INT32, CD_CONSTRUCT, totloop, ".corner_vert");
|
|
|
|
|
int *corner_edges = (int *)CustomData_add_layer_named(
|
|
|
|
|
&ldata, CD_PROP_INT32, CD_CONSTRUCT, totloop, ".corner_edge");
|
2023-07-24 22:06:55 +02:00
|
|
|
int *face_offsets = static_cast<int *>(MEM_malloc_arrayN(faces_num + 1, sizeof(int), __func__));
|
|
|
|
|
face_offsets[faces_num] = totloop;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
vertofs = 0;
|
|
|
|
|
edgeofs = 0;
|
|
|
|
|
loopofs = 0;
|
|
|
|
|
polyofs = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-08-25 14:32:10 +10:00
|
|
|
/* Inverse transform for all selected meshes in this object,
|
|
|
|
|
* See #object_join_exec for detailed comment on why the safe version is used. */
|
2024-02-14 16:14:49 +01:00
|
|
|
invert_m4_m4_safe_ortho(imat, ob->object_to_world().ptr());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
/* Add back active mesh first.
|
|
|
|
|
* This allows to keep things similar as they were, as much as possible
|
|
|
|
|
* (i.e. data from active mesh will remain first ones in new result of the merge,
|
2023-02-12 14:37:16 +11:00
|
|
|
* in same order for CD layers, etc). See also #50084.
|
2019-04-17 06:17:24 +02:00
|
|
|
*/
|
2012-03-26 02:56:48 +00:00
|
|
|
join_mesh_single(depsgraph,
|
2019-04-17 06:17:24 +02:00
|
|
|
bmain,
|
|
|
|
|
scene,
|
|
|
|
|
ob,
|
|
|
|
|
ob,
|
|
|
|
|
imat,
|
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
|
|
|
&vert_positions,
|
2023-03-01 15:57:50 -05:00
|
|
|
&edge,
|
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
|
|
|
&corner_verts,
|
|
|
|
|
&corner_edges,
|
2023-07-24 22:06:55 +02:00
|
|
|
face_offsets,
|
2023-07-25 21:15:52 +02:00
|
|
|
&vert_data,
|
|
|
|
|
&edge_data,
|
2019-04-17 06:17:24 +02:00
|
|
|
&ldata,
|
2023-07-25 21:15:52 +02:00
|
|
|
&face_data,
|
2012-03-26 02:56:48 +00:00
|
|
|
totvert,
|
|
|
|
|
totedge,
|
|
|
|
|
totloop,
|
2023-07-24 22:06:55 +02:00
|
|
|
faces_num,
|
2019-01-15 23:24:20 +11:00
|
|
|
key,
|
2017-02-02 21:37:53 +01:00
|
|
|
nkey,
|
|
|
|
|
matar,
|
|
|
|
|
matmap,
|
|
|
|
|
totcol,
|
|
|
|
|
&vertofs,
|
|
|
|
|
&edgeofs,
|
|
|
|
|
&loopofs,
|
|
|
|
|
&polyofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
|
|
|
|
if (ob_iter == ob) {
|
2017-02-02 21:37:53 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2009-07-13 00:40:20 +00:00
|
|
|
/* only join if this is a mesh */
|
2018-10-01 16:43:49 +10:00
|
|
|
if (ob_iter->type == OB_MESH) {
|
2017-02-02 21:37:53 +01:00
|
|
|
join_mesh_single(depsgraph,
|
2018-04-06 12:07:27 +02:00
|
|
|
bmain,
|
|
|
|
|
scene,
|
2018-10-01 16:43:49 +10:00
|
|
|
ob,
|
|
|
|
|
ob_iter,
|
|
|
|
|
imat,
|
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
|
|
|
&vert_positions,
|
2023-03-01 15:57:50 -05:00
|
|
|
&edge,
|
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
|
|
|
&corner_verts,
|
|
|
|
|
&corner_edges,
|
2023-07-24 22:06:55 +02:00
|
|
|
face_offsets,
|
2023-07-25 21:15:52 +02:00
|
|
|
&vert_data,
|
|
|
|
|
&edge_data,
|
2017-02-02 21:37:53 +01:00
|
|
|
&ldata,
|
2023-07-25 21:15:52 +02:00
|
|
|
&face_data,
|
2017-02-02 21:37:53 +01:00
|
|
|
totvert,
|
|
|
|
|
totedge,
|
|
|
|
|
totloop,
|
2023-07-24 22:06:55 +02:00
|
|
|
faces_num,
|
2017-02-02 21:37:53 +01:00
|
|
|
key,
|
|
|
|
|
nkey,
|
|
|
|
|
matar,
|
|
|
|
|
matmap,
|
|
|
|
|
totcol,
|
|
|
|
|
&vertofs,
|
|
|
|
|
&edgeofs,
|
|
|
|
|
&loopofs,
|
|
|
|
|
&polyofs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/* free base, now that data is merged */
|
2018-10-01 16:43:49 +10:00
|
|
|
if (ob_iter != ob) {
|
2024-03-28 01:30:38 +01:00
|
|
|
blender::ed::object::base_free_and_unlink(bmain, scene, ob_iter);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2009-07-13 00:40:20 +00:00
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
/* return to mesh we're merging to */
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh = static_cast<Mesh *>(ob->data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
BKE_mesh_clear_geometry(mesh);
|
2023-04-12 11:27:52 -04:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
if (faces_num) {
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->face_offset_indices = face_offsets;
|
|
|
|
|
mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
|
2023-07-24 22:06:55 +02:00
|
|
|
face_offsets);
|
2023-04-14 17:58:13 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
mesh->verts_num = totvert;
|
|
|
|
|
mesh->edges_num = totedge;
|
|
|
|
|
mesh->corners_num = totloop;
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->faces_num = faces_num;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->vert_data = vert_data;
|
|
|
|
|
mesh->edge_data = edge_data;
|
2023-12-19 20:38:59 -05:00
|
|
|
mesh->corner_data = ldata;
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->face_data = face_data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* old material array */
|
2012-03-26 02:56:48 +00:00
|
|
|
for (a = 1; a <= ob->totcol; a++) {
|
|
|
|
|
ma = ob->mat[a - 1];
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ma) {
|
2015-11-09 19:47:10 +01:00
|
|
|
id_us_min(&ma->id);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2023-12-08 16:40:06 -05:00
|
|
|
for (a = 1; a <= mesh->totcol; a++) {
|
|
|
|
|
ma = mesh->mat[a - 1];
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ma) {
|
2015-11-09 19:47:10 +01:00
|
|
|
id_us_min(&ma->id);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2018-03-18 05:03:42 +01:00
|
|
|
MEM_SAFE_FREE(ob->mat);
|
|
|
|
|
MEM_SAFE_FREE(ob->matbits);
|
2023-12-08 16:40:06 -05:00
|
|
|
MEM_SAFE_FREE(mesh->mat);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (totcol) {
|
2023-12-08 16:40:06 -05:00
|
|
|
mesh->mat = matar;
|
2022-05-15 20:41:11 +02:00
|
|
|
ob->mat = static_cast<Material **>(MEM_callocN(sizeof(*ob->mat) * totcol, __func__));
|
|
|
|
|
ob->matbits = static_cast<char *>(MEM_callocN(sizeof(*ob->matbits) * totcol, __func__));
|
2017-02-02 21:37:53 +01:00
|
|
|
MEM_freeN(matmap);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
ob->totcol = mesh->totcol = totcol;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* other mesh users */
|
2023-12-08 16:40:06 -05:00
|
|
|
BKE_objects_materials_test_all(bmain, (ID *)mesh);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-03-10 11:32:48 +11:00
|
|
|
/* Free temporary copy of destination shape-keys (if applicable). */
|
2012-03-24 06:38:07 +00:00
|
|
|
if (nkey) {
|
2017-02-02 21:37:53 +01:00
|
|
|
/* We can assume nobody is using that ID currently. */
|
2019-01-24 14:31:47 +01:00
|
|
|
BKE_id_free_ex(bmain, nkey, LIB_ID_FREE_NO_UI_USER, false);
|
2009-07-13 00:40:20 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-19 12:11:28 +00:00
|
|
|
/* ensure newly inserted keys are time sorted */
|
|
|
|
|
if (key && (key->type != KEY_RELATIVE)) {
|
|
|
|
|
BKE_key_sort(key);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Due to dependency cycle some other object might access old derived data. */
|
2017-04-12 16:12:28 +02:00
|
|
|
BKE_object_free_derived_caches(ob);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-06-08 10:14:53 +02:00
|
|
|
DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
2012-03-26 02:56:48 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
|
2020-08-21 19:06:20 +02:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-13 00:40:20 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
|
2020-06-17 17:07:11 +10:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Join as Shapes
|
2021-12-10 21:42:06 +11:00
|
|
|
*
|
|
|
|
|
* Append selected meshes vertex locations as shapes of the active mesh.
|
2020-06-17 17:07:11 +10:00
|
|
|
* \{ */
|
2009-11-28 04:04:01 +00:00
|
|
|
|
2020-06-17 17:07:11 +10:00
|
|
|
int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
|
2009-11-28 04:04:01 +00:00
|
|
|
{
|
2018-06-12 12:53:27 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
2012-03-26 02:56:48 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-10-01 16:43:49 +10:00
|
|
|
Object *ob_active = CTX_data_active_object(C);
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = (Mesh *)ob_active->data;
|
2022-05-15 20:41:11 +02:00
|
|
|
Mesh *selme = nullptr;
|
|
|
|
|
Mesh *me_deformed = nullptr;
|
2023-12-08 16:40:06 -05:00
|
|
|
Key *key = mesh->key;
|
2009-11-28 04:04:01 +00:00
|
|
|
KeyBlock *kb;
|
2014-04-11 11:25:41 +10:00
|
|
|
bool ok = false, nonequal_verts = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
|
|
|
|
if (ob_iter == ob_active) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
if (ob_iter->type == OB_MESH) {
|
|
|
|
|
selme = (Mesh *)ob_iter->data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (selme->verts_num == mesh->verts_num) {
|
2014-04-11 11:25:41 +10:00
|
|
|
ok = true;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2022-05-15 20:41:11 +02:00
|
|
|
nonequal_verts = true;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-11-28 04:04:01 +00:00
|
|
|
}
|
|
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-28 04:04:01 +00:00
|
|
|
if (!ok) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (nonequal_verts) {
|
2011-09-19 12:26:20 +00:00
|
|
|
BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2011-09-19 12:26:20 +00:00
|
|
|
BKE_report(op->reports,
|
|
|
|
|
RPT_WARNING,
|
|
|
|
|
"No additional selected meshes with equal vertex count to join");
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-11-28 04:04:01 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
if (key == nullptr) {
|
2023-12-08 16:40:06 -05:00
|
|
|
key = mesh->key = BKE_key_add(bmain, (ID *)mesh);
|
2012-03-26 02:56:48 +00:00
|
|
|
key->type = KEY_RELATIVE;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-02 16:05:54 +00:00
|
|
|
/* first key added, so it was the basis. initialize it with the existing mesh */
|
2022-05-15 20:41:11 +02:00
|
|
|
kb = BKE_keyblock_add(key, nullptr);
|
2023-12-08 16:40:06 -05:00
|
|
|
BKE_keyblock_convert_from_mesh(mesh, key, kb);
|
2009-11-28 04:04:01 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-28 04:04:01 +00:00
|
|
|
/* now ready to add new keys from selected meshes */
|
2018-10-01 16:43:49 +10:00
|
|
|
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
|
|
|
|
|
if (ob_iter == ob_active) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
if (ob_iter->type == OB_MESH) {
|
|
|
|
|
selme = (Mesh *)ob_iter->data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (selme->verts_num == mesh->verts_num) {
|
2018-12-01 19:06:44 +03:00
|
|
|
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
|
|
|
|
|
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
me_deformed = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-06-21 18:24:32 +02:00
|
|
|
if (!me_deformed) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-10-01 16:43:49 +10:00
|
|
|
kb = BKE_keyblock_add(key, ob_iter->id.name + 2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
BKE_mesh_runtime_eval_to_meshkey(me_deformed, mesh, kb);
|
2009-11-28 04:04:01 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CTX_DATA_END;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-06 17:52:37 +01:00
|
|
|
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
|
2012-03-26 02:56:48 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-11-28 04:04:01 +00:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 17:07:11 +10:00
|
|
|
/** \} */
|
|
|
|
|
|
2014-03-13 01:36:24 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Mesh Topology Mirror API
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
static MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
|
2010-02-17 19:50:42 +00:00
|
|
|
|
2020-04-03 21:47:56 +11:00
|
|
|
BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
|
2024-03-11 11:21:12 -04:00
|
|
|
Mesh *mesh_eval,
|
|
|
|
|
Mesh **r_mesh_mirror,
|
2020-04-03 21:47:56 +11:00
|
|
|
BMEditMesh **r_em_mirror)
|
|
|
|
|
{
|
2024-03-11 11:21:12 -04:00
|
|
|
Mesh *mesh_mirror = nullptr;
|
2022-05-15 20:41:11 +02:00
|
|
|
BMEditMesh *em_mirror = nullptr;
|
2020-04-03 21:47:56 +11:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2024-03-11 11:21:12 -04:00
|
|
|
if (mesh_eval != nullptr) {
|
|
|
|
|
mesh_mirror = mesh_eval;
|
2020-04-03 21:47:56 +11:00
|
|
|
}
|
2024-03-21 23:18:49 +01:00
|
|
|
else if (BMEditMesh *em = mesh->runtime->edit_mesh) {
|
|
|
|
|
em_mirror = em;
|
2020-04-03 21:47:56 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2024-03-11 11:21:12 -04:00
|
|
|
mesh_mirror = mesh;
|
2020-04-03 21:47:56 +11:00
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
*r_mesh_mirror = mesh_mirror;
|
2020-04-03 21:47:56 +11:00
|
|
|
*r_em_mirror = em_mirror;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *mesh_eval)
|
2018-05-15 13:26:40 +02:00
|
|
|
{
|
2024-03-11 11:21:12 -04:00
|
|
|
Mesh *mesh_mirror;
|
2020-04-03 21:47:56 +11:00
|
|
|
BMEditMesh *em_mirror;
|
2024-03-11 11:21:12 -04:00
|
|
|
mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
|
2020-01-07 15:39:08 +11:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
ED_mesh_mirrtopo_init(em_mirror, mesh_mirror, &mesh_topo_store, false);
|
2020-04-03 21:47:56 +11:00
|
|
|
}
|
2020-01-07 15:39:08 +11:00
|
|
|
|
2022-10-03 17:37:25 -05:00
|
|
|
void ED_mesh_mirror_topo_table_end(Object * /*ob*/)
|
2020-04-03 21:47:56 +11:00
|
|
|
{
|
|
|
|
|
/* TODO: store this in object/object-data (keep unused argument for now). */
|
|
|
|
|
ED_mesh_mirrtopo_free(&mesh_topo_store);
|
|
|
|
|
}
|
2020-01-07 15:39:08 +11:00
|
|
|
|
2020-09-09 11:10:38 +02:00
|
|
|
/* Returns true on success. */
|
2024-03-11 11:21:12 -04:00
|
|
|
static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *mesh_eval)
|
2020-04-03 21:47:56 +11:00
|
|
|
{
|
2024-03-11 11:21:12 -04:00
|
|
|
Mesh *mesh_mirror;
|
2020-04-03 21:47:56 +11:00
|
|
|
BMEditMesh *em_mirror;
|
2024-03-11 11:21:12 -04:00
|
|
|
mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
if (ED_mesh_mirrtopo_recalc_check(em_mirror, mesh_mirror, &mesh_topo_store)) {
|
|
|
|
|
ED_mesh_mirror_topo_table_begin(ob, mesh_eval);
|
2020-04-03 21:47:56 +11:00
|
|
|
}
|
2020-09-09 11:10:38 +02:00
|
|
|
return true;
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
|
|
|
|
|
2014-03-13 01:36:24 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh_eval, int index)
|
2018-05-15 13:26:40 +02:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2024-03-11 11:21:12 -04:00
|
|
|
const Span<float3> positions = mesh_eval ? mesh_eval->vert_positions() : mesh->vert_positions();
|
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
|
|
|
|
2018-05-15 13:26:40 +02:00
|
|
|
float vec[3];
|
|
|
|
|
|
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
|
|
|
vec[0] = -positions[index][0];
|
|
|
|
|
vec[1] = positions[index][1];
|
|
|
|
|
vec[2] = positions[index][2];
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, mesh_eval, vec);
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
|
|
|
|
|
2018-06-21 19:05:10 +02:00
|
|
|
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
|
2018-05-15 13:26:40 +02:00
|
|
|
{
|
2020-09-09 11:10:38 +02:00
|
|
|
if (!ed_mesh_mirror_topo_table_update(ob, mesh)) {
|
2018-05-15 13:26:40 +02:00
|
|
|
return -1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-05-15 13:26:40 +02:00
|
|
|
|
|
|
|
|
return mesh_topo_store.index_lookup[index];
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, const bool use_topology)
|
2018-05-15 13:26:40 +02:00
|
|
|
{
|
|
|
|
|
if (use_topology) {
|
2024-03-11 11:21:12 -04:00
|
|
|
return mesh_get_x_mirror_vert_topo(ob, mesh_eval, index);
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
2024-03-11 11:21:12 -04:00
|
|
|
return mesh_get_x_mirror_vert_spatial(ob, mesh_eval, index);
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
|
|
|
|
|
2012-06-27 05:59:41 +00:00
|
|
|
static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
|
|
|
|
float vec[3];
|
2014-03-13 01:36:24 +11:00
|
|
|
int i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
/* ignore nan verts */
|
2016-05-16 00:48:02 +02:00
|
|
|
if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) {
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2012-04-28 06:31:57 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
vec[0] = -co[0];
|
|
|
|
|
vec[1] = co[1];
|
|
|
|
|
vec[2] = co[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
i = ED_mesh_mirror_spatial_table_lookup(ob, em, nullptr, vec);
|
2014-03-13 01:36:24 +11:00
|
|
|
if (i != -1) {
|
|
|
|
|
return BM_vert_at_index(em->bm, i);
|
|
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, BMEditMesh *em, BMVert *eve, int index)
|
2010-02-17 19:50:42 +00:00
|
|
|
{
|
2011-12-16 07:27:56 +00:00
|
|
|
intptr_t poinval;
|
2022-05-15 20:41:11 +02:00
|
|
|
if (!ed_mesh_mirror_topo_table_update(ob, nullptr)) {
|
|
|
|
|
return nullptr;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-09-28 19:53:45 +00:00
|
|
|
if (index == -1) {
|
2011-02-27 06:19:40 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
BMVert *v;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
index = 0;
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (v == eve) {
|
2011-02-27 06:19:40 +00:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2011-02-27 06:19:40 +00:00
|
|
|
index++;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-02-27 06:19:40 +00:00
|
|
|
if (index == em->bm->totvert) {
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2010-09-28 19:53:45 +00:00
|
|
|
}
|
2010-02-17 19:50:42 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
poinval = mesh_topo_store.index_lookup[index];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (poinval != -1) {
|
2011-02-27 06:19:40 +00:00
|
|
|
return (BMVert *)(poinval);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2018-06-04 09:31:30 +02:00
|
|
|
}
|
2010-02-17 19:50:42 +00:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
BMVert *editbmesh_get_x_mirror_vert(
|
|
|
|
|
Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
|
2010-02-17 19:50:42 +00:00
|
|
|
{
|
2013-06-28 17:13:09 +00:00
|
|
|
if (use_topology) {
|
2011-02-27 06:19:40 +00:00
|
|
|
return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
|
2012-02-06 09:39:47 +00:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
|
2010-02-17 19:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
2013-09-17 07:03:13 +00:00
|
|
|
int ED_mesh_mirror_get_vert(Object *ob, int index)
|
|
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
|
|
|
|
bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
|
2013-09-17 07:03:13 +00:00
|
|
|
int index_mirr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-03-21 23:18:49 +01:00
|
|
|
if (BMEditMesh *em = mesh->runtime->edit_mesh) {
|
2013-09-17 07:03:13 +00:00
|
|
|
BMVert *eve, *eve_mirr;
|
2013-10-28 02:05:33 +00:00
|
|
|
eve = BM_vert_at_index(em->bm, index);
|
2013-09-17 07:03:13 +00:00
|
|
|
eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology);
|
|
|
|
|
index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-05-15 20:41:11 +02:00
|
|
|
index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, use_topology);
|
2013-09-17 07:03:13 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-09-17 07:03:13 +00:00
|
|
|
return index_mirr;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-06 09:39:47 +00:00
|
|
|
#if 0
|
|
|
|
|
|
2019-04-17 08:24:14 +02:00
|
|
|
static float *editmesh_get_mirror_uv(
|
|
|
|
|
BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
|
2010-02-17 19:50:42 +00:00
|
|
|
{
|
|
|
|
|
float vec[2];
|
|
|
|
|
float cent_vec[2];
|
|
|
|
|
float cent[2];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-17 19:50:42 +00:00
|
|
|
/* ignore nan verts */
|
2019-04-17 08:24:14 +02:00
|
|
|
if (isnan(uv[0]) || !isfinite(uv[0]) || isnan(uv[1]) || !isfinite(uv[1])) {
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2016-01-21 09:05:52 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-17 19:50:42 +00:00
|
|
|
if (axis) {
|
2012-03-26 02:56:48 +00:00
|
|
|
vec[0] = uv[0];
|
|
|
|
|
vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-02-17 19:50:42 +00:00
|
|
|
cent_vec[0] = face_cent[0];
|
2012-03-26 02:56:48 +00:00
|
|
|
cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
|
2012-03-24 06:38:07 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2012-03-26 02:56:48 +00:00
|
|
|
vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
|
|
|
|
|
vec[1] = uv[1];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
|
2010-02-17 19:50:42 +00:00
|
|
|
cent_vec[1] = face_cent[1];
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-03 23:08:40 +10:00
|
|
|
/* TODO: Optimize. */
|
2010-02-17 19:50:42 +00:00
|
|
|
{
|
2011-02-27 06:19:40 +00:00
|
|
|
BMIter iter;
|
|
|
|
|
BMFace *efa;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
2020-08-11 15:11:31 +10:00
|
|
|
BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-17 08:24:14 +02:00
|
|
|
if ((fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
|
2011-02-27 06:19:40 +00:00
|
|
|
BMIter liter;
|
|
|
|
|
BMLoop *l;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-04-19 13:47:58 +00:00
|
|
|
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
2023-03-20 21:09:53 +01:00
|
|
|
float *luv2 = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
|
Mesh: Move UV layers to generic attributes
Currently the `MLoopUV` struct stores UV coordinates and flags related
to editing UV maps in the UV editor. This patch changes the coordinates
to use the generic 2D vector type, and moves the flags into three
separate boolean attributes. This follows the design in T95965, with
the ultimate intention of simplifying code and improving performance.
Importantly, the change allows exporters and renderers to use UVs
"touched" by geometry nodes, which only creates generic attributes.
It also allows geometry nodes to create "proper" UV maps from scratch,
though only with the Store Named Attribute node for now.
The new design considers any 2D vector attribute on the corner domain
to be a UV map. In the future, they might be distinguished from regular
2D vectors with attribute metadata, which may be helpful because they
are often interpolated differently.
Most of the code changes deal with passing around UV BMesh custom data
offsets and tracking the boolean "sublayers". The boolean layers are
use the following prefixes for attribute names: vert selection: `.vs.`,
edge selection: `.es.`, pinning: `.pn.`. Currently these are short to
avoid using up the maximum length of attribute names. To accommodate
for these 4 extra characters, the name length limit is enlarged to 68
bytes, while the maximum user settable name length is still 64 bytes.
Unfortunately Python/RNA API access to the UV flag data becomes slower.
Accessing the boolean layers directly is be better for performance in
general.
Like the other mesh SoA refactors, backward and forward compatibility
aren't affected, and won't be changed until 4.0. We pay for that by
making mesh reading and writing more expensive with conversions.
Resolves T85962
Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
|
|
|
if ((fabsf(luv[0] - vec[0]) < 0.001f) && (fabsf(luv[1] - vec[1]) < 0.001f)) {
|
|
|
|
|
return luv;
|
2012-03-26 02:56:48 +00:00
|
|
|
}
|
2010-02-17 19:50:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2010-02-17 19:50:42 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-06 09:39:47 +00:00
|
|
|
#endif
|
|
|
|
|
|
2020-04-03 16:21:24 +11:00
|
|
|
static uint mirror_facehash(const void *ptr)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2022-05-15 20:41:11 +02:00
|
|
|
const MFace *mf = static_cast<const MFace *>(ptr);
|
2020-04-03 16:21:24 +11:00
|
|
|
uint v0, v1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-24 06:38:07 +00:00
|
|
|
if (mf->v4) {
|
2024-01-22 15:58:18 +01:00
|
|
|
v0 = std::min({mf->v1, mf->v2, mf->v3, mf->v4});
|
|
|
|
|
v1 = std::max({mf->v1, mf->v2, mf->v3, mf->v4});
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2024-01-22 15:58:18 +01:00
|
|
|
v0 = std::min({mf->v1, mf->v2, mf->v3});
|
|
|
|
|
v1 = std::min({mf->v1, mf->v2, mf->v3});
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-26 02:56:48 +00:00
|
|
|
return ((v0 * 39) ^ (v1 * 31));
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2023-01-13 14:50:59 -06:00
|
|
|
static int mirror_facerotation(const MFace *a, const MFace *b)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2012-03-24 06:38:07 +00:00
|
|
|
if (b->v4) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 2;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 3;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) {
|
2008-12-30 13:16:14 +00:00
|
|
|
return 2;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 06:15:52 +10:00
|
|
|
static bool mirror_facecmp(const void *a, const void *b)
|
2008-12-30 13:16:14 +00:00
|
|
|
{
|
2012-03-26 02:56:48 +00:00
|
|
|
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
|
2008-12-30 13:16:14 +00:00
|
|
|
}
|
|
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
|
2018-05-15 13:26:40 +02:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2023-01-13 14:50:59 -06:00
|
|
|
MFace mirrormf;
|
|
|
|
|
const MFace *mf, *hashmf;
|
2018-05-15 13:26:40 +02:00
|
|
|
GHash *fhash;
|
|
|
|
|
int *mirrorverts, *mirrorfaces;
|
|
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
BLI_assert(em == nullptr); /* Does not work otherwise, currently... */
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
const bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
|
2024-03-11 11:21:12 -04:00
|
|
|
const int totvert = mesh_eval ? mesh_eval->verts_num : mesh->verts_num;
|
|
|
|
|
const int totface = mesh_eval ? mesh_eval->totface_legacy : mesh->totface_legacy;
|
2018-05-15 13:26:40 +02:00
|
|
|
int a;
|
|
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
mirrorverts = static_cast<int *>(MEM_callocN(sizeof(int) * totvert, "MirrorVerts"));
|
|
|
|
|
mirrorfaces = static_cast<int *>(MEM_callocN(sizeof(int[2]) * totface, "MirrorFaces"));
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
const Span<float3> vert_positions = mesh_eval ? mesh_eval->vert_positions() :
|
|
|
|
|
mesh->vert_positions();
|
2023-12-08 16:40:06 -05:00
|
|
|
const MFace *mface = (const MFace *)CustomData_get_layer(
|
2024-03-11 11:21:12 -04:00
|
|
|
&(mesh_eval ? mesh_eval : mesh)->fdata_legacy, CD_MFACE);
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
ED_mesh_mirror_spatial_table_begin(ob, em, mesh_eval);
|
2018-05-15 13:26:40 +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
|
|
|
for (const int i : vert_positions.index_range()) {
|
2024-03-11 11:21:12 -04:00
|
|
|
mirrorverts[i] = mesh_get_x_mirror_vert(ob, mesh_eval, i, use_topology);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2020-04-03 21:47:56 +11:00
|
|
|
ED_mesh_mirror_spatial_table_end(ob);
|
2018-05-15 13:26:40 +02:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
fhash = BLI_ghash_new_ex(
|
2023-12-08 16:40:06 -05:00
|
|
|
mirror_facehash, mirror_facecmp, "mirror_facehash gh", mesh->totface_legacy);
|
2019-04-22 09:19:45 +10:00
|
|
|
for (a = 0, mf = mface; a < totface; a++, mf++) {
|
2023-01-13 14:50:59 -06:00
|
|
|
BLI_ghash_insert(fhash, (void *)mf, (void *)mf);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-05-15 13:26:40 +02:00
|
|
|
|
|
|
|
|
for (a = 0, mf = mface; a < totface; a++, mf++) {
|
|
|
|
|
mirrormf.v1 = mirrorverts[mf->v3];
|
|
|
|
|
mirrormf.v2 = mirrorverts[mf->v2];
|
|
|
|
|
mirrormf.v3 = mirrorverts[mf->v1];
|
|
|
|
|
mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0;
|
|
|
|
|
|
|
|
|
|
/* make sure v4 is not 0 if a quad */
|
|
|
|
|
if (mf->v4 && mirrormf.v4 == 0) {
|
2023-01-09 11:12:03 -05:00
|
|
|
std::swap(mirrormf.v1, mirrormf.v3);
|
|
|
|
|
std::swap(mirrormf.v2, mirrormf.v4);
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-13 14:50:59 -06:00
|
|
|
hashmf = static_cast<const MFace *>(BLI_ghash_lookup(fhash, &mirrormf));
|
2018-05-15 13:26:40 +02:00
|
|
|
if (hashmf) {
|
|
|
|
|
mirrorfaces[a * 2] = hashmf - mface;
|
|
|
|
|
mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
|
|
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
else {
|
2018-05-15 13:26:40 +02:00
|
|
|
mirrorfaces[a * 2] = -1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-05-15 13:26:40 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-15 20:41:11 +02:00
|
|
|
BLI_ghash_free(fhash, nullptr, nullptr);
|
2018-05-15 13:26:40 +02:00
|
|
|
MEM_freeN(mirrorverts);
|
|
|
|
|
|
2008-12-30 13:16:14 +00:00
|
|
|
return mirrorfaces;
|
|
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2021-12-10 21:42:06 +11:00
|
|
|
/* Selection (vertex and face). */
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2019-03-16 11:38:55 +11:00
|
|
|
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
|
2012-09-06 23:50:28 +00:00
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2012-12-23 01:54:11 +00:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
if (!mesh || mesh->faces_num == 0) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2019-09-18 17:19:07 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2023-10-17 10:34:59 +02:00
|
|
|
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
|
2019-05-16 09:26:33 +10:00
|
|
|
ED_view3d_select_id_validate(&vc);
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2019-03-15 16:02:55 -03:00
|
|
|
if (dist_px) {
|
2022-05-17 15:34:02 +10:00
|
|
|
/* Sample rect to increase chances of selecting, so that when clicking
|
|
|
|
|
* on an edge in the back-buffer, we can still select a face. */
|
2019-08-15 10:31:54 -03:00
|
|
|
*r_index = DRW_select_buffer_find_nearest_to_point(
|
2023-12-08 16:40:06 -05:00
|
|
|
vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->faces_num + 1, &dist_px);
|
2012-09-06 23:50:28 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* sample only on the exact position */
|
2020-03-06 16:56:42 +01:00
|
|
|
*r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
|
2012-09-06 23:50:28 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
if ((*r_index) == 0 || (*r_index) > uint(mesh->faces_num)) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2019-03-16 11:38:55 +11:00
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2019-03-16 11:38:55 +11:00
|
|
|
(*r_index)--;
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
return true;
|
2012-09-06 23:50:28 +00:00
|
|
|
}
|
2019-03-15 16:02:55 -03:00
|
|
|
|
2013-11-01 01:14:36 +00:00
|
|
|
static void ed_mesh_pick_face_vert__mpoly_find(
|
|
|
|
|
/* context */
|
2022-05-15 20:41:11 +02:00
|
|
|
ARegion *region,
|
2013-11-01 01:14:36 +00:00
|
|
|
const float mval[2],
|
2018-06-01 14:29:22 +02:00
|
|
|
/* mesh data (evaluated) */
|
2023-07-24 22:06:55 +02:00
|
|
|
const blender::IndexRange face,
|
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
|
|
|
const Span<float3> vert_positions,
|
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
|
|
|
const int *corner_verts,
|
2013-11-01 01:14:36 +00:00
|
|
|
/* return values */
|
|
|
|
|
float *r_len_best,
|
|
|
|
|
int *r_v_idx_best)
|
|
|
|
|
{
|
2023-07-24 22:06:55 +02:00
|
|
|
for (int j = face.size(); j--;) {
|
2018-06-01 14:29:22 +02:00
|
|
|
float sco[2];
|
2023-07-24 22:06:55 +02:00
|
|
|
const int v_idx = corner_verts[face[j]];
|
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 (ED_view3d_project_float_object(region, vert_positions[v_idx], sco, V3D_PROJ_TEST_NOP) ==
|
|
|
|
|
V3D_PROJ_RET_OK)
|
|
|
|
|
{
|
2018-06-01 14:29:22 +02:00
|
|
|
const float len_test = len_manhattan_v2v2(mval, sco);
|
|
|
|
|
if (len_test < *r_len_best) {
|
|
|
|
|
*r_len_best = len_test;
|
2013-11-01 01:14:36 +00:00
|
|
|
*r_v_idx_best = v_idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-16 11:38:55 +11:00
|
|
|
bool ED_mesh_pick_face_vert(
|
|
|
|
|
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
|
2012-09-07 05:54:54 +00:00
|
|
|
{
|
2019-07-25 16:36:22 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2023-07-24 22:06:55 +02:00
|
|
|
uint face_index;
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
if (ED_mesh_pick_face(C, ob, mval, dist_px, &face_index)) {
|
2023-05-30 22:25:06 +02:00
|
|
|
const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
|
2024-03-11 11:21:12 -04:00
|
|
|
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
|
|
|
|
|
if (!mesh_eval) {
|
2023-05-30 22:25:06 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-01 01:14:36 +00:00
|
|
|
int v_idx_best = ORIGINDEX_NONE;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-01 01:14:36 +00:00
|
|
|
/* find the vert closest to 'mval' */
|
2022-09-25 18:33:28 +10:00
|
|
|
const float mval_f[2] = {float(mval[0]), float(mval[1])};
|
2013-11-01 01:14:36 +00:00
|
|
|
float len_best = FLT_MAX;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
const Span<float3> vert_positions = mesh_eval->vert_positions();
|
|
|
|
|
const blender::OffsetIndices faces = mesh_eval->faces();
|
|
|
|
|
const Span<int> corner_verts = mesh_eval->corner_verts();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
const int *index_mp_to_orig = (const int *)CustomData_get_layer(&mesh_eval->face_data,
|
2023-07-25 21:15:52 +02:00
|
|
|
CD_ORIGINDEX);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-11-01 01:14:36 +00:00
|
|
|
/* tag all verts using this face */
|
|
|
|
|
if (index_mp_to_orig) {
|
2023-07-24 22:06:55 +02:00
|
|
|
for (const int i : faces.index_range()) {
|
|
|
|
|
if (index_mp_to_orig[i] == face_index) {
|
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
|
|
|
ed_mesh_pick_face_vert__mpoly_find(region,
|
|
|
|
|
mval_f,
|
2023-07-24 22:06:55 +02:00
|
|
|
faces[i],
|
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
|
|
|
vert_positions,
|
|
|
|
|
corner_verts.data(),
|
|
|
|
|
&len_best,
|
|
|
|
|
&v_idx_best);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-07 05:54:54 +00:00
|
|
|
}
|
2013-11-01 01:14:36 +00:00
|
|
|
else {
|
2023-07-24 22:06:55 +02:00
|
|
|
if (face_index < faces.size()) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ed_mesh_pick_face_vert__mpoly_find(region,
|
2013-11-01 01:14:36 +00:00
|
|
|
mval_f,
|
2023-07-24 22:06:55 +02:00
|
|
|
faces[face_index],
|
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
|
|
|
vert_positions,
|
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
|
|
|
corner_verts.data(),
|
2013-11-01 01:14:36 +00:00
|
|
|
&len_best,
|
|
|
|
|
&v_idx_best);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
/* map 'dm -> mesh' r_index if possible */
|
2013-11-01 01:14:36 +00:00
|
|
|
if (v_idx_best != ORIGINDEX_NONE) {
|
2024-03-11 11:21:12 -04:00
|
|
|
const int *index_mv_to_orig = (const int *)CustomData_get_layer(&mesh_eval->vert_data,
|
2022-05-15 20:41:11 +02:00
|
|
|
CD_ORIGINDEX);
|
2013-11-01 01:14:36 +00:00
|
|
|
if (index_mv_to_orig) {
|
|
|
|
|
v_idx_best = index_mv_to_orig[v_idx_best];
|
|
|
|
|
}
|
2012-09-07 05:54:54 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < mesh->verts_num)) {
|
2019-03-16 10:12:47 +11:00
|
|
|
*r_index = v_idx_best;
|
2013-03-19 23:17:44 +00:00
|
|
|
return true;
|
2012-09-07 05:54:54 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2012-09-07 05:54:54 +00:00
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vertex selection in object mode,
|
|
|
|
|
* currently only weight paint uses this.
|
|
|
|
|
*
|
2013-03-19 23:17:44 +00:00
|
|
|
* \return boolean true == Found
|
2012-09-06 23:50:28 +00:00
|
|
|
*/
|
2022-05-15 20:41:11 +02:00
|
|
|
struct VertPickData {
|
2023-12-12 17:49:51 -05:00
|
|
|
blender::VArraySpan<bool> hide_vert;
|
2012-12-23 02:32:03 +00:00
|
|
|
const float *mval_f; /* [2] */
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region;
|
2012-12-23 02:32:03 +00:00
|
|
|
|
|
|
|
|
/* runtime */
|
|
|
|
|
float len_best;
|
|
|
|
|
int v_idx_best;
|
2022-05-15 20:41:11 +02:00
|
|
|
};
|
2012-12-23 02:32:03 +00:00
|
|
|
|
2023-07-27 12:04:18 +10:00
|
|
|
static void ed_mesh_pick_vert__mapFunc(void *user_data,
|
2012-12-23 02:32:03 +00:00
|
|
|
int index,
|
|
|
|
|
const float co[3],
|
2022-10-12 10:27:27 +11:00
|
|
|
const float /*no*/[3])
|
2012-12-23 02:32:03 +00:00
|
|
|
{
|
2023-07-27 12:04:18 +10:00
|
|
|
VertPickData *data = static_cast<VertPickData *>(user_data);
|
2023-12-12 17:49:51 -05:00
|
|
|
if (!data->hide_vert.is_empty() && data->hide_vert[index]) {
|
Mesh: Move hide flags to generic attributes
This commit moves the hide status of mesh vertices, edges, and faces
from the `ME_FLAG` to optional generic boolean attributes. Storing this
data as generic attributes can significantly simplify and improve code,
as described in T95965.
The attributes are called `.hide_vert`, `.hide_edge`, and `.hide_poly`,
using the attribute name semantics discussed in T97452. The `.` prefix
means they are "UI attributes", so they still contain original data
edited by users, but they aren't meant to be accessed procedurally by
the user in arbitrary situations. They are also be hidden in the
spreadsheet and the attribute list by default,
Until 4.0, the attributes are still written to and read from the mesh
in the old way, so neither forward nor backward compatibility are
affected. This means memory requirements will be increased by one byte
per element when the hide status is used. When the flags are removed
completely, requirements will decrease when hiding is unused.
Further notes:
* Some code can be further simplified to skip some processing when the
hide attributes don't exist.
* The data is still stored in flags for `BMesh`, necessitating some
complexity in the conversion to and from `Mesh`.
* Access to the "hide" property of mesh elements in RNA is slower.
The separate boolean arrays should be used where possible.
Ref T95965
Differential Revision: https://developer.blender.org/D14685
2022-08-11 12:54:24 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
float sco[2];
|
|
|
|
|
if (ED_view3d_project_float_object(data->region, co, sco, V3D_PROJ_TEST_CLIP_DEFAULT) ==
|
|
|
|
|
V3D_PROJ_RET_OK)
|
|
|
|
|
{
|
|
|
|
|
const float len = len_manhattan_v2v2(data->mval_f, sco);
|
|
|
|
|
if (len < data->len_best) {
|
|
|
|
|
data->len_best = len;
|
|
|
|
|
data->v_idx_best = index;
|
2012-12-23 02:32:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-16 11:38:55 +11:00
|
|
|
bool ED_mesh_pick_vert(
|
|
|
|
|
bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
|
2012-09-06 23:50:28 +00:00
|
|
|
{
|
2023-12-12 17:49:51 -05:00
|
|
|
using namespace blender;
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
2012-12-23 01:54:11 +00:00
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if (!mesh || mesh->verts_num == 0) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2019-09-18 17:19:07 +02:00
|
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
2023-10-17 10:34:59 +02:00
|
|
|
ViewContext vc = ED_view3d_viewcontext_init(C, depsgraph);
|
2019-05-16 09:26:33 +10:00
|
|
|
ED_view3d_select_id_validate(&vc);
|
2012-09-07 00:58:00 +00:00
|
|
|
|
2012-12-23 01:54:11 +00:00
|
|
|
if (use_zbuf) {
|
2019-03-15 16:02:55 -03:00
|
|
|
if (dist_px > 0) {
|
2022-05-19 10:02:52 +10:00
|
|
|
/* Sample rectangle to increase chances of selecting, so that when clicking
|
|
|
|
|
* on an face in the back-buffer, we can still select a vert. */
|
2019-08-15 10:31:54 -03:00
|
|
|
*r_index = DRW_select_buffer_find_nearest_to_point(
|
2023-12-20 02:21:48 +01:00
|
|
|
vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->verts_num + 1, &dist_px);
|
2012-12-23 01:54:11 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* sample only on the exact position */
|
2020-03-06 16:56:42 +01:00
|
|
|
*r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
|
2012-12-23 01:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-20 02:21:48 +01:00
|
|
|
if ((*r_index) == 0 || (*r_index) > uint(mesh->verts_num)) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2019-03-16 10:12:47 +11:00
|
|
|
}
|
2012-12-23 01:54:11 +00:00
|
|
|
|
2019-03-16 10:12:47 +11:00
|
|
|
(*r_index)--;
|
2012-09-06 23:50:28 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2023-05-30 22:25:06 +02:00
|
|
|
const Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, ob);
|
2024-03-11 11:21:12 -04:00
|
|
|
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = vc.region;
|
2022-05-15 20:41:11 +02:00
|
|
|
RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2012-12-23 02:32:03 +00:00
|
|
|
/* find the vert closest to 'mval' */
|
2022-09-25 18:33:28 +10:00
|
|
|
const float mval_f[2] = {float(mval[0]), float(mval[1])};
|
2012-09-06 23:50:28 +00: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
|
|
|
VertPickData data{};
|
2012-12-23 02:32:03 +00:00
|
|
|
|
|
|
|
|
ED_view3d_init_mats_rv3d(ob, rv3d);
|
2012-12-23 01:54:11 +00:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
if (mesh_eval == nullptr) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2012-12-23 01:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-12 17:49:51 -05:00
|
|
|
const bke::AttributeAccessor attributes = mesh->attributes();
|
|
|
|
|
|
2012-12-23 02:32:03 +00:00
|
|
|
/* setup data */
|
2020-03-06 16:56:42 +01:00
|
|
|
data.region = region;
|
2012-12-23 02:32:03 +00:00
|
|
|
data.mval_f = mval_f;
|
|
|
|
|
data.len_best = FLT_MAX;
|
|
|
|
|
data.v_idx_best = -1;
|
2023-12-20 13:13:16 -05:00
|
|
|
data.hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
|
2012-12-23 02:04:38 +00:00
|
|
|
|
2024-03-11 11:21:12 -04:00
|
|
|
BKE_mesh_foreach_mapped_vert(mesh_eval, ed_mesh_pick_vert__mapFunc, &data, MESH_FOREACH_NOP);
|
2012-12-23 01:54:11 +00:00
|
|
|
|
2012-12-23 02:32:03 +00:00
|
|
|
if (data.v_idx_best == -1) {
|
2013-03-19 23:17:44 +00:00
|
|
|
return false;
|
2012-12-23 01:54:11 +00:00
|
|
|
}
|
2012-12-23 02:32:03 +00:00
|
|
|
|
2019-03-16 10:12:47 +11:00
|
|
|
*r_index = data.v_idx_best;
|
2012-12-23 01:54:11 +00:00
|
|
|
}
|
2012-09-06 23:50:28 +00:00
|
|
|
|
2013-03-19 23:17:44 +00:00
|
|
|
return true;
|
2012-09-06 23:50:28 +00:00
|
|
|
}
|
2013-06-24 04:41:03 +00:00
|
|
|
|
|
|
|
|
MDeformVert *ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
|
|
|
|
|
{
|
2021-07-13 12:10:34 -04:00
|
|
|
if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
|
|
|
|
if (!BLI_listbase_is_empty(&mesh->vertex_group_names)) {
|
2024-03-21 23:18:49 +01:00
|
|
|
BMesh *bm = mesh->runtime->edit_mesh->bm;
|
2021-07-13 12:10:34 -04:00
|
|
|
const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-13 12:10:34 -04:00
|
|
|
if (cd_dvert_offset != -1) {
|
|
|
|
|
BMVert *eve = BM_mesh_active_vert_get(bm);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-07-13 12:10:34 -04:00
|
|
|
if (eve) {
|
|
|
|
|
if (r_eve) {
|
|
|
|
|
*r_eve = eve;
|
|
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (r_eve) {
|
2022-05-15 20:41:11 +02:00
|
|
|
*r_eve = nullptr;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MDeformVert *ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
|
|
|
|
|
{
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh = static_cast<Mesh *>(ob->data);
|
|
|
|
|
int index = BKE_mesh_mselect_active_get(mesh, ME_VSEL);
|
2019-04-22 09:19:45 +10:00
|
|
|
if (r_index) {
|
2013-06-24 04:41:03 +00:00
|
|
|
*r_index = index;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2023-12-08 16:40:06 -05:00
|
|
|
if (index == -1 || mesh->deform_verts().is_empty()) {
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
2023-12-08 16:40:06 -05:00
|
|
|
MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
|
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
|
|
|
return &dverts[index];
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MDeformVert *ED_mesh_active_dvert_get_only(Object *ob)
|
|
|
|
|
{
|
|
|
|
|
if (ob->type == OB_MESH) {
|
2018-04-05 18:20:27 +02:00
|
|
|
if (ob->mode & OB_MODE_EDIT) {
|
2022-05-15 20:41:11 +02:00
|
|
|
return ED_mesh_active_dvert_get_em(ob, nullptr);
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return ED_mesh_active_dvert_get_ob(ob, nullptr);
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
2022-05-15 20:41:11 +02:00
|
|
|
return nullptr;
|
2013-06-24 04:41:03 +00:00
|
|
|
}
|
2018-04-16 16:27:55 +02:00
|
|
|
|
2024-01-24 18:18:14 +01:00
|
|
|
void EDBM_mesh_stats_multi(const Span<Object *> objects, int totelem[3], int totelem_sel[3])
|
2018-04-16 16:27:55 +02:00
|
|
|
{
|
|
|
|
|
if (totelem) {
|
|
|
|
|
totelem[0] = 0;
|
|
|
|
|
totelem[1] = 0;
|
|
|
|
|
totelem[2] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (totelem_sel) {
|
|
|
|
|
totelem_sel[0] = 0;
|
|
|
|
|
totelem_sel[1] = 0;
|
|
|
|
|
totelem_sel[2] = 0;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-01-24 18:18:14 +01:00
|
|
|
for (Object *obedit : objects) {
|
2018-04-16 16:27:55 +02:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
if (totelem) {
|
|
|
|
|
totelem[0] += bm->totvert;
|
|
|
|
|
totelem[1] += bm->totedge;
|
|
|
|
|
totelem[2] += bm->totface;
|
|
|
|
|
}
|
|
|
|
|
if (totelem_sel) {
|
|
|
|
|
totelem_sel[0] += bm->totvertsel;
|
|
|
|
|
totelem_sel[1] += bm->totedgesel;
|
|
|
|
|
totelem_sel[2] += bm->totfacesel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-24 18:18:14 +01:00
|
|
|
void EDBM_mesh_elem_index_ensure_multi(const Span<Object *> objects, const char htype)
|
2018-04-16 16:27:55 +02:00
|
|
|
{
|
|
|
|
|
int elem_offset[4] = {0, 0, 0, 0};
|
2024-01-24 18:18:14 +01:00
|
|
|
for (Object *obedit : objects) {
|
2018-04-16 16:27:55 +02:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset);
|
|
|
|
|
}
|
|
|
|
|
}
|