Mesh: Add API functions to assign vertex normals
A few places already calculated vertex normals with better contextual information to improve performance. To allow changing the storage of vertex normals more (mostly for improved caching), change some code from "get normals, set values, clear dirty flag" to "make vertex normals data, give to mesh". This makes the API less awkward too, since previously the "get for write" and "clear dirty" calls always had to be separated. Pull Request: https://projects.blender.org/blender/blender/pulls/110754
This commit is contained in:
@@ -321,25 +321,6 @@ void BKE_mesh_recalc_looptri(const int *corner_verts,
|
||||
*/
|
||||
const float (*BKE_mesh_vert_normals_ensure(const struct Mesh *mesh))[3];
|
||||
|
||||
/**
|
||||
* Retrieve write access to the cached vertex normals, ensuring that they are allocated but *not*
|
||||
* that they are calculated. The provided vertex normals should be the same as if they were
|
||||
* calculated automatically.
|
||||
*
|
||||
* \note In order to clear the dirty flag, this function should be followed by a call to
|
||||
* #BKE_mesh_vert_normals_clear_dirty. This is separate so that normals are still tagged dirty
|
||||
* while they are being assigned.
|
||||
*
|
||||
* \warning The memory returned by this function is not initialized if it was not previously
|
||||
* allocated.
|
||||
*/
|
||||
float (*BKE_mesh_vert_normals_for_write(struct Mesh *mesh))[3];
|
||||
|
||||
/**
|
||||
* Mark the mesh's vertex normals non-dirty, for when they are calculated or assigned manually.
|
||||
*/
|
||||
void BKE_mesh_vert_normals_clear_dirty(struct Mesh *mesh);
|
||||
|
||||
/**
|
||||
* Return true if the mesh vertex normals either are not stored or are dirty.
|
||||
* This can be used to help decide whether to transfer them when copying a mesh.
|
||||
|
||||
@@ -277,6 +277,12 @@ inline int edge_other_vert(const int2 &edge, const int vert)
|
||||
|
||||
void mesh_flip_faces(Mesh &mesh, const IndexMask &selection);
|
||||
|
||||
/** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */
|
||||
void mesh_vert_normals_assign(Mesh &mesh, Span<float3> vert_normals);
|
||||
|
||||
/** Set mesh vertex normals to known-correct values, avoiding future lazy computation. */
|
||||
void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals);
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -1488,10 +1488,7 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
|
||||
for (int i = 0; i < mesh->totvert; i++) {
|
||||
normalize_v3(process.no[i]);
|
||||
}
|
||||
memcpy(BKE_mesh_vert_normals_for_write(mesh),
|
||||
process.no.data(),
|
||||
sizeof(float[3]) * size_t(mesh->totvert));
|
||||
BKE_mesh_vert_normals_clear_dirty(mesh);
|
||||
blender::bke::mesh_vert_normals_assign(*mesh, std::move(process.no));
|
||||
|
||||
BKE_mesh_calc_edges(mesh, false, false);
|
||||
|
||||
|
||||
@@ -89,18 +89,23 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
|
||||
* Related to managing normals but not directly related to calculating normals.
|
||||
* \{ */
|
||||
|
||||
float (*BKE_mesh_vert_normals_for_write(Mesh *mesh))[3]
|
||||
namespace blender::bke {
|
||||
|
||||
void mesh_vert_normals_assign(Mesh &mesh, Span<float3> vert_normals)
|
||||
{
|
||||
mesh->runtime->vert_normals.reinitialize(mesh->totvert);
|
||||
return reinterpret_cast<float(*)[3]>(mesh->runtime->vert_normals.data());
|
||||
mesh.runtime->vert_normals.clear();
|
||||
mesh.runtime->vert_normals.extend(vert_normals);
|
||||
mesh.runtime->vert_normals_dirty = false;
|
||||
}
|
||||
|
||||
void BKE_mesh_vert_normals_clear_dirty(Mesh *mesh)
|
||||
void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals)
|
||||
{
|
||||
mesh->runtime->vert_normals_dirty = false;
|
||||
BLI_assert(mesh->runtime->vert_normals.size() == mesh->totvert);
|
||||
mesh.runtime->vert_normals = std::move(vert_normals);
|
||||
mesh.runtime->vert_normals_dirty = false;
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
bool BKE_mesh_vert_normals_are_dirty(const Mesh *mesh)
|
||||
{
|
||||
return mesh->runtime->vert_normals_dirty;
|
||||
|
||||
@@ -174,12 +174,12 @@ void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySa
|
||||
BKE_mesh_tag_positions_changed(&mesh);
|
||||
|
||||
if (normals) {
|
||||
float(*vert_normals)[3] = BKE_mesh_vert_normals_for_write(&mesh);
|
||||
Vector<float3> vert_normals(mesh.totvert);
|
||||
for (const int64_t i : IndexRange(normals->size())) {
|
||||
Imath::V3f nor_in = (*normals)[i];
|
||||
copy_zup_from_yup(vert_normals[i], nor_in.getValue());
|
||||
}
|
||||
BKE_mesh_vert_normals_clear_dirty(&mesh);
|
||||
bke::mesh_vert_normals_assign(mesh, std::move(vert_normals));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -656,10 +656,9 @@ void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
|
||||
return;
|
||||
}
|
||||
|
||||
MutableSpan vert_normals{(float3 *)BKE_mesh_vert_normals_for_write(mesh), mesh->totvert};
|
||||
BLI_STATIC_ASSERT(sizeof(normals_[0]) == sizeof(float3), "Expected float3 normals size");
|
||||
vert_normals.copy_from({(float3 *)normals_.data(), int64_t(normals_.size())});
|
||||
BKE_mesh_vert_normals_clear_dirty(mesh);
|
||||
bke::mesh_vert_normals_assign(
|
||||
*mesh, Span(reinterpret_cast<const float3 *>(normals_.data()), int64_t(normals_.size())));
|
||||
}
|
||||
|
||||
void USDMeshReader::process_normals_face_varying(Mesh *mesh)
|
||||
|
||||
@@ -282,7 +282,7 @@ static void mesh_merge_transform(Mesh *result,
|
||||
int cap_nfaces,
|
||||
int *remap,
|
||||
int remap_len,
|
||||
const bool recalc_normals_later)
|
||||
MutableSpan<float3> dst_vert_normals)
|
||||
{
|
||||
using namespace blender;
|
||||
int *index_orig;
|
||||
@@ -305,8 +305,7 @@ static void mesh_merge_transform(Mesh *result,
|
||||
}
|
||||
|
||||
/* We have to correct normals too, if we do not tag them as dirty later! */
|
||||
if (!recalc_normals_later) {
|
||||
float(*dst_vert_normals)[3] = BKE_mesh_vert_normals_for_write(result);
|
||||
if (!dst_vert_normals.is_empty()) {
|
||||
for (i = 0; i < cap_nverts; i++) {
|
||||
mul_mat3_m4_v3(cap_offset, dst_vert_normals[cap_verts_index + i]);
|
||||
normalize_v3(dst_vert_normals[cap_verts_index + i]);
|
||||
@@ -583,11 +582,10 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
|
||||
unit_m4(current_offset);
|
||||
blender::Span<blender::float3> src_vert_normals;
|
||||
float(*dst_vert_normals)[3] = nullptr;
|
||||
Vector<float3> dst_vert_normals;
|
||||
if (!use_recalc_normals) {
|
||||
src_vert_normals = mesh->vert_normals();
|
||||
dst_vert_normals = BKE_mesh_vert_normals_for_write(result);
|
||||
BKE_mesh_vert_normals_clear_dirty(result);
|
||||
dst_vert_normals.reinitialize(result->totvert);
|
||||
}
|
||||
|
||||
for (c = 1; c < count; c++) {
|
||||
@@ -608,7 +606,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
mul_m4_v3(current_offset, result_positions[i_dst]);
|
||||
|
||||
/* We have to correct normals too, if we do not tag them as dirty! */
|
||||
if (!use_recalc_normals) {
|
||||
if (!dst_vert_normals.is_empty()) {
|
||||
copy_v3_v3(dst_vert_normals[i_dst], src_vert_normals[i]);
|
||||
mul_mat3_m4_v3(current_offset, dst_vert_normals[i_dst]);
|
||||
normalize_v3(dst_vert_normals[i_dst]);
|
||||
@@ -758,7 +756,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
start_cap_nfaces,
|
||||
vgroup_start_cap_remap,
|
||||
vgroup_start_cap_remap_len,
|
||||
use_recalc_normals);
|
||||
dst_vert_normals);
|
||||
/* Identify doubles with first chunk */
|
||||
if (use_merge) {
|
||||
dm_mvert_map_doubles(full_doubles_map,
|
||||
@@ -788,7 +786,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
end_cap_nfaces,
|
||||
vgroup_end_cap_remap,
|
||||
vgroup_end_cap_remap_len,
|
||||
use_recalc_normals);
|
||||
dst_vert_normals);
|
||||
/* Identify doubles with last chunk */
|
||||
if (use_merge) {
|
||||
dm_mvert_map_doubles(full_doubles_map,
|
||||
@@ -802,6 +800,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
}
|
||||
/* done capping */
|
||||
|
||||
blender::bke::mesh_vert_normals_assign(*result, std::move(dst_vert_normals));
|
||||
|
||||
/* Handle merging */
|
||||
tot_doubles = 0;
|
||||
if (use_merge) {
|
||||
|
||||
@@ -318,10 +318,9 @@ static Mesh *create_uv_sphere_mesh(const float radius,
|
||||
threading::parallel_invoke(
|
||||
1024 < segments * rings,
|
||||
[&]() {
|
||||
MutableSpan vert_normals{reinterpret_cast<float3 *>(BKE_mesh_vert_normals_for_write(mesh)),
|
||||
mesh->totvert};
|
||||
Vector<float3> vert_normals(mesh->totvert);
|
||||
calculate_sphere_vertex_data(positions, vert_normals, radius, segments, rings);
|
||||
BKE_mesh_vert_normals_clear_dirty(mesh);
|
||||
bke::mesh_vert_normals_assign(*mesh, std::move(vert_normals));
|
||||
},
|
||||
[&]() { calculate_sphere_edge_indices(edges, segments, rings); },
|
||||
[&]() { calculate_sphere_faces(face_offsets, segments); },
|
||||
|
||||
Reference in New Issue
Block a user