2023-05-31 16:19:06 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup bke
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
|
2022-08-31 09:09:01 -05:00
|
|
|
#include "BKE_attribute.hh"
|
2021-02-21 17:57:03 -05:00
|
|
|
#include "BKE_customdata.h"
|
|
|
|
|
#include "BKE_material.h"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2021-04-02 00:16:01 -05:00
|
|
|
#include "BKE_mesh_boolean_convert.hh"
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
#include "BLI_alloca.h"
|
2021-04-02 00:16:01 -05:00
|
|
|
#include "BLI_array.hh"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_geom.h"
|
|
|
|
|
#include "BLI_math_matrix.h"
|
2023-02-06 21:25:45 +01:00
|
|
|
#include "BLI_math_matrix.hh"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_vector.h"
|
2021-02-21 17:57:03 -05:00
|
|
|
#include "BLI_mesh_boolean.hh"
|
|
|
|
|
#include "BLI_mesh_intersect.hh"
|
|
|
|
|
#include "BLI_span.hh"
|
2023-09-01 21:37:11 +02:00
|
|
|
#include "BLI_string.h"
|
2021-07-05 18:09:36 -04:00
|
|
|
#include "BLI_task.hh"
|
2022-08-31 09:09:01 -05:00
|
|
|
#include "BLI_virtual_array.hh"
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
namespace blender::meshintersect {
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_GMP
|
|
|
|
|
|
|
|
|
|
constexpr int estimated_max_facelen = 100; /* Used for initial size of some Vectors. */
|
|
|
|
|
|
|
|
|
|
/* Snap entries that are near 0 or 1 or -1 to those values.
|
|
|
|
|
* Sometimes Blender's rotation matrices for multiples of 90 degrees have
|
|
|
|
|
* tiny numbers where there should be zeros. That messes makes some things
|
|
|
|
|
* every so slightly non-coplanar when users expect coplanarity,
|
|
|
|
|
* so this is a hack to clean up such matrices.
|
|
|
|
|
* Would be better to change the transformation code itself.
|
|
|
|
|
*/
|
2022-04-27 18:52:56 -05:00
|
|
|
static float4x4 clean_transform(const float4x4 &mat)
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
float4x4 cleaned;
|
2021-02-21 17:57:03 -05:00
|
|
|
const float fuzz = 1e-6f;
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
for (int j = 0; j < 4; j++) {
|
2023-02-06 21:25:45 +01:00
|
|
|
float f = mat[i][j];
|
2021-02-21 17:57:03 -05:00
|
|
|
if (fabsf(f) <= fuzz) {
|
|
|
|
|
f = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (fabsf(f - 1.0f) <= fuzz) {
|
|
|
|
|
f = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (fabsf(f + 1.0f) <= fuzz) {
|
|
|
|
|
f = -1.0f;
|
|
|
|
|
}
|
2023-02-06 21:25:45 +01:00
|
|
|
cleaned[i][j] = f;
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
return cleaned;
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* `MeshesToIMeshInfo` keeps track of information used when combining a number
|
|
|
|
|
* of `Mesh`es into a single `IMesh` for doing boolean on.
|
|
|
|
|
* Mostly this means keeping track of the index offsets for various mesh elements. */
|
|
|
|
|
class MeshesToIMeshInfo {
|
|
|
|
|
public:
|
|
|
|
|
/* The input meshes, */
|
|
|
|
|
Span<const Mesh *> meshes;
|
|
|
|
|
/* Numbering the vertices of the meshes in order of meshes,
|
|
|
|
|
* at what offset does the vertex range for mesh[i] start? */
|
|
|
|
|
Array<int> mesh_vert_offset;
|
|
|
|
|
/* Similarly for edges of meshes. */
|
|
|
|
|
Array<int> mesh_edge_offset;
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Similarly for faces of meshes. */
|
|
|
|
|
Array<int> mesh_face_offset;
|
2021-02-21 17:57:03 -05:00
|
|
|
/* For each Mesh vertex in all the meshes (with concatenated indexing),
|
2021-02-24 15:53:03 +11:00
|
|
|
* what is the IMesh Vert* allocated for it in the input IMesh? */
|
2021-02-21 17:57:03 -05:00
|
|
|
Array<const Vert *> mesh_to_imesh_vert;
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Similarly for each Mesh face. */
|
2021-02-21 17:57:03 -05:00
|
|
|
Array<Face *> mesh_to_imesh_face;
|
|
|
|
|
/* Transformation matrix to transform a coordinate in the corresponding
|
|
|
|
|
* Mesh to the local space of the first Mesh. */
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
Array<float4x4> to_target_transform;
|
2021-07-25 13:29:45 -04:00
|
|
|
/* For each input mesh, whether or not their transform is negative. */
|
|
|
|
|
Array<bool> has_negative_transform;
|
2021-03-14 11:39:56 -04:00
|
|
|
/* For each input mesh, how to remap the material slot numbers to
|
|
|
|
|
* the material slots in the first mesh. */
|
2021-04-02 00:16:01 -05:00
|
|
|
Span<Array<short>> material_remaps;
|
2021-02-21 17:57:03 -05:00
|
|
|
/* Total number of input mesh vertices. */
|
|
|
|
|
int tot_meshes_verts;
|
|
|
|
|
/* Total number of input mesh edges. */
|
|
|
|
|
int tot_meshes_edges;
|
|
|
|
|
/* Total number of input mesh polys. */
|
|
|
|
|
int tot_meshes_polys;
|
|
|
|
|
|
|
|
|
|
int input_mesh_for_imesh_vert(int imesh_v) const;
|
|
|
|
|
int input_mesh_for_imesh_edge(int imesh_e) const;
|
|
|
|
|
int input_mesh_for_imesh_face(int imesh_f) const;
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange input_face_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_orig_mesh_index,
|
|
|
|
|
int *r_index_in_orig_mesh) const;
|
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
|
|
|
void input_mvert_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_index_in_orig_mesh) const;
|
2023-03-01 14:13:05 +01:00
|
|
|
void input_medge_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_index_in_orig_mesh) const;
|
2021-02-21 17:57:03 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Given an index `imesh_v` in the `IMesh`, return the index of the
|
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
|
|
|
* input `Mesh` that contained the vertex that it came from. */
|
2021-02-21 17:57:03 -05:00
|
|
|
int MeshesToIMeshInfo::input_mesh_for_imesh_vert(int imesh_v) const
|
|
|
|
|
{
|
2022-09-25 18:30:50 +10:00
|
|
|
int n = int(mesh_vert_offset.size());
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int i = 0; i < n - 1; ++i) {
|
|
|
|
|
if (imesh_v < mesh_vert_offset[i + 1]) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given an index `imesh_e` used as an original index in the `IMesh`,
|
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
|
|
|
* return the index of the input `Mesh` that contained the vertex that it came from. */
|
2021-02-21 17:57:03 -05:00
|
|
|
int MeshesToIMeshInfo::input_mesh_for_imesh_edge(int imesh_e) const
|
|
|
|
|
{
|
2022-09-25 18:30:50 +10:00
|
|
|
int n = int(mesh_edge_offset.size());
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int i = 0; i < n - 1; ++i) {
|
|
|
|
|
if (imesh_e < mesh_edge_offset[i + 1]) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given an index `imesh_f` in the `IMesh`, return the index of the
|
2023-07-24 22:06:55 +02:00
|
|
|
* input `Mesh` that contained the face that it came from. */
|
2021-02-21 17:57:03 -05:00
|
|
|
int MeshesToIMeshInfo::input_mesh_for_imesh_face(int imesh_f) const
|
|
|
|
|
{
|
2023-07-24 22:06:55 +02:00
|
|
|
int n = int(mesh_face_offset.size());
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int i = 0; i < n - 1; ++i) {
|
2023-07-24 22:06:55 +02:00
|
|
|
if (imesh_f < mesh_face_offset[i + 1]) {
|
2021-02-21 17:57:03 -05:00
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given an index of an original face in the `IMesh`, find out the input
|
|
|
|
|
* `Mesh` that it came from and return it in `*r_orig_mesh`,
|
|
|
|
|
* and also return the index of that `Mesh` in `*r_orig_mesh_index`.
|
2023-07-24 22:06:55 +02:00
|
|
|
* Finally, return the index of the corresponding face in that `Mesh`
|
2021-02-21 17:57:03 -05:00
|
|
|
* in `*r_index_in_orig_mesh`. */
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange MeshesToIMeshInfo::input_face_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_orig_mesh_index,
|
|
|
|
|
int *r_index_in_orig_mesh) const
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
|
|
|
|
int orig_mesh_index = input_mesh_for_imesh_face(orig_index);
|
|
|
|
|
BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
|
|
|
|
|
const Mesh *me = meshes[orig_mesh_index];
|
2023-07-24 22:06:55 +02:00
|
|
|
const OffsetIndices faces = me->faces();
|
|
|
|
|
int index_in_mesh = orig_index - mesh_face_offset[orig_mesh_index];
|
|
|
|
|
BLI_assert(0 <= index_in_mesh && index_in_mesh < me->faces_num);
|
|
|
|
|
const IndexRange face = faces[index_in_mesh];
|
2021-02-21 17:57:03 -05:00
|
|
|
if (r_orig_mesh) {
|
|
|
|
|
*r_orig_mesh = me;
|
|
|
|
|
}
|
|
|
|
|
if (r_orig_mesh_index) {
|
|
|
|
|
*r_orig_mesh_index = orig_mesh_index;
|
|
|
|
|
}
|
|
|
|
|
if (r_index_in_orig_mesh) {
|
|
|
|
|
*r_index_in_orig_mesh = index_in_mesh;
|
|
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
return face;
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given an index of an original vertex in the `IMesh`, find out the input
|
|
|
|
|
* `Mesh` that it came from and return it in `*r_orig_mesh`.
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
* Also find the index of the vertex in that `Mesh` and return it in
|
2021-02-21 17:57:03 -05:00
|
|
|
* `*r_index_in_orig_mesh`. */
|
Mesh: Move positions to a generic attribute
**Changes**
As described in T93602, this patch removes all use of the `MVert`
struct, replacing it with a generic named attribute with the name
`"position"`, consistent with other geometry types.
Variable names have been changed from `verts` to `positions`, to align
with the attribute name and the more generic design (positions are not
vertices, they are just an attribute stored on the point domain).
This change is made possible by previous commits that moved all other
data out of `MVert` to runtime data or other generic attributes. What
remains is mostly a simple type change. Though, the type still shows up
859 times, so the patch is quite large.
One compromise is that now `CD_MASK_BAREMESH` now contains
`CD_PROP_FLOAT3`. With the general move towards generic attributes
over custom data types, we are removing use of these type masks anyway.
**Benefits**
The most obvious benefit is reduced memory usage and the benefits
that brings in memory-bound situations. `float3` is only 3 bytes, in
comparison to `MVert` which was 4. When there are millions of vertices
this starts to matter more.
The other benefits come from using a more generic type. Instead of
writing algorithms specifically for `MVert`, code can just use arrays
of vectors. This will allow eliminating many temporary arrays or
wrappers used to extract positions.
Many possible improvements aren't implemented in this patch, though
I did switch simplify or remove the process of creating temporary
position arrays in a few places.
The design clarity that "positions are just another attribute" brings
allows removing explicit copying of vertices in some procedural
operations-- they are just processed like most other attributes.
**Performance**
This touches so many areas that it's hard to benchmark exhaustively,
but I observed some areas as examples.
* The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster.
* The Spring splash screen went from ~4.3 to ~4.5 fps.
* The subdivision surface modifier/node was slightly faster
RNA access through Python may be slightly slower, since now we need
a name lookup instead of just a custom data type lookup for each index.
**Future Improvements**
* Remove uses of "vert_coords" functions:
* `BKE_mesh_vert_coords_alloc`
* `BKE_mesh_vert_coords_get`
* `BKE_mesh_vert_coords_apply{_with_mat4}`
* Remove more hidden copying of positions
* General simplification now possible in many areas
* Convert more code to C++ to use `float3` instead of `float[3]`
* Currently `reinterpret_cast` is used for those C-API functions
Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
|
|
|
void MeshesToIMeshInfo::input_mvert_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_index_in_orig_mesh) const
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
|
|
|
|
int orig_mesh_index = input_mesh_for_imesh_vert(orig_index);
|
|
|
|
|
BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
|
|
|
|
|
const Mesh *me = meshes[orig_mesh_index];
|
|
|
|
|
int index_in_mesh = orig_index - mesh_vert_offset[orig_mesh_index];
|
|
|
|
|
BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totvert);
|
|
|
|
|
if (r_orig_mesh) {
|
|
|
|
|
*r_orig_mesh = me;
|
|
|
|
|
}
|
|
|
|
|
if (r_index_in_orig_mesh) {
|
|
|
|
|
*r_index_in_orig_mesh = index_in_mesh;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Similarly for edges. */
|
2023-03-01 14:13:05 +01:00
|
|
|
void MeshesToIMeshInfo::input_medge_for_orig_index(int orig_index,
|
|
|
|
|
const Mesh **r_orig_mesh,
|
|
|
|
|
int *r_index_in_orig_mesh) const
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
|
|
|
|
int orig_mesh_index = input_mesh_for_imesh_edge(orig_index);
|
|
|
|
|
BLI_assert(0 <= orig_mesh_index && orig_mesh_index < meshes.size());
|
|
|
|
|
const Mesh *me = meshes[orig_mesh_index];
|
|
|
|
|
int index_in_mesh = orig_index - mesh_edge_offset[orig_mesh_index];
|
|
|
|
|
BLI_assert(0 <= index_in_mesh && index_in_mesh < me->totedge);
|
|
|
|
|
if (r_orig_mesh) {
|
|
|
|
|
*r_orig_mesh = me;
|
|
|
|
|
}
|
|
|
|
|
if (r_index_in_orig_mesh) {
|
|
|
|
|
*r_index_in_orig_mesh = index_in_mesh;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 18:47:10 +10:00
|
|
|
/**
|
|
|
|
|
* Convert all of the meshes in `meshes` to an `IMesh` and return that.
|
2021-02-21 17:57:03 -05:00
|
|
|
* All of the coordinates are transformed into the local space of the
|
|
|
|
|
* first Mesh. To do this transformation, we also need the transformation
|
|
|
|
|
* obmats corresponding to the Meshes, so they are in the `obmats` argument.
|
|
|
|
|
* The 'original' indexes in the IMesh are the indexes you get by
|
2023-07-24 22:06:55 +02:00
|
|
|
* a scheme that offsets each vertex, edge, and face index by the sum of the
|
2021-02-21 17:57:03 -05:00
|
|
|
* vertices, edges, and polys in the preceding Meshes in the mesh span.
|
|
|
|
|
* The `*r_info class` is filled in with information needed to make the
|
|
|
|
|
* correspondence between the Mesh MVerts/MPolys and the IMesh Verts/Faces.
|
|
|
|
|
* All allocation of memory for the IMesh comes from `arena`.
|
|
|
|
|
*/
|
|
|
|
|
static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
|
2021-03-02 20:58:05 -06:00
|
|
|
Span<const float4x4 *> obmats,
|
2021-04-02 00:16:01 -05:00
|
|
|
Span<Array<short>> material_remaps,
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
const float4x4 &target_transform,
|
2021-02-21 17:57:03 -05:00
|
|
|
IMeshArena &arena,
|
|
|
|
|
MeshesToIMeshInfo *r_info)
|
|
|
|
|
{
|
|
|
|
|
int nmeshes = meshes.size();
|
|
|
|
|
BLI_assert(nmeshes > 0);
|
|
|
|
|
r_info->meshes = meshes;
|
|
|
|
|
r_info->tot_meshes_verts = 0;
|
|
|
|
|
r_info->tot_meshes_polys = 0;
|
|
|
|
|
int &totvert = r_info->tot_meshes_verts;
|
|
|
|
|
int &totedge = r_info->tot_meshes_edges;
|
2023-07-24 22:06:55 +02:00
|
|
|
int &faces_num = r_info->tot_meshes_polys;
|
2021-02-21 17:57:03 -05:00
|
|
|
for (const Mesh *me : meshes) {
|
|
|
|
|
totvert += me->totvert;
|
|
|
|
|
totedge += me->totedge;
|
2023-07-24 22:06:55 +02:00
|
|
|
faces_num += me->faces_num;
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Estimate the number of vertices and faces in the boolean output,
|
|
|
|
|
* so that the memory arena can reserve some space. It is OK if these
|
|
|
|
|
* estimates are wrong. */
|
|
|
|
|
const int estimate_num_outv = 3 * totvert;
|
2023-07-24 22:06:55 +02:00
|
|
|
const int estimate_num_outf = 4 * faces_num;
|
2021-02-21 17:57:03 -05:00
|
|
|
arena.reserve(estimate_num_outv, estimate_num_outf);
|
2022-04-27 18:52:56 -05:00
|
|
|
r_info->mesh_to_imesh_vert.reinitialize(totvert);
|
2023-07-24 22:06:55 +02:00
|
|
|
r_info->mesh_to_imesh_face.reinitialize(faces_num);
|
2022-04-27 18:52:56 -05:00
|
|
|
r_info->mesh_vert_offset.reinitialize(nmeshes);
|
|
|
|
|
r_info->mesh_edge_offset.reinitialize(nmeshes);
|
2023-07-24 22:06:55 +02:00
|
|
|
r_info->mesh_face_offset.reinitialize(nmeshes);
|
2022-04-27 18:52:56 -05:00
|
|
|
r_info->to_target_transform.reinitialize(nmeshes);
|
|
|
|
|
r_info->has_negative_transform.reinitialize(nmeshes);
|
2021-04-02 00:16:01 -05:00
|
|
|
r_info->material_remaps = material_remaps;
|
2021-02-21 17:57:03 -05:00
|
|
|
int v = 0;
|
|
|
|
|
int e = 0;
|
|
|
|
|
int f = 0;
|
|
|
|
|
|
|
|
|
|
/* Put these Vectors here, with a size unlikely to need resizing,
|
|
|
|
|
* so that the loop to make new Faces will likely not need to allocate
|
|
|
|
|
* over and over. */
|
|
|
|
|
Vector<const Vert *, estimated_max_facelen> face_vert;
|
|
|
|
|
Vector<int, estimated_max_facelen> face_edge_orig;
|
|
|
|
|
|
2022-04-27 18:52:56 -05:00
|
|
|
/* To convert the coordinates of meshes 1, 2, etc. into the local space
|
|
|
|
|
* of the target, multiply each transform by the inverse of the
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
* target matrix. Exact Boolean works better if these matrices are 'cleaned'
|
2022-04-27 18:52:56 -05:00
|
|
|
* -- see the comment for the `clean_transform` function, above. */
|
2023-02-06 21:25:45 +01:00
|
|
|
const float4x4 inv_target_mat = math::invert(clean_transform(target_transform));
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
/* For each input `Mesh`, make `Vert`s and `Face`s for the corresponding
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
* vertices and polygons, and keep track of the original indices (using the
|
2021-02-21 17:57:03 -05:00
|
|
|
* concatenating offset scheme) inside the `Vert`s and `Face`s.
|
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
|
|
|
* When making `Face`s, we also put in the original indices for edges that
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
* make up the polygons using the same scheme. */
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int mi : meshes.index_range()) {
|
|
|
|
|
const Mesh *me = meshes[mi];
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
r_info->mesh_vert_offset[mi] = v;
|
|
|
|
|
r_info->mesh_edge_offset[mi] = e;
|
2023-07-24 22:06:55 +02:00
|
|
|
r_info->mesh_face_offset[mi] = f;
|
2022-04-27 18:52:56 -05:00
|
|
|
/* Get matrix that transforms a coordinate in meshes[mi]'s local space
|
2022-02-23 18:24:08 +11:00
|
|
|
* to the target space. */
|
2023-05-18 15:08:53 -04:00
|
|
|
const float4x4 objn_mat = (obmats.is_empty() || obmats[mi] == nullptr) ?
|
|
|
|
|
float4x4::identity() :
|
|
|
|
|
clean_transform(*obmats[mi]);
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
r_info->to_target_transform[mi] = inv_target_mat * objn_mat;
|
2023-02-06 21:25:45 +01:00
|
|
|
r_info->has_negative_transform[mi] = math::is_negative(objn_mat);
|
2021-07-25 13:29:45 -04:00
|
|
|
|
|
|
|
|
/* All meshes 1 and up will be transformed into the local space of operand 0.
|
|
|
|
|
* Historical behavior of the modifier has been to flip the faces of any meshes
|
|
|
|
|
* that would have a negative transform if you do that. */
|
|
|
|
|
bool need_face_flip = r_info->has_negative_transform[mi] != r_info->has_negative_transform[0];
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
|
2021-07-05 18:09:36 -04:00
|
|
|
Vector<Vert *> verts(me->totvert);
|
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 = me->vert_positions();
|
2023-07-24 22:06:55 +02:00
|
|
|
const OffsetIndices faces = me->faces();
|
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 Span<int> corner_verts = me->corner_verts();
|
|
|
|
|
const Span<int> corner_edges = me->corner_edges();
|
2021-07-05 18:09:36 -04:00
|
|
|
|
|
|
|
|
/* Allocate verts
|
|
|
|
|
* Skip the matrix multiplication for each point when there is no transform for a mesh,
|
|
|
|
|
* for example when the first mesh is already in the target space. (Note the logic
|
|
|
|
|
* directly above, which uses an identity matrix with a null input transform). */
|
2023-05-18 15:08:53 -04:00
|
|
|
if (obmats.is_empty() || obmats[mi] == nullptr) {
|
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
|
|
|
threading::parallel_for(vert_positions.index_range(), 2048, [&](IndexRange range) {
|
2021-07-05 18:09:36 -04:00
|
|
|
for (int i : range) {
|
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 co = vert_positions[i];
|
2021-07-05 18:09:36 -04:00
|
|
|
mpq3 mco = mpq3(co.x, co.y, co.z);
|
|
|
|
|
double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
|
|
|
|
|
verts[i] = new Vert(mco, dco, NO_INDEX, i);
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
else {
|
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
|
|
|
threading::parallel_for(vert_positions.index_range(), 2048, [&](IndexRange range) {
|
2021-07-05 18:09:36 -04:00
|
|
|
for (int i : range) {
|
2023-02-06 21:25:45 +01:00
|
|
|
float3 co = math::transform_point(r_info->to_target_transform[mi], vert_positions[i]);
|
2021-07-05 18:09:36 -04:00
|
|
|
mpq3 mco = mpq3(co.x, co.y, co.z);
|
|
|
|
|
double3 dco(mco[0].get_d(), mco[1].get_d(), mco[2].get_d());
|
|
|
|
|
verts[i] = new Vert(mco, dco, NO_INDEX, i);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
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 (int i : vert_positions.index_range()) {
|
2021-07-05 18:09:36 -04:00
|
|
|
r_info->mesh_to_imesh_vert[v] = arena.add_or_find_vert(verts[i]);
|
|
|
|
|
++v;
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
for (const int face_i : faces.index_range()) {
|
|
|
|
|
const IndexRange face = faces[face_i];
|
|
|
|
|
int flen = face.size();
|
2021-07-25 13:29:45 -04:00
|
|
|
face_vert.resize(flen);
|
|
|
|
|
face_edge_orig.resize(flen);
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int i = 0; i < flen; ++i) {
|
2023-07-24 22:06:55 +02:00
|
|
|
const int corner_i = face[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
|
|
|
int mverti = r_info->mesh_vert_offset[mi] + corner_verts[corner_i];
|
2021-02-21 17:57:03 -05:00
|
|
|
const Vert *fv = r_info->mesh_to_imesh_vert[mverti];
|
2021-07-25 13:29:45 -04:00
|
|
|
if (need_face_flip) {
|
|
|
|
|
face_vert[flen - i - 1] = fv;
|
|
|
|
|
int iedge = i < flen - 1 ? flen - i - 2 : flen - 1;
|
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
|
|
|
face_edge_orig[iedge] = e + corner_edges[corner_i];
|
2021-07-25 13:29:45 -04:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
face_vert[i] = fv;
|
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
|
|
|
face_edge_orig[i] = e + corner_edges[corner_i];
|
2021-07-25 13:29:45 -04:00
|
|
|
}
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
r_info->mesh_to_imesh_face[f] = arena.add_face(face_vert, f, face_edge_orig);
|
|
|
|
|
++f;
|
|
|
|
|
}
|
|
|
|
|
e += me->totedge;
|
|
|
|
|
}
|
|
|
|
|
return IMesh(r_info->mesh_to_imesh_face);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy vertex attributes, including customdata, from `orig_mv` to `mv`.
|
|
|
|
|
* `mv` is in `dest_mesh` with index `mv_index`.
|
|
|
|
|
* The `orig_mv` vertex came from Mesh `orig_me` and had index `index_in_orig_me` there. */
|
|
|
|
|
static void copy_vert_attributes(Mesh *dest_mesh,
|
|
|
|
|
const Mesh *orig_me,
|
|
|
|
|
int mv_index,
|
|
|
|
|
int index_in_orig_me)
|
|
|
|
|
{
|
|
|
|
|
/* For all layers in the orig mesh, copy the layer information. */
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *target_cd = &dest_mesh->vert_data;
|
|
|
|
|
const CustomData *source_cd = &orig_me->vert_data;
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
|
2023-03-29 17:10:49 +02:00
|
|
|
const eCustomDataType ty = eCustomDataType(source_cd->layers[source_layer_i].type);
|
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 (StringRef(source_cd->layers->name) == "position") {
|
2021-02-21 17:57:03 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const char *name = source_cd->layers[source_layer_i].name;
|
|
|
|
|
int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
|
|
|
|
|
/* Not all layers were merged in target: some are marked CD_FLAG_NOCOPY
|
|
|
|
|
* and some are not in the CD_MASK_MESH.vdata. */
|
|
|
|
|
if (target_layer_i != -1) {
|
|
|
|
|
CustomData_copy_data_layer(
|
|
|
|
|
source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, mv_index, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Similar to copy_vert_attributes but for face attributes. */
|
|
|
|
|
static void copy_face_attributes(Mesh *dest_mesh,
|
2021-02-21 17:57:03 -05:00
|
|
|
const Mesh *orig_me,
|
2023-07-24 22:06:55 +02:00
|
|
|
int face_index,
|
2021-03-14 11:39:56 -04:00
|
|
|
int index_in_orig_me,
|
2022-08-31 09:09:01 -05:00
|
|
|
Span<short> material_remap,
|
|
|
|
|
MutableSpan<int> dst_material_indices)
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *target_cd = &dest_mesh->face_data;
|
|
|
|
|
const CustomData *source_cd = &orig_me->face_data;
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
|
2023-03-29 17:10:49 +02:00
|
|
|
const eCustomDataType ty = eCustomDataType(source_cd->layers[source_layer_i].type);
|
2021-02-21 17:57:03 -05:00
|
|
|
const char *name = source_cd->layers[source_layer_i].name;
|
|
|
|
|
int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
|
|
|
|
|
if (target_layer_i != -1) {
|
|
|
|
|
CustomData_copy_data_layer(
|
2023-07-24 22:06:55 +02:00
|
|
|
source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, face_index, 1);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-21 15:49:18 -06:00
|
|
|
|
|
|
|
|
/* Fix material indices after they have been transferred as a generic attribute. */
|
2023-04-19 11:21:06 +02:00
|
|
|
const VArray<int> src_material_indices = *orig_me->attributes().lookup_or_default<int>(
|
2022-11-21 15:49:18 -06:00
|
|
|
"material_index", ATTR_DOMAIN_FACE, 0);
|
|
|
|
|
const int src_index = src_material_indices[index_in_orig_me];
|
Fix T99592: Exact Boolean: Skip empty materials, add index-based option
**Empty Slot Fix**
Currently the boolean modifier transfers the default material from
meshes with no materials and empty material slots to the faces on the
base mesh. I added this in a2d59b2dac9e for the sake of consistency,
but the behavior is actually not useful at all. The default empty
material isn't chosen by users, it just signifies "nothing," so when
it replaces a material chosen by users, it feels like a bug.
This commit corrects that behavior by only transferring materials from
non-empty material slots. The implementation is now consistent between
exact mode of the boolean modifier and the geometry node.
**Index-Based Option**
"Index-based" is the new default material method for the boolean
modifier, to access the old behavior from before the breaking commit.
a2d59b2dac9e actually broke some Boolean workflows fundamentally, since
it was important to set up matching slot indices on each operand. That
isn't the cleanest workflow, and it breaks when materials change
procedurally, but historically that hasn't been a problem. The
"transfer" behavior transfers all materials except for empty slots,
but the fundamental problem is that there isn't a good way to specify
the result materials besides using the slot indices.
Even then, the transfer option is a bit more intuitive and useful for
some simpler situations, and it allows accessing the behavior that has
been in 3.2 and 3.3 for a long time, so it's also left in as an option.
The geometry node doesn't get this new option, in the hope that we'll
find a better solution in the future.
Differential Revision: https://developer.blender.org/D16187
2022-11-28 12:42:08 -06:00
|
|
|
if (material_remap.index_range().contains(src_index)) {
|
|
|
|
|
const int remapped_index = material_remap[src_index];
|
2023-07-24 22:06:55 +02:00
|
|
|
dst_material_indices[face_index] = remapped_index >= 0 ? remapped_index : src_index;
|
2022-11-21 15:49:18 -06:00
|
|
|
}
|
|
|
|
|
else {
|
2023-07-24 22:06:55 +02:00
|
|
|
dst_material_indices[face_index] = src_index;
|
2022-11-21 15:49:18 -06:00
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
BLI_assert(dst_material_indices[face_index] >= 0);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Similar to copy_vert_attributes but for edge attributes. */
|
|
|
|
|
static void copy_edge_attributes(Mesh *dest_mesh,
|
|
|
|
|
const Mesh *orig_me,
|
|
|
|
|
int medge_index,
|
|
|
|
|
int index_in_orig_me)
|
|
|
|
|
{
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *target_cd = &dest_mesh->edge_data;
|
|
|
|
|
const CustomData *source_cd = &orig_me->edge_data;
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
|
2023-03-29 17:10:49 +02:00
|
|
|
const eCustomDataType ty = eCustomDataType(source_cd->layers[source_layer_i].type);
|
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
|
|
|
if (ty == CD_PROP_INT32_2D) {
|
|
|
|
|
if (STREQ(source_cd->layers[source_layer_i].name, ".edge_verts")) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
const char *name = source_cd->layers[source_layer_i].name;
|
|
|
|
|
int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
|
|
|
|
|
if (target_layer_i != -1) {
|
|
|
|
|
CustomData_copy_data_layer(
|
|
|
|
|
source_cd, target_cd, source_layer_i, target_layer_i, index_in_orig_me, medge_index, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-25 16:34:27 +11:00
|
|
|
/**
|
2023-07-24 22:06:55 +02:00
|
|
|
* For #IMesh face `f`, with corresponding output Mesh face `face`,
|
|
|
|
|
* where the original Mesh face is `orig_face`, coming from the Mesh
|
2021-02-21 17:57:03 -05:00
|
|
|
* `orig_me`, which has index `orig_me_index` in `mim`:
|
|
|
|
|
* fill in the `orig_loops` Array with corresponding indices of MLoops from `orig_me`
|
|
|
|
|
* where they have the same start and end vertices; for cases where that is
|
|
|
|
|
* not true, put -1 in the `orig_loops` slot.
|
2023-07-24 22:06:55 +02:00
|
|
|
* For now, we only try to do this if `face` and `orig_face` have the same size.
|
2021-02-21 17:57:03 -05:00
|
|
|
* Return the number of non-null MLoops filled in.
|
|
|
|
|
*/
|
|
|
|
|
static int fill_orig_loops(const Face *f,
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange orig_face,
|
2021-02-21 17:57:03 -05:00
|
|
|
const Mesh *orig_me,
|
|
|
|
|
int orig_me_index,
|
|
|
|
|
MeshesToIMeshInfo &mim,
|
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
|
|
|
MutableSpan<int> r_orig_loops)
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
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
|
|
|
r_orig_loops.fill(-1);
|
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 Span<int> orig_corner_verts = orig_me->corner_verts();
|
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
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
int orig_mplen = orig_face.size();
|
2021-02-21 17:57:03 -05:00
|
|
|
if (f->size() != orig_mplen) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
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
|
|
|
BLI_assert(r_orig_loops.size() == orig_mplen);
|
2021-02-21 17:57:03 -05:00
|
|
|
/* We'll look for the case where the first vertex in f has an original vertex
|
|
|
|
|
* that is the same as one in orig_me (after correcting for offset in mim meshes).
|
|
|
|
|
* Then see that loop and any subsequent ones have the same start and end vertex.
|
|
|
|
|
* This may miss some cases of partial alignment, but that's OK since discovering
|
2021-02-25 16:34:27 +11:00
|
|
|
* aligned loops is only an optimization to avoid some re-interpolation.
|
2021-02-21 17:57:03 -05:00
|
|
|
*/
|
|
|
|
|
int first_orig_v = f->vert[0]->orig;
|
|
|
|
|
if (first_orig_v == NO_INDEX) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* It is possible that the original vert was merged with another in another mesh. */
|
|
|
|
|
if (orig_me_index != mim.input_mesh_for_imesh_vert(first_orig_v)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
int orig_me_vert_offset = mim.mesh_vert_offset[orig_me_index];
|
|
|
|
|
int first_orig_v_in_orig_me = first_orig_v - orig_me_vert_offset;
|
|
|
|
|
BLI_assert(0 <= first_orig_v_in_orig_me && first_orig_v_in_orig_me < orig_me->totvert);
|
2023-07-26 15:23:26 +10:00
|
|
|
/* Assume all vertices in each face is unique. */
|
2021-02-21 17:57:03 -05:00
|
|
|
int offset = -1;
|
|
|
|
|
for (int i = 0; i < orig_mplen; ++i) {
|
2023-07-24 22:06:55 +02:00
|
|
|
int loop_i = i + orig_face.start();
|
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
|
|
|
if (orig_corner_verts[loop_i] == first_orig_v_in_orig_me) {
|
2021-02-21 17:57:03 -05:00
|
|
|
offset = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (offset == -1) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
int num_orig_loops_found = 0;
|
|
|
|
|
for (int mp_loop_index = 0; mp_loop_index < orig_mplen; ++mp_loop_index) {
|
|
|
|
|
int orig_mp_loop_index = (mp_loop_index + offset) % orig_mplen;
|
2023-07-24 22:06:55 +02:00
|
|
|
const int vert_i = orig_corner_verts[orig_face.start() + orig_mp_loop_index];
|
2021-02-21 17:57:03 -05:00
|
|
|
int fv_orig = f->vert[mp_loop_index]->orig;
|
|
|
|
|
if (fv_orig != NO_INDEX) {
|
|
|
|
|
fv_orig -= orig_me_vert_offset;
|
|
|
|
|
if (fv_orig < 0 || fv_orig >= orig_me->totvert) {
|
|
|
|
|
fv_orig = NO_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
|
|
|
if (vert_i == fv_orig) {
|
|
|
|
|
const int vert_next =
|
2023-07-24 22:06:55 +02:00
|
|
|
orig_corner_verts[orig_face.start() + ((orig_mp_loop_index + 1) % orig_mplen)];
|
2021-02-21 17:57:03 -05:00
|
|
|
int fvnext_orig = f->vert[(mp_loop_index + 1) % orig_mplen]->orig;
|
|
|
|
|
if (fvnext_orig != NO_INDEX) {
|
|
|
|
|
fvnext_orig -= orig_me_vert_offset;
|
|
|
|
|
if (fvnext_orig < 0 || fvnext_orig >= orig_me->totvert) {
|
|
|
|
|
fvnext_orig = NO_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
|
|
|
if (vert_next == fvnext_orig) {
|
2023-07-24 22:06:55 +02:00
|
|
|
r_orig_loops[mp_loop_index] = orig_face.start() + orig_mp_loop_index;
|
2021-02-21 17:57:03 -05:00
|
|
|
++num_orig_loops_found;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return num_orig_loops_found;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Fill `cos_2d` with the 2d coordinates found by projection face `face` along
|
2021-02-21 17:57:03 -05:00
|
|
|
* its normal. Also fill in r_axis_mat with the matrix that does that projection.
|
|
|
|
|
* But before projecting, also transform the 3d coordinate by multiplying by trans_mat.
|
2023-07-24 22:06:55 +02:00
|
|
|
* `cos_2d` should have room for `face.size()` entries. */
|
2021-02-21 17:57:03 -05:00
|
|
|
static void get_poly2d_cos(const Mesh *me,
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange face,
|
2021-02-21 17:57:03 -05:00
|
|
|
float (*cos_2d)[2],
|
2021-03-02 20:58:05 -06:00
|
|
|
const float4x4 &trans_mat,
|
2021-02-21 17:57:03 -05:00
|
|
|
float r_axis_mat[3][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
|
|
|
const Span<float3> positions = me->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 Span<int> corner_verts = me->corner_verts();
|
2023-07-24 22:06:55 +02:00
|
|
|
const Span<int> face_verts = corner_verts.slice(face);
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
/* Project coordinates to 2d in cos_2d, using normal as projection axis. */
|
2023-07-24 22:06:55 +02:00
|
|
|
const float3 axis_dominant = bke::mesh::face_normal_calc(positions, face_verts);
|
2021-02-21 17:57:03 -05:00
|
|
|
axis_dominant_v3_to_m3(r_axis_mat, axis_dominant);
|
2023-07-24 22:06:55 +02:00
|
|
|
for (const int i : face_verts.index_range()) {
|
|
|
|
|
float3 co = positions[face_verts[i]];
|
2023-02-06 21:25:45 +01:00
|
|
|
co = math::transform_point(trans_mat, co);
|
|
|
|
|
*reinterpret_cast<float2 *>(&cos_2d[i]) = (float3x3(r_axis_mat) * co).xy();
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
/* For the loops of `face`, see if the face is unchanged from `orig_face`, and if so,
|
2021-02-21 17:57:03 -05:00
|
|
|
* copy the Loop attributes from corresponding loops to corresponding loops.
|
2023-07-24 22:06:55 +02:00
|
|
|
* Otherwise, interpolate the Loop attributes in the face `orig_face`. */
|
2021-02-21 17:57:03 -05:00
|
|
|
static void copy_or_interp_loop_attributes(Mesh *dest_mesh,
|
|
|
|
|
const Face *f,
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange face,
|
|
|
|
|
const IndexRange orig_face,
|
2021-02-21 17:57:03 -05:00
|
|
|
const Mesh *orig_me,
|
|
|
|
|
int orig_me_index,
|
|
|
|
|
MeshesToIMeshInfo &mim)
|
|
|
|
|
{
|
2023-07-24 22:06:55 +02:00
|
|
|
Array<int> orig_loops(face.size());
|
|
|
|
|
int norig = fill_orig_loops(f, orig_face, orig_me, orig_me_index, mim, orig_loops);
|
2021-02-21 17:57:03 -05:00
|
|
|
/* We may need these arrays if we have to interpolate Loop attributes rather than just copy.
|
|
|
|
|
* Right now, trying Array<float[2]> complains, so declare cos_2d a different way. */
|
|
|
|
|
float(*cos_2d)[2];
|
|
|
|
|
Array<float> weights;
|
|
|
|
|
Array<const void *> src_blocks_ofs;
|
|
|
|
|
float axis_mat[3][3];
|
2023-07-24 22:06:55 +02:00
|
|
|
if (norig != face.size()) {
|
|
|
|
|
/* We will need to interpolate. Make `cos_2d` hold 2d-projected coordinates of `orig_face`,
|
2021-02-21 17:57:03 -05:00
|
|
|
* which are transformed into object 0's local space before projecting.
|
|
|
|
|
* At this point we cannot yet calculate the interpolation weights, as they depend on
|
|
|
|
|
* the coordinate where interpolation is to happen, but we can allocate the needed arrays,
|
|
|
|
|
* so they don't have to be allocated per-layer. */
|
2023-07-24 22:06:55 +02:00
|
|
|
cos_2d = (float(*)[2])BLI_array_alloca(cos_2d, orig_face.size());
|
|
|
|
|
weights = Array<float>(orig_face.size());
|
|
|
|
|
src_blocks_ofs = Array<const void *>(orig_face.size());
|
|
|
|
|
get_poly2d_cos(orig_me, orig_face, cos_2d, mim.to_target_transform[orig_me_index], axis_mat);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
2023-07-25 21:15:52 +02:00
|
|
|
CustomData *target_cd = &dest_mesh->loop_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
|
|
|
const Span<float3> dst_positions = dest_mesh->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 Span<int> dst_corner_verts = dest_mesh->corner_verts();
|
2023-07-24 22:06:55 +02:00
|
|
|
for (int i = 0; i < face.size(); ++i) {
|
|
|
|
|
int loop_index = face[i];
|
2021-02-21 17:57:03 -05:00
|
|
|
int orig_loop_index = norig > 0 ? orig_loops[i] : -1;
|
2023-07-25 21:15:52 +02:00
|
|
|
const CustomData *source_cd = &orig_me->loop_data;
|
2021-02-21 17:57:03 -05:00
|
|
|
if (orig_loop_index == -1) {
|
|
|
|
|
/* Will need interpolation weights for this loop's vertex's coordinates.
|
2023-07-24 22:06:55 +02:00
|
|
|
* The coordinate needs to be projected into 2d, just like the interpolating face's
|
2021-02-21 17:57:03 -05:00
|
|
|
* coordinates were. The `dest_mesh` coordinates are already in object 0 local space. */
|
|
|
|
|
float co[2];
|
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
|
|
|
mul_v2_m3v3(co, axis_mat, dst_positions[dst_corner_verts[loop_index]]);
|
2023-07-24 22:06:55 +02:00
|
|
|
interp_weights_poly_v2(weights.data(), cos_2d, orig_face.size(), co);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
|
2023-03-29 17:10:49 +02:00
|
|
|
const eCustomDataType ty = eCustomDataType(source_cd->layers[source_layer_i].type);
|
2023-03-21 19:46:13 +11:00
|
|
|
if (STR_ELEM(source_cd->layers[source_layer_i].name, ".corner_vert", ".corner_edge")) {
|
2021-02-21 17:57:03 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const char *name = source_cd->layers[source_layer_i].name;
|
|
|
|
|
int target_layer_i = CustomData_get_named_layer_index(target_cd, ty, name);
|
|
|
|
|
if (target_layer_i == -1) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (orig_loop_index != -1) {
|
|
|
|
|
CustomData_copy_data_layer(
|
|
|
|
|
source_cd, target_cd, source_layer_i, target_layer_i, orig_loop_index, loop_index, 1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2021-07-03 23:08:40 +10:00
|
|
|
/* NOTE: although CustomData_bmesh_interp_n function has bmesh in its name, nothing about
|
2021-02-21 17:57:03 -05:00
|
|
|
* it is BMesh-specific. We can't use CustomData_interp because it assumes that
|
|
|
|
|
* all source layers exist in the dest.
|
|
|
|
|
* A non bmesh version could have the benefit of not copying data into src_blocks_ofs -
|
|
|
|
|
* using the contiguous data instead. TODO: add to the custom data API. */
|
|
|
|
|
int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name);
|
2021-03-06 09:05:55 -05:00
|
|
|
if (!CustomData_layer_has_interp(source_cd, source_layer_i)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2021-02-21 17:57:03 -05:00
|
|
|
int source_layer_type_index = source_layer_i - source_cd->typemap[ty];
|
|
|
|
|
BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0);
|
2023-01-13 17:21:20 -06:00
|
|
|
const int size = CustomData_sizeof(ty);
|
2023-07-24 22:06:55 +02:00
|
|
|
for (int j = 0; j < orig_face.size(); ++j) {
|
2023-01-13 17:21:20 -06:00
|
|
|
const void *layer = CustomData_get_layer_n(source_cd, ty, source_layer_type_index);
|
2023-07-24 22:06:55 +02:00
|
|
|
src_blocks_ofs[j] = POINTER_OFFSET(layer, size * (orig_face[j]));
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
2023-01-13 17:21:20 -06:00
|
|
|
void *dst_layer = CustomData_get_layer_n_for_write(
|
|
|
|
|
target_cd, ty, target_layer_type_index, dest_mesh->totloop);
|
|
|
|
|
void *dst_block_ofs = POINTER_OFFSET(dst_layer, size * loop_index);
|
2021-02-21 17:57:03 -05:00
|
|
|
CustomData_bmesh_interp_n(target_cd,
|
|
|
|
|
src_blocks_ofs.data(),
|
|
|
|
|
weights.data(),
|
|
|
|
|
nullptr,
|
2023-07-24 22:06:55 +02:00
|
|
|
orig_face.size(),
|
2021-02-21 17:57:03 -05:00
|
|
|
dst_block_ofs,
|
|
|
|
|
target_layer_i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 18:47:10 +10:00
|
|
|
/**
|
|
|
|
|
* Make sure that there are custom data layers in the target mesh
|
2021-02-21 17:57:03 -05:00
|
|
|
* corresponding to all target layers in all of the operands after the first.
|
|
|
|
|
* (The target should already have layers for those in the first operand mesh).
|
|
|
|
|
* Edges done separately -- will have to be done later, after edges are made.
|
|
|
|
|
*/
|
2023-07-24 22:06:55 +02:00
|
|
|
static void merge_vertex_loop_face_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
|
|
|
|
for (int mesh_index = 1; mesh_index < mim.meshes.size(); ++mesh_index) {
|
|
|
|
|
const Mesh *me = mim.meshes[mesh_index];
|
|
|
|
|
if (me->totvert) {
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_merge_layout(
|
2023-07-25 21:15:52 +02:00
|
|
|
&me->vert_data, &target->vert_data, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
if (me->totloop) {
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_merge_layout(
|
2023-07-25 21:15:52 +02:00
|
|
|
&me->loop_data, &target->loop_data, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
if (me->faces_num) {
|
2023-07-25 15:23:56 -04:00
|
|
|
CustomData_merge_layout(&me->face_data,
|
|
|
|
|
&target->face_data,
|
|
|
|
|
CD_MASK_MESH.pmask,
|
|
|
|
|
CD_SET_DEFAULT,
|
|
|
|
|
target->faces_num);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim)
|
|
|
|
|
{
|
2022-12-26 14:43:32 -05:00
|
|
|
for (int mesh_index = 0; mesh_index < mim.meshes.size(); ++mesh_index) {
|
2021-02-21 17:57:03 -05:00
|
|
|
const Mesh *me = mim.meshes[mesh_index];
|
|
|
|
|
if (me->totedge) {
|
2023-04-13 14:57:57 +02:00
|
|
|
CustomData_merge_layout(
|
2023-07-25 21:15:52 +02:00
|
|
|
&me->edge_data, &target->edge_data, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-09 18:47:10 +10:00
|
|
|
/**
|
|
|
|
|
* Convert the output IMesh im to a Blender Mesh,
|
2021-02-21 17:57:03 -05:00
|
|
|
* using the information in mim to get all the attributes right.
|
|
|
|
|
*/
|
|
|
|
|
static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
|
|
|
|
|
{
|
|
|
|
|
constexpr int dbg_level = 0;
|
|
|
|
|
|
|
|
|
|
im->populate_vert();
|
|
|
|
|
int out_totvert = im->vert_size();
|
2023-07-24 22:06:55 +02:00
|
|
|
int out_faces_num = im->face_size();
|
2021-02-21 17:57:03 -05:00
|
|
|
int out_totloop = 0;
|
|
|
|
|
for (const Face *f : im->faces()) {
|
|
|
|
|
out_totloop += f->size();
|
|
|
|
|
}
|
|
|
|
|
/* Will calculate edges later. */
|
|
|
|
|
Mesh *result = BKE_mesh_new_nomain_from_template(
|
2023-07-24 22:06:55 +02:00
|
|
|
mim.meshes[0], out_totvert, 0, out_faces_num, out_totloop);
|
2021-02-21 17:57:03 -05:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
merge_vertex_loop_face_customdata_layers(result, mim);
|
2021-02-21 17:57:03 -05:00
|
|
|
/* Set the vertex coordinate values and other 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
|
|
|
MutableSpan<float3> positions = result->vert_positions_for_write();
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int vi : im->vert_index_range()) {
|
|
|
|
|
const Vert *v = im->vert(vi);
|
|
|
|
|
if (v->orig != NO_INDEX) {
|
|
|
|
|
const Mesh *orig_me;
|
|
|
|
|
int index_in_orig_me;
|
Mesh: Move selection flags to generic attributes
Using the attribute name semantics from T97452, this patch moves the
selection status of mesh elements from the `SELECT` of vertices, and
edges, and the `ME_FACE_SEL` of faces to generic boolean attribute
Storing this data as generic attributes can significantly simplify and
improve code, as described in T95965.
The attributes are called `.select_vert`, `.select_edge`, and
`.select_poly`. 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.
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 selection is used. When the flags are removed
completely, requirements will decrease.
Further notes:
* The `MVert` flag is empty at runtime now, so it can be ignored.
* `BMesh` is unchanged, otherwise the change would be much larger.
* Many tests have slightly different results, since the selection
attribute uses more generic propagation. Previously you couldn't
really rely on edit mode selections being propagated procedurally.
Now it mostly works as expected.
Similar to 2480b55f216c
Ref T95965
Differential Revision: https://developer.blender.org/D15795
2022-09-23 09:38:37 -05:00
|
|
|
mim.input_mvert_for_orig_index(v->orig, &orig_me, &index_in_orig_me);
|
|
|
|
|
copy_vert_attributes(result, orig_me, vi, index_in_orig_me);
|
2021-02-21 17:57:03 -05: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
|
|
|
copy_v3fl_v3db(positions[vi], v->co);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
/* Set the loop-start and total-loops for each output face,
|
2021-02-21 17:57:03 -05:00
|
|
|
* and set the vertices in the appropriate loops. */
|
2022-08-31 09:09:01 -05:00
|
|
|
bke::SpanAttributeWriter<int> dst_material_indices =
|
2022-09-07 21:41:39 -05:00
|
|
|
result->attributes_for_write().lookup_or_add_for_write_only_span<int>("material_index",
|
|
|
|
|
ATTR_DOMAIN_FACE);
|
2021-02-21 17:57:03 -05:00
|
|
|
int cur_loop_index = 0;
|
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
|
|
|
MutableSpan<int> dst_corner_verts = result->corner_verts_for_write();
|
2023-07-24 22:06:55 +02:00
|
|
|
MutableSpan<int> dst_face_offsets = result->face_offsets_for_write();
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int fi : im->face_index_range()) {
|
|
|
|
|
const Face *f = im->face(fi);
|
|
|
|
|
const Mesh *orig_me;
|
|
|
|
|
int index_in_orig_me;
|
|
|
|
|
int orig_me_index;
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange orig_face = mim.input_face_for_orig_index(
|
2021-02-21 17:57:03 -05:00
|
|
|
f->orig, &orig_me, &orig_me_index, &index_in_orig_me);
|
2023-07-24 22:06:55 +02:00
|
|
|
dst_face_offsets[fi] = cur_loop_index;
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int j : f->index_range()) {
|
|
|
|
|
const Vert *vf = f->vert[j];
|
|
|
|
|
const int vfi = im->lookup_vert(vf);
|
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
|
|
|
dst_corner_verts[cur_loop_index] = vfi;
|
2021-02-21 17:57:03 -05:00
|
|
|
++cur_loop_index;
|
|
|
|
|
}
|
2021-03-14 11:39:56 -04:00
|
|
|
|
2023-07-24 22:06:55 +02:00
|
|
|
copy_face_attributes(result,
|
2021-04-02 00:16:01 -05:00
|
|
|
orig_me,
|
|
|
|
|
fi,
|
|
|
|
|
index_in_orig_me,
|
|
|
|
|
(mim.material_remaps.size() > 0) ?
|
|
|
|
|
mim.material_remaps[orig_me_index].as_span() :
|
2022-08-31 09:09:01 -05:00
|
|
|
Span<short>(),
|
|
|
|
|
dst_material_indices.span);
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
copy_or_interp_loop_attributes(result,
|
|
|
|
|
f,
|
2023-07-24 22:06:55 +02:00
|
|
|
IndexRange(dst_face_offsets[fi], f->size()),
|
|
|
|
|
orig_face,
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
orig_me,
|
|
|
|
|
orig_me_index,
|
|
|
|
|
mim);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
2022-08-31 09:09:01 -05:00
|
|
|
dst_material_indices.finish();
|
2021-02-21 17:57:03 -05:00
|
|
|
|
|
|
|
|
/* BKE_mesh_calc_edges will calculate and populate all the
|
|
|
|
|
* MEdges from the MPolys. */
|
|
|
|
|
BKE_mesh_calc_edges(result, false, false);
|
|
|
|
|
merge_edge_customdata_layers(result, mim);
|
|
|
|
|
|
|
|
|
|
/* Now that the MEdges are populated, we can copy over the required attributes and custom layers.
|
|
|
|
|
*/
|
2023-07-24 22:06:55 +02:00
|
|
|
const OffsetIndices dst_polys = result->faces();
|
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 Span<int> dst_corner_edges = result->corner_edges();
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int fi : im->face_index_range()) {
|
|
|
|
|
const Face *f = im->face(fi);
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange face = dst_polys[fi];
|
2021-02-21 17:57:03 -05:00
|
|
|
for (int j : f->index_range()) {
|
|
|
|
|
if (f->edge_orig[j] != NO_INDEX) {
|
|
|
|
|
const Mesh *orig_me;
|
|
|
|
|
int index_in_orig_me;
|
2023-03-01 14:13:05 +01:00
|
|
|
mim.input_medge_for_orig_index(f->edge_orig[j], &orig_me, &index_in_orig_me);
|
2023-07-24 22:06:55 +02:00
|
|
|
int e_index = dst_corner_edges[face[j]];
|
2023-03-01 14:13:05 +01:00
|
|
|
copy_edge_attributes(result, orig_me, e_index, index_in_orig_me);
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dbg_level > 0) {
|
|
|
|
|
BKE_mesh_validate(result, true, true);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
#endif // WITH_GMP
|
|
|
|
|
|
|
|
|
|
Mesh *direct_mesh_boolean(Span<const Mesh *> meshes,
|
2022-04-27 18:52:56 -05:00
|
|
|
Span<const float4x4 *> transforms,
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
const float4x4 &target_transform,
|
2021-04-02 00:16:01 -05:00
|
|
|
Span<Array<short>> material_remaps,
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
const bool use_self,
|
|
|
|
|
const bool hole_tolerant,
|
2022-04-04 12:26:50 +02:00
|
|
|
const int boolean_mode,
|
|
|
|
|
Vector<int> *r_intersecting_edges)
|
2021-02-21 17:57:03 -05:00
|
|
|
{
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
#ifdef WITH_GMP
|
2023-05-18 15:08:53 -04:00
|
|
|
BLI_assert(transforms.is_empty() || meshes.size() == transforms.size());
|
2021-04-02 00:16:01 -05:00
|
|
|
BLI_assert(material_remaps.size() == 0 || material_remaps.size() == meshes.size());
|
|
|
|
|
if (meshes.size() <= 0) {
|
2021-02-21 17:57:03 -05:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2021-04-02 00:16:01 -05:00
|
|
|
|
|
|
|
|
const int dbg_level = 0;
|
2021-02-21 17:57:03 -05:00
|
|
|
if (dbg_level > 0) {
|
2021-04-02 00:16:01 -05:00
|
|
|
std::cout << "\nDIRECT_MESH_INTERSECT, nmeshes = " << meshes.size() << "\n";
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
MeshesToIMeshInfo mim;
|
|
|
|
|
IMeshArena arena;
|
2022-04-27 18:52:56 -05:00
|
|
|
IMesh m_in = meshes_to_imesh(meshes, transforms, material_remaps, target_transform, arena, &mim);
|
2021-02-21 17:57:03 -05:00
|
|
|
std::function<int(int)> shape_fn = [&mim](int f) {
|
2023-07-24 22:06:55 +02:00
|
|
|
for (int mi = 0; mi < mim.mesh_face_offset.size() - 1; ++mi) {
|
|
|
|
|
if (f < mim.mesh_face_offset[mi + 1]) {
|
2021-02-21 17:57:03 -05:00
|
|
|
return mi;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-07-24 22:06:55 +02:00
|
|
|
return int(mim.mesh_face_offset.size()) - 1;
|
2021-02-21 17:57:03 -05:00
|
|
|
};
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
IMesh m_out = boolean_mesh(m_in,
|
|
|
|
|
static_cast<BoolOpType>(boolean_mode),
|
2021-04-02 00:16:01 -05:00
|
|
|
meshes.size(),
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
shape_fn,
|
|
|
|
|
use_self,
|
|
|
|
|
hole_tolerant,
|
|
|
|
|
nullptr,
|
|
|
|
|
&arena);
|
2021-04-02 00:16:01 -05:00
|
|
|
if (dbg_level > 0) {
|
2021-02-21 17:57:03 -05:00
|
|
|
std::cout << m_out;
|
|
|
|
|
write_obj_mesh(m_out, "m_out");
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-04 12:26:50 +02:00
|
|
|
Mesh *result = imesh_to_mesh(&m_out, mim);
|
|
|
|
|
|
|
|
|
|
/* Store intersecting edge indices. */
|
|
|
|
|
if (r_intersecting_edges != nullptr) {
|
2023-07-24 22:06:55 +02:00
|
|
|
const OffsetIndices faces = result->faces();
|
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 Span<int> corner_edges = result->corner_edges();
|
2022-04-04 12:26:50 +02:00
|
|
|
for (int fi : m_out.face_index_range()) {
|
|
|
|
|
const Face &face = *m_out.face(fi);
|
2023-07-24 22:06:55 +02:00
|
|
|
const IndexRange mesh_face = faces[fi];
|
Mesh: Replace MPoly struct with offset indices
Implements #95967.
Currently the `MPoly` struct is 12 bytes, and stores the index of a
face's first corner and the number of corners/verts/edges. Polygons
and corners are always created in order by Blender, meaning each
face's corners will be after the previous face's corners. We can take
advantage of this fact and eliminate the redundancy in mesh face
storage by only storing a single integer corner offset for each face.
The size of the face is then encoded by the offset of the next face.
The size of a single integer is 4 bytes, so this reduces memory
usage by 3 times.
The same method is used for `CurvesGeometry`, so Blender already has
an abstraction to simplify using these offsets called `OffsetIndices`.
This class is used to easily retrieve a range of corner indices for
each face. This also gives the opportunity for sharing some logic with
curves.
Another benefit of the change is that the offsets and sizes stored in
`MPoly` can no longer disagree with each other. Storing faces in the
order of their corners can simplify some code too.
Face/polygon variables now use the `IndexRange` type, which comes with
quite a few utilities that can simplify code.
Some:
- The offset integer array has to be one longer than the face count to
avoid a branch for every face, which means the data is no longer part
of the mesh's `CustomData`.
- We lose the ability to "reference" an original mesh's offset array
until more reusable CoW from #104478 is committed. That will be added
in a separate commit.
- Since they aren't part of `CustomData`, poly offsets often have to be
copied manually.
- To simplify using `OffsetIndices` in many places, some functions and
structs in headers were moved to only compile in C++.
- All meshes created by Blender use the same order for faces and face
corners, but just in case, meshes with mismatched order are fixed by
versioning code.
- `MeshPolygon.totloop` is no longer editable in RNA. This API break is
necessary here unfortunately. It should be worth it in 3.6, since
that's the best way to allow loading meshes from 4.0, which is
important for an LTS version.
Pull Request: https://projects.blender.org/blender/blender/pulls/105938
2023-04-04 20:39:28 +02:00
|
|
|
for (int i : face.index_range()) {
|
|
|
|
|
if (face.is_intersect[i]) {
|
2023-07-24 22:06:55 +02:00
|
|
|
int e_index = corner_edges[mesh_face[i]];
|
2022-04-04 12:26:50 +02:00
|
|
|
r_intersecting_edges->append(e_index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
#else // WITH_GMP
|
2022-04-27 18:52:56 -05:00
|
|
|
UNUSED_VARS(meshes,
|
|
|
|
|
transforms,
|
|
|
|
|
material_remaps,
|
|
|
|
|
target_transform,
|
|
|
|
|
use_self,
|
|
|
|
|
hole_tolerant,
|
2022-06-17 07:23:21 +10:00
|
|
|
boolean_mode,
|
|
|
|
|
r_intersecting_edges);
|
Geometry Nodes: Improve speed of boolean node, use multi-input socket
This commit improves the performance of the node by up to 40% in some
cases when there are only two input meshes, mainly by skipping the
conversion to and from BMesh.
When there are more than two input meshes (note the distinction from
"Geometries", a geometry set can have many mesh instances), the
performance is actually worse, since boolean currently always does
self intersection in that case. Theoretically this could be improved
in the boolean code, or another option is automatically realizing
instances for each input geometry set.
Another improvement is using multi-input sockets for the inputs, which
removes the need to have a separate boolean node for every operation,
which can hopefully simplify some node trees.
The changes necessary for transforms in `mesh_boolean_convert.cc` are
somewhat subtle; they come from the fact that the collecting the
geometry set instances already gives transforms in the local space
of the modifier object. There is also a very small amount of cleanup
to those lines, using `float4x4::identity()`.
This commit also fixes T87078, where overlapping difference meshes
makes the operation not work, though I haven't investigated why.
Differential Revision: https://developer.blender.org/D10599
2021-04-01 15:00:47 -05:00
|
|
|
return nullptr;
|
|
|
|
|
#endif // WITH_GMP
|
2021-02-21 17:57:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace blender::meshintersect
|