Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorHans Goudey <h.goudey@me.com>2022-02-22 20:47:05 +0300
committerHans Goudey <h.goudey@me.com>2022-02-22 20:47:05 +0300
commitc7a9f76149d85dfb64710722a45979f6decedbb1 (patch)
treef4d763e7a41bb9f8f2baab0e8708ac6f9c55c39b /source
parentf3d97498c3a6afcffbe3c8551fec32efb246a4f1 (diff)
parent59343ee1627f4c369e237cea201015b979da1540 (diff)
Merge branch 'blender-v3.1-release'
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_mesh.h11
-rw-r--r--source/blender/blenkernel/intern/customdata.cc10
-rw-r--r--source/blender/blenkernel/intern/mesh.cc21
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc11
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc67
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c6
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.cc4
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h4
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc4
10 files changed, 95 insertions, 56 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index aa56fb7d1da..5628992d415 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -419,6 +419,17 @@ float (*BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3];
float (*BKE_mesh_poly_normals_for_write(struct Mesh *mesh))[3];
/**
+ * Free any cached vertex or poly normals. Face corner (loop) normals are also derived data,
+ * but are not handled with the same method yet, so they are not included. It's important that this
+ * is called after the mesh changes size, since otherwise cached normal arrays might not be large
+ * enough (though it may be called indirectly by other functions).
+ *
+ * \note Normally it's preferred to call #BKE_mesh_normals_tag_dirty instead,
+ * but this can be used in specific situations to reset a mesh or reduce memory usage.
+ */
+void BKE_mesh_clear_derived_normals(struct Mesh *mesh);
+
+/**
* Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually.
*/
void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh);
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 867bdcd06bd..587c0b73dff 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -1959,10 +1959,10 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
};
const CustomData_MeshMasks CD_MASK_EVERYTHING = {
- /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL |
- CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO |
- CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX |
- CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
+ /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT |
+ CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO |
+ CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK |
+ CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR | CD_MASK_CREASE),
/* emask */
(CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE |
CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
@@ -1971,7 +1971,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL |
CD_MASK_PROP_ALL),
/* pmask */
- (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP |
+ (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FACEMAP |
CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
/* lmask */
(CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 8c5be7291ca..83619cb50ef 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -59,6 +59,8 @@
#include "BLO_read_write.h"
+using blender::float3;
+
static void mesh_clear_geometry(Mesh *mesh);
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
@@ -1106,16 +1108,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
mesh_tessface_clear_intern(me_dst, false);
}
- me_dst->runtime.cd_dirty_poly = me_src->runtime.cd_dirty_poly;
- me_dst->runtime.cd_dirty_vert = me_src->runtime.cd_dirty_vert;
-
- /* Ensure that when no normal layers exist, they are marked dirty, because
- * normals might not have been included in the mask of copied layers. */
- if (!CustomData_has_layer(&me_dst->vdata, CD_NORMAL) ||
- !CustomData_has_layer(&me_dst->pdata, CD_NORMAL)) {
- BKE_mesh_normals_tag_dirty(me_dst);
- }
-
/* The destination mesh should at least have valid primary CD layers,
* even in cases where the source mesh does not. */
mesh_ensure_cdlayers_primary(me_dst, do_tessface);
@@ -2162,6 +2154,10 @@ static void split_faces_split_new_verts(Mesh *mesh,
MVert *mvert = mesh->mvert;
float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
+ /* Normals were already calculated at the beginning of this operation, we rely on that to update
+ * them partially here. */
+ BLI_assert(!BKE_mesh_vertex_normals_are_dirty(mesh));
+
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
for (int i = mesh->totvert - 1; i >= verts_len; i--, new_mv--, new_verts = new_verts->next) {
@@ -2172,7 +2168,6 @@ static void split_faces_split_new_verts(Mesh *mesh,
copy_v3_v3(vert_normals[i], new_verts->vnor);
}
}
- BKE_mesh_vertex_normals_clear_dirty(mesh);
}
/* Perform actual split of edges. */
@@ -2243,6 +2238,10 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Update pointers to a newly allocated memory. */
BKE_mesh_update_customdata_pointers(mesh, false);
+ /* Update normals manually to avoid recalculation after this operation. */
+ mesh->runtime.vert_normals = (float(*)[3])MEM_reallocN(mesh->runtime.vert_normals,
+ sizeof(float[3]) * mesh->totvert);
+
/* Perform actual split of vertices and edges. */
split_faces_split_new_verts(mesh, new_verts, num_new_verts);
if (do_edges) {
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 648f0008c19..5af599f0302 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -1481,15 +1481,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
tmp.cd_flag = mesh_src->cd_flag;
tmp.runtime.deformed_only = mesh_src->runtime.deformed_only;
- tmp.runtime.cd_dirty_poly = mesh_src->runtime.cd_dirty_poly;
- tmp.runtime.cd_dirty_vert = mesh_src->runtime.cd_dirty_vert;
-
- /* Ensure that when no normal layers exist, they are marked dirty, because
- * normals might not have been included in the mask of copied layers. */
- if (!CustomData_has_layer(&tmp.vdata, CD_NORMAL) ||
- !CustomData_has_layer(&tmp.pdata, CD_NORMAL)) {
- BKE_mesh_normals_tag_dirty(&tmp);
- }
+ /* Clear the normals completely, since the new vertex / polygon count might be different. */
+ BKE_mesh_clear_derived_normals(&tmp);
if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
KeyBlock *kb;
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 3d801b301f9..89aa1dbfa94 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -94,53 +94,72 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
{
- mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ mesh->runtime.vert_normals_dirty = true;
+ mesh->runtime.poly_normals_dirty = true;
}
float (*BKE_mesh_vertex_normals_for_write(Mesh *mesh))[3]
{
- CustomData_duplicate_referenced_layer(&mesh->vdata, CD_NORMAL, mesh->totvert);
- return (float(*)[3])CustomData_add_layer(
- &mesh->vdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totvert);
+ if (mesh->runtime.vert_normals == nullptr) {
+ mesh->runtime.vert_normals = (float(*)[3])MEM_malloc_arrayN(
+ mesh->totvert, sizeof(float[3]), __func__);
+ }
+
+ BLI_assert(MEM_allocN_len(mesh->runtime.vert_normals) >= sizeof(float[3]) * mesh->totvert);
+
+ return mesh->runtime.vert_normals;
}
float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3]
{
- CustomData_duplicate_referenced_layer(&mesh->pdata, CD_NORMAL, mesh->totpoly);
- return (float(*)[3])CustomData_add_layer(
- &mesh->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totpoly);
+ if (mesh->runtime.poly_normals == nullptr) {
+ mesh->runtime.poly_normals = (float(*)[3])MEM_malloc_arrayN(
+ mesh->totpoly, sizeof(float[3]), __func__);
+ }
+
+ BLI_assert(MEM_allocN_len(mesh->runtime.poly_normals) >= sizeof(float[3]) * mesh->totpoly);
+
+ return mesh->runtime.poly_normals;
}
void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ mesh->runtime.vert_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh)
{
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
+ mesh->runtime.poly_normals_dirty = false;
BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
bool BKE_mesh_vertex_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL;
+ return mesh->runtime.vert_normals_dirty;
}
bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
{
- return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL;
+ return mesh->runtime.poly_normals_dirty;
+}
+
+void BKE_mesh_clear_derived_normals(Mesh *mesh)
+{
+ MEM_SAFE_FREE(mesh->runtime.vert_normals);
+ MEM_SAFE_FREE(mesh->runtime.poly_normals);
+
+ mesh->runtime.vert_normals_dirty = true;
+ mesh->runtime.poly_normals_dirty = true;
}
void BKE_mesh_assert_normals_dirty_or_calculated(const Mesh *mesh)
{
- if (!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL)) {
- BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
+ if (!mesh->runtime.vert_normals_dirty) {
+ BLI_assert(mesh->runtime.vert_normals || mesh->totvert == 0);
}
- if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL)) {
- BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ if (!mesh->runtime.poly_normals_dirty) {
+ BLI_assert(mesh->runtime.poly_normals || mesh->totpoly == 0);
}
}
@@ -342,8 +361,8 @@ static void mesh_calc_normals_poly_and_vertex(MVert *mvert,
const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
- BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL) || mesh->totvert == 0);
- return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
+ BLI_assert(mesh->runtime.vert_normals != nullptr || mesh->totvert == 0);
+ return mesh->runtime.vert_normals;
}
if (mesh->totvert == 0) {
@@ -353,9 +372,9 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
BLI_mutex_lock(normals_mutex);
if (!(BKE_mesh_vertex_normals_are_dirty(mesh) || BKE_mesh_poly_normals_are_dirty(mesh))) {
- BLI_assert(CustomData_has_layer(&mesh->vdata, CD_NORMAL));
+ BLI_assert(mesh->runtime.vert_normals != nullptr);
BLI_mutex_unlock(normals_mutex);
- return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
+ return mesh->runtime.vert_normals;
}
float(*vert_normals)[3];
@@ -388,8 +407,8 @@ const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
{
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
- return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ BLI_assert(mesh->runtime.poly_normals != nullptr || mesh->totpoly == 0);
+ return mesh->runtime.poly_normals;
}
if (mesh->totpoly == 0) {
@@ -399,9 +418,9 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
ThreadMutex *normals_mutex = (ThreadMutex *)mesh->runtime.normals_mutex;
BLI_mutex_lock(normals_mutex);
if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
- BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL));
+ BLI_assert(mesh->runtime.poly_normals != nullptr);
BLI_mutex_unlock(normals_mutex);
- return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ return mesh->runtime.poly_normals;
}
float(*poly_normals)[3];
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 204441d5326..7bd52abeb0d 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -88,6 +88,11 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag))
runtime->bvh_cache = NULL;
runtime->shrinkwrap_data = NULL;
+ runtime->vert_normals_dirty = true;
+ runtime->poly_normals_dirty = true;
+ runtime->vert_normals = NULL;
+ runtime->poly_normals = NULL;
+
mesh_runtime_init_mutexes(mesh);
}
@@ -101,6 +106,7 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
BKE_mesh_runtime_clear_geometry(mesh);
BKE_mesh_batch_cache_free(mesh);
BKE_mesh_runtime_clear_edit_data(mesh);
+ BKE_mesh_clear_derived_normals(mesh);
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
index d5a5c08752d..700570d28a4 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc
@@ -1186,7 +1186,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
- BKE_mesh_normals_tag_dirty(me);
+ /* Clear normals on the mesh completely, since the original vertex and polygon count might be
+ * different than the BMesh's. */
+ BKE_mesh_clear_derived_normals(me);
me->runtime.deformed_only = true;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 23406033126..2f9f63cb966 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -98,6 +98,10 @@ typedef enum CustomDataType {
CD_MTFACE = 5,
CD_MCOL = 6,
CD_ORIGINDEX = 7,
+ /**
+ * Used for derived face corner normals on mesh `ldata`, since currently they are not computed
+ * lazily. Derived vertex and polygon normals are stored in #Mesh_Runtime.
+ */
CD_NORMAL = 8,
CD_FACEMAP = 9, /* exclusive face group, each face can only be part of one */
CD_PROP_FLOAT = 10,
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index c566ad93335..f40e91c1d5e 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -116,14 +116,23 @@ typedef struct Mesh_Runtime {
*/
char wrapper_type_finalize;
+ int subsurf_resolution;
/**
* Settings for lazily evaluating the subdivision on the CPU if needed. These are
* set in the modifier when GPU subdivision can be performed.
*/
char subsurf_apply_render;
char subsurf_use_optimal_display;
- char _pad[2];
- int subsurf_resolution;
+
+ /**
+ * Caches for lazily computed vertex and polygon normals. These are stored here rather than in
+ * #CustomData because they can be calculated on a const mesh, and adding custom data layers on a
+ * const mesh is not thread-safe.
+ */
+ char vert_normals_dirty;
+ char poly_normals_dirty;
+ float (*vert_normals)[3];
+ float (*poly_normals)[3];
void *_pad2;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
index 5aeeb72961d..82584f6f413 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc
@@ -302,7 +302,6 @@ static void extrude_mesh_vertices(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
static Array<Vector<int, 2>> mesh_calculate_polys_of_edge(const Mesh &mesh)
@@ -626,7 +625,6 @@ static void extrude_mesh_edges(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
/**
@@ -995,7 +993,6 @@ static void extrude_mesh_face_regions(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
/* Get the range into an array of extruded corners, edges, or vertices for a particular polygon. */
@@ -1263,7 +1260,6 @@ static void extrude_individual_mesh_faces(MeshComponent &component,
}
BKE_mesh_runtime_clear_cache(&mesh);
- BKE_mesh_normals_tag_dirty(&mesh);
}
static void node_geo_exec(GeoNodeExecParams params)