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-01-13 23:37:58 +0300
committerHans Goudey <h.goudey@me.com>2022-01-13 23:38:25 +0300
commitcfa53e0fbeed7178c7876413e2010fd3347d7f72 (patch)
treef5cdc39134a3477614ae98699f90da3722161ed0 /source
parent800fc17367480b82e07570d5234726aa61c38563 (diff)
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a contiguous array of float vectors in a custom data layer, how face normals are currently stored. The main interface is documented in `BKE_mesh.h`. Vertex and face normals are now calculated on-demand and cached, retrieved with an "ensure" function. Since the logical state of a mesh is now "has normals when necessary", they can be retrieved from a `const` mesh. The goal is to use on-demand calculation for all derived data, but leave room for eager calculation for performance purposes (modifier evaluation is threaded, but viewport data generation is not). **Benefits** This moves us closer to a SoA approach rather than the current AoS paradigm. Accessing a contiguous `float3` is much more efficient than retrieving data from a larger struct. The memory requirements for accessing only normals or vertex locations are smaller, and at the cost of more memory usage for just normals, they now don't have to be converted between float and short, which also simplifies code In the future, the remaining items can be removed from `MVert`, leaving only `float3`, which has similar benefits (see T93602). Removing the combination of derived and original data makes it conceptually simpler to only calculate normals when necessary. This is especially important now that we have more opportunities for temporary meshes in geometry nodes. **Performance** In addition to the theoretical future performance improvements by making `MVert == float3`, I've done some basic performance testing on this patch directly. The data is fairly rough, but it gives an idea about where things stand generally. - Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms), showing that accessing just `MVert` is now more efficient. - Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight change that at least shows there is no regression. - Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small but observable speedup. - Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms), shows that using normals in geometry nodes is faster. - Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms), shows that calculating normals is slightly faster now. - File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB), Normals are not saved in files, which can help with large meshes. As for memory usage, it may be slightly more in some cases, but I didn't observe any difference in the production files I tested. **Tests** Some modifiers and cycles test results need to be updated with this commit, for two reasons: - The subdivision surface modifier is not responsible for calculating normals anymore. In master, the modifier creates different normals than the result of the `Mesh` normal calculation, so this is a bug fix. - There are small differences in the results of some modifiers that use normals because they are not converted to and from `short` anymore. **Future improvements** - Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier already retrieves normals if they are needed anyway. - Copy normals as part of a better CoW system for attributes. - Make more areas use lazy instead of eager normal calculation. - Remove `BKE_mesh_normals_tag_dirty` in more places since that is now the default state of a new mesh. - Possibly apply a similar change to derived face corner normals. Differential Revision: https://developer.blender.org/D12770
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_bvhutils.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h100
-rw-r--r--source/blender/blenkernel/BKE_mesh_iterators.h13
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h7
-rw-r--r--source/blender/blenkernel/BKE_mesh_tangent.h1
-rw-r--r--source/blender/blenkernel/BKE_paint.h1
-rw-r--r--source/blender/blenkernel/BKE_particle.h1
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h8
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h2
-rw-r--r--source/blender/blenkernel/BKE_subdiv_eval.h11
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc64
-rw-r--r--source/blender/blenkernel/intern/bvhutils.cc2
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c4
-rw-r--r--source/blender/blenkernel/intern/cloth.c3
-rw-r--r--source/blender/blenkernel/intern/constraint.c6
-rw-r--r--source/blender/blenkernel/intern/customdata.cc26
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c31
-rw-r--r--source/blender/blenkernel/intern/displist.cc6
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c26
-rw-r--r--source/blender/blenkernel/intern/editmesh.c3
-rw-r--r--source/blender/blenkernel/intern/effect.c4
-rw-r--r--source/blender/blenkernel/intern/fluid.c67
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc119
-rw-r--r--source/blender/blenkernel/intern/gpencil_geom.cc8
-rw-r--r--source/blender/blenkernel/intern/key.c13
-rw-r--r--source/blender/blenkernel/intern/mesh.cc85
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc33
-rw-r--r--source/blender/blenkernel/intern/mesh_iterators.c50
-rw-r--r--source/blender/blenkernel/intern/mesh_mirror.c14
-rw-r--r--source/blender/blenkernel/intern/mesh_normals.cc242
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c66
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.c7
-rw-r--r--source/blender/blenkernel/intern/mesh_tangent.c11
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c20
-rw-r--r--source/blender/blenkernel/intern/modifier.c5
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc11
-rw-r--r--source/blender/blenkernel/intern/object_update.c5
-rw-r--r--source/blender/blenkernel/intern/particle.c19
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c3
-rw-r--r--source/blender/blenkernel/intern/pbvh.c25
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h3
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c48
-rw-r--r--source/blender/blenkernel/intern/subdiv_eval.c45
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.c102
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c64
-rw-r--r--source/blender/blenlib/BLI_math_vector.h1
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c7
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c15
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h5
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_convert.c21
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_render_data.c5
-rw-r--r--source/blender/draw/intern/draw_cache_impl_subdivision.cc2
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh.h3
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc5
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc4
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc18
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc1
-rw-r--r--source/blender/editors/armature/meshlaplacian.c3
-rw-r--r--source/blender/editors/mesh/mesh_data.c9
-rw-r--r--source/blender/editors/mesh/meshtools.c3
-rw-r--r--source/blender/editors/object/object_remesh.cc2
-rw-r--r--source/blender/editors/physics/particle_edit.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c19
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c30
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_proj.c26
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c36
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_boundary.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_types.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c9
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c6
-rw-r--r--source/blender/editors/transform/transform_snap_object.c4
-rw-r--r--source/blender/editors/util/ed_transverts.c6
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp12
-rw-r--r--source/blender/gpu/GPU_buffers.h1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c3
-rw-r--r--source/blender/io/alembic/exporter/abc_writer_hair.cc33
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.cc20
-rw-r--r--source/blender/io/alembic/intern/abc_reader_mesh.h2
-rw-r--r--source/blender/io/alembic/intern/abc_reader_points.cc2
-rw-r--r--source/blender/io/collada/GeometryExporter.cpp3
-rw-r--r--source/blender/io/usd/intern/usd_reader_mesh.cc27
-rw-r--r--source/blender/io/usd/intern/usd_writer_mesh.cc10
-rw-r--r--source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h24
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h6
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c22
-rw-r--r--source/blender/modifiers/intern/MOD_array.c40
-rw-r--r--source/blender/modifiers/intern/MOD_build.c4
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c9
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c2
-rw-r--r--source/blender/modifiers/intern/MOD_mask.cc10
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c47
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c2
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c6
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c57
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c10
-rw-r--r--source/blender/modifiers/intern/MOD_util.c4
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c8
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c27
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc15
-rw-r--r--source/blender/render/intern/bake.c13
-rw-r--r--source/blender/render/intern/multires_bake.c6
-rw-r--r--source/blender/render/intern/texture_pointdensity.c17
114 files changed, 927 insertions, 1230 deletions
diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h
index 146e6394fd6..c454e441551 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -71,6 +71,7 @@ typedef struct BVHTreeFromMesh {
/* Vertex array, so that callbacks have instant access to data. */
const struct MVert *vert;
+ const float (*vert_normals)[3];
const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */
const struct MFace *face;
const struct MLoop *loop;
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 5f3fcb535b2..a9a78bbc12e 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -322,7 +322,6 @@ void BKE_mesh_vert_coords_apply_with_mat4(struct Mesh *mesh,
const float (*vert_coords)[3],
const float mat[4][4]);
void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3]);
-void BKE_mesh_vert_normals_apply(struct Mesh *mesh, const short (*vert_normals)[3]);
/* *** mesh_tessellate.c *** */
@@ -374,7 +373,83 @@ void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop,
/* *** mesh_normals.cc *** */
+/**
+ * Returns the normals for each vertex, which is defined as the weighted average of the normals
+ * from a vertices surrounding faces, or the normalized position of vertices connected to no faces.
+ * \warning May still return null if the mesh is empty.
+ */
+const float (*BKE_mesh_vertex_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Return the normal direction of every polygon, which is defined by the winding direction of its
+ * corners.
+ * \warning May still return null if the mesh is empty or has no polygons.
+ */
+const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
+
+/**
+ * Tag mesh vertex and face normals to be recalculated when/if they are needed later.
+ *
+ * \note Dirty tagged normals are the default state of a new mesh, so tagging them
+ * dirty explicitly is not always necessary if the mesh is created locally.
+ */
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh);
+
+/**
+ * Check that a mesh with non-dirty normals has vertex and face custom data layers.
+ * If these asserts fail, it means some area cleared the dirty flag but didn't copy or add the
+ * normal layers, or removed normals but didn't set the dirty flag.
+ */
+void BKE_mesh_assert_normals_dirty_or_calculated(const struct Mesh *mesh);
+
+/**
+ * Retrieve write access to the vertex normal layer, ensuring that it exists and that it is not
+ * shared. 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_vertex_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3];
+
+/**
+ * Retrieve write access to the poly normal layer, ensuring that it exists and that it is not
+ * shared. The provided poly 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_poly_normals_clear_dirty. This is separate so that normals are still tagged dirty
+ * while they are being assigned.
+ */
+float (*BKE_mesh_poly_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_vertex_normals_clear_dirty(struct Mesh *mesh);
+
+/**
+ * Mark the mesh's poly normals non-dirty, for when they are calculated or assigned manually.
+ */
+void BKE_mesh_poly_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.
+ */
+bool BKE_mesh_vertex_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Return true if the mesh polygon normals either are not stored or are dirty.
+ * This can be used to help decide whether to transfer them when copying a mesh.
+ */
+bool BKE_mesh_poly_normals_are_dirty(const struct Mesh *mesh);
+
+/**
+ * Calculate face normals directly into a result array.
+ *
+ * \note Usually #BKE_mesh_poly_normals_ensure is the preferred way to access face normals,
+ * since they may already be calculated and cached on the mesh.
+ */
void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
int mvert_len,
const struct MLoop *mloop,
@@ -382,20 +457,16 @@ void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
const struct MPoly *mpoly,
int mpoly_len,
float (*r_poly_normals)[3]);
-void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
- int mvert_len,
- const struct MLoop *mloop,
- int mloop_len,
- const struct MPoly *mpolys,
- int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3]);
-/**
- * \note this does not update the #CD_NORMAL layer,
- * but does update the normals in the #CD_MVERT layer.
+
+/**
+ * Calculate vertex and face normals, storing the result in custom data layers on the mesh.
+ *
+ * \note It is usually preferrable to calculate normals lazily with
+ * #BKE_mesh_vertex_normals_ensure, but some areas (perhaps unnecessarily)
+ * can also calculate them eagerly.
*/
void BKE_mesh_calc_normals(struct Mesh *me);
-void BKE_mesh_ensure_normals(struct Mesh *me);
+
/**
* Called after calculating all modifiers.
*/
@@ -544,6 +615,7 @@ void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space,
* (splitting edges).
*/
void BKE_mesh_normals_loop_split(const struct MVert *mverts,
+ const float (*vert_normals)[3],
int numVerts,
struct MEdge *medges,
int numEdges,
@@ -560,6 +632,7 @@ void BKE_mesh_normals_loop_split(const struct MVert *mverts,
int *r_loop_to_poly);
void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts,
+ const float (*vert_normals)[3],
int numVerts,
struct MEdge *medges,
int numEdges,
@@ -571,6 +644,7 @@ void BKE_mesh_normals_loop_custom_set(const struct MVert *mverts,
int numPolys,
short (*r_clnors_data)[2]);
void BKE_mesh_normals_loop_custom_from_vertices_set(const struct MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
int numVerts,
struct MEdge *medges,
diff --git a/source/blender/blenkernel/BKE_mesh_iterators.h b/source/blender/blenkernel/BKE_mesh_iterators.h
index d20849557c1..b28465fc41e 100644
--- a/source/blender/blenkernel/BKE_mesh_iterators.h
+++ b/source/blender/blenkernel/BKE_mesh_iterators.h
@@ -31,14 +31,11 @@ typedef enum MeshForeachFlag {
MESH_FOREACH_USE_NORMAL = (1 << 0),
} MeshForeachFlag;
-void BKE_mesh_foreach_mapped_vert(struct Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag);
+void BKE_mesh_foreach_mapped_vert(
+ struct Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag);
/**
* Copied from #cdDM_foreachMappedEdge.
* \param tot_edges: Number of original edges. Used to avoid calling the callback with invalid
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index 84abeac0d13..ab07cb0df4e 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -210,6 +210,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(int mode,
const struct SpaceTransform *space_transform,
float max_dist,
float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
int numverts_dst,
struct MEdge *edges_dst,
@@ -219,7 +220,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(int mode,
struct MPoly *polys_dst,
int numpolys_dst,
struct CustomData *ldata_dst,
- struct CustomData *pdata_dst,
bool use_split_nors_dst,
float split_angle_dst,
bool dirty_nors_dst,
@@ -232,14 +232,11 @@ void BKE_mesh_remap_calc_polys_from_mesh(int mode,
const struct SpaceTransform *space_transform,
float max_dist,
float ray_radius,
+ struct Mesh *mesh_dst,
struct MVert *verts_dst,
- int numverts_dst,
struct MLoop *loops_dst,
- int numloops_dst,
struct MPoly *polys_dst,
int numpolys_dst,
- struct CustomData *pdata_dst,
- bool dirty_nors_dst,
struct Mesh *me_src,
struct MeshPairRemap *r_map);
diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h
index 8a7562ea3fb..320c4e7f36a 100644
--- a/source/blender/blenkernel/BKE_mesh_tangent.h
+++ b/source/blender/blenkernel/BKE_mesh_tangent.h
@@ -66,6 +66,7 @@ void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
bool calc_active_tangent,
const char (*tangent_names)[64],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index acae80b7a2b..89e794cd2fc 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -499,6 +499,7 @@ typedef struct SculptSession {
/* These are always assigned to base mesh data when using PBVH_FACES and PBVH_GRIDS. */
struct MVert *mvert;
+ const float (*vert_normals)[3];
struct MPoly *mpoly;
struct MLoop *mloop;
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 1e71e158c10..804331a3412 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -597,6 +597,7 @@ void psys_get_texture(struct ParticleSimulationData *sim,
* Interpolate a location on a face based on face coordinates.
*/
void psys_interpolate_face(struct MVert *mvert,
+ const float (*vert_normals)[3],
struct MFace *mface,
struct MTFace *tface,
float (*orcodata)[3],
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 692c935ae5f..1ef1c98ce83 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -110,7 +110,7 @@ PBVH *BKE_pbvh_new(void);
* (which means it may rewrite it if needed, see #BKE_pbvh_vert_coords_apply().
*/
void BKE_pbvh_build_mesh(PBVH *pbvh,
- const struct Mesh *mesh,
+ struct Mesh *mesh,
const struct MPoly *mpoly,
const struct MLoop *mloop,
struct MVert *verts,
@@ -397,6 +397,7 @@ typedef struct PBVHVertexIter {
/* mesh */
struct MVert *mverts;
+ float (*vert_normals)[3];
int totvert;
const int *vert_indices;
struct MPropCol *vcol;
@@ -413,7 +414,7 @@ typedef struct PBVHVertexIter {
struct MVert *mvert;
struct BMVert *bm_vert;
float *co;
- short *no;
+ float *no;
float *fno;
float *mask;
float *col;
@@ -467,7 +468,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
BLI_assert(vi.visible); \
} \
vi.co = vi.mvert->co; \
- vi.no = vi.mvert->no; \
+ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \
vi.index = vi.vert_indices[vi.i]; \
if (vi.vmask) { \
vi.mask = &vi.vmask[vi.index]; \
@@ -533,6 +534,7 @@ void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings,
int totnode);
struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh);
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 55940d6ba57..510d6773f6d 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -88,7 +88,7 @@ typedef struct ShrinkwrapTreeData {
BVHTree *bvh;
BVHTreeFromMesh treeData;
- float (*pnors)[3];
+ const float (*pnors)[3];
float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;
diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h
index 052d25693c4..eeb80898148 100644
--- a/source/blender/blenkernel/BKE_subdiv_eval.h
+++ b/source/blender/blenkernel/BKE_subdiv_eval.h
@@ -75,8 +75,6 @@ void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv,
float r_dPdv[3]);
void BKE_subdiv_eval_limit_point_and_normal(
struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]);
-void BKE_subdiv_eval_limit_point_and_short_normal(
- struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], short r_N[3]);
/* Evaluate face-varying layer (such as UV). */
void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv,
@@ -137,15 +135,6 @@ void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(struct Subdiv *subd
void *normal_buffer,
int normal_offset,
int normal_stride);
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(struct Subdiv *subdiv,
- int ptex_face_index,
- int resolution,
- void *point_buffer,
- int point_offset,
- int point_stride,
- void *normal_buffer,
- int normal_offset,
- int normal_stride);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 73785e2ee2b..f25c0044c7d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -775,28 +775,6 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
/* Compute normals. */
const bool do_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well.
- * Note that they will always be generated when no loop normals are computed,
- * since they are needed by drawing code. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals (NOTE: will compute poly and vert normals as well, if needed!). */
@@ -814,11 +792,7 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
* normals and will also have to calculate normals on the fly, try avoid
* this where possible since calculating polygon normals isn't fast,
* note that this isn't a problem for subsurf (only quads) or editmode
- * which deals with drawing differently.
- *
- * Only calc vertex normals if they are flagged as dirty.
- * If using loop normals, poly nors have already been computed.
- */
+ * which deals with drawing differently. */
if (!do_loop_normals) {
BKE_mesh_ensure_normals_for_display(mesh_final);
}
@@ -927,6 +901,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
* constructive modifier is executed, or a deform modifier needs normals
* or certain data layers. */
Mesh *mesh_input = (Mesh *)ob->data;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_input);
Mesh *mesh_final = nullptr;
Mesh *mesh_deform = nullptr;
/* This geometry set contains the non-mesh data that might be generated by modifiers. */
@@ -1458,26 +1433,6 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const bool do_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
- /* Some modifiers may need this info from their target (other) object,
- * simpler to generate it here as well. */
- const bool do_poly_normals = ((final_datamask->pmask & CD_MASK_NORMAL) != 0);
-
- /* In case we also need poly normals, add the layer and compute them here
- * (BKE_mesh_calc_normals_split() assumes that if that data exists, it is always valid). */
- if (do_poly_normals) {
- if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
- float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
- &mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
- BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
- mesh_final->totvert,
- mesh_final->mloop,
- mesh_final->totloop,
- mesh_final->mpoly,
- mesh_final->totpoly,
- polynors,
- nullptr);
- }
- }
if (do_loop_normals) {
/* Compute loop normals */
@@ -1808,14 +1763,6 @@ static void mesh_build_extra_data(struct Depsgraph *depsgraph, Object *ob, Mesh
}
}
-static void mesh_runtime_check_normals_valid(const Mesh *mesh)
-{
- UNUSED_VARS_NDEBUG(mesh);
- BLI_assert(!(mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_loop & CD_MASK_NORMAL));
- BLI_assert(!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL));
-}
-
static void mesh_build_data(struct Depsgraph *depsgraph,
Scene *scene,
Object *ob,
@@ -1890,7 +1837,6 @@ static void mesh_build_data(struct Depsgraph *depsgraph,
}
}
- mesh_runtime_check_normals_valid(mesh_eval);
mesh_build_extra_data(depsgraph, ob, mesh_eval);
}
@@ -1923,8 +1869,6 @@ static void editbmesh_build_data(struct Depsgraph *depsgraph,
BKE_object_boundbox_calc_from_mesh(obedit, em->mesh_eval_final);
em->lastDataMask = *dataMask;
-
- mesh_runtime_check_normals_valid(em->mesh_eval_final);
}
static void object_get_datamask(const Depsgraph *depsgraph,
@@ -2181,8 +2125,7 @@ struct MappedUserData {
static void make_vertexcos__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedUserData *mappedData = (MappedUserData *)userData;
@@ -2229,6 +2172,7 @@ void DM_calc_loop_tangents(DerivedMesh *dm,
calc_active_tangent,
tangent_names,
tangent_names_len,
+ (const float(*)[3])CustomData_get_layer(&dm->vertData, CD_NORMAL),
(const float(*)[3])CustomData_get_layer(&dm->polyData, CD_NORMAL),
(const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL),
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* may be nullptr */
diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc
index 09a01d209df..5e7a4eea0cd 100644
--- a/source/blender/blenkernel/intern/bvhutils.cc
+++ b/source/blender/blenkernel/intern/bvhutils.cc
@@ -1601,6 +1601,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
memset(data, 0, sizeof(*data));
}
+ data->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+
return tree;
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index c93d320787a..a4f3e84a2bf 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -56,6 +56,7 @@ typedef struct {
/* these point to data in the DerivedMesh custom data layers,
* they are only here for efficiency and convenience */
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MFace *mface;
MLoop *mloop;
@@ -143,7 +144,7 @@ static void cdDM_getVertCo(DerivedMesh *dm, int index, float r_co[3])
static void cdDM_getVertNo(DerivedMesh *dm, int index, float r_no[3])
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
- normal_short_to_float_v3(r_no, cddm->mvert[index].no);
+ copy_v3_v3(r_no, cddm->vert_normals[index]);
}
static const MeshElemMap *cdDM_getPolyMap(Object *ob, DerivedMesh *dm)
@@ -281,6 +282,7 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
CustomData_merge(&mesh->pdata, &dm->polyData, cddata_masks.pmask, alloctype, mesh->totpoly);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->vert_normals = CustomData_get_layer(&dm->vertData, CD_NORMAL);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 42633ff3809..43b8690e219 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1400,8 +1400,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
float radius;
copy_v3_v3(co, treedata->vert[v_idx].co);
- normal_short_to_float_v3(no, treedata->vert[v_idx].no);
- negate_v3(no);
+ negate_v3_v3(no, treedata->vert_normals[v_idx]);
float vec_len = sin(max_diversion);
float offset[3];
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 2a5afb6be9a..f013ef99dde 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -72,6 +72,7 @@
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_movieclip.h"
#include "BKE_object.h"
@@ -544,6 +545,7 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
float vec[3] = {0.0f, 0.0f, 0.0f};
float normal[3] = {0.0f, 0.0f, 0.0f};
float weightsum = 0.0f;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval) {
const MDeformVert *dvert = CustomData_get_layer(&me_eval->vdata, CD_MDEFORMVERT);
int numVerts = me_eval->totvert;
@@ -558,10 +560,8 @@ static void contarget_get_mesh_mat(Object *ob, const char *substring, float mat[
const MDeformWeight *dw = BKE_defvert_find_index(dv, defgroup);
if (dw && dw->weight > 0.0f) {
- float nor[3];
- normal_short_to_float_v3(nor, mv->no);
madd_v3_v3fl(vec, mv->co, dw->weight);
- madd_v3_v3fl(normal, nor, dw->weight);
+ madd_v3_v3fl(normal, vert_normals[i], dw->weight);
weightsum += dw->weight;
}
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 59d9039fff5..6ec3e783fa2 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -345,30 +345,6 @@ static void layerInterp_normal(const void **sources,
normalize_v3_v3((float *)dest, no);
}
-static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes)
-{
- static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */
- float(*no)[3] = (float(*)[3])data;
- bool has_errors = false;
-
- for (int i = 0; i < totitems; i++, no++) {
- if (!is_finite_v3((float *)no)) {
- has_errors = true;
- if (do_fixes) {
- copy_v3_v3((float *)no, no_default);
- }
- }
- else if (!compare_ff(len_squared_v3((float *)no), 1.0f, 1e-6f)) {
- has_errors = true;
- if (do_fixes) {
- normalize_v3((float *)no);
- }
- }
- }
-
- return has_errors;
-}
-
static void layerCopyValue_normal(const void *source,
void *dest,
const int mixmode,
@@ -1549,7 +1525,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerInterp_normal,
nullptr,
nullptr,
- layerValidate_normal,
+ nullptr,
nullptr,
nullptr,
nullptr,
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index f036f1ced87..0ad7efb6347 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -273,7 +273,6 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
@@ -284,26 +283,9 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
BLI_assert(CustomData_get_layer(&me_src->pdata, CD_NORMAL) != NULL);
(void)me_src;
- float(*poly_nors_dst)[3];
float(*loop_nors_dst)[3];
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (do_poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- num_verts_dst,
- loops_dst,
- num_loops_dst,
- polys_dst,
- num_polys_dst,
- poly_nors_dst);
- }
/* Cache loop nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
const bool do_loop_nors_dst = (loop_nors_dst == NULL);
@@ -313,6 +295,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -320,7 +303,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
loop_nors_dst,
num_loops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ BKE_mesh_poly_normals_ensure(me_dst),
num_polys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -368,6 +351,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src),
/* Note loop_nors_dst contains our custom normals as transferred from source... */
BKE_mesh_normals_loop_custom_set(verts_dst,
+ BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
edges_dst,
num_edges_dst,
@@ -1651,7 +1635,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
@@ -1685,6 +1668,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
num_verts_dst,
edges_dst,
@@ -1694,7 +1678,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
polys_dst,
num_polys_dst,
ldata_dst,
- pdata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0,
me_dst->smoothresh,
dirty_nors_dst,
@@ -1745,7 +1728,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const int num_polys_dst = me_dst->totpoly;
MLoop *loops_dst = me_dst->mloop;
const int num_loops_dst = me_dst->totloop;
- CustomData *pdata_dst = &me_dst->pdata;
if (!geom_map_init[PDATA]) {
const int num_polys_src = me_src->totpoly;
@@ -1776,14 +1758,11 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
space_transform,
max_distance,
ray_radius,
+ me_dst,
verts_dst,
- num_verts_dst,
loops_dst,
- num_loops_dst,
polys_dst,
num_polys_dst,
- pdata_dst,
- dirty_nors_dst,
me_src,
&geom_map[PDATA]);
geom_map_init[PDATA] = true;
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index 48bf24a0825..78177095a77 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -904,7 +904,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
int totvert;
float(*vertex_coords)[3] = BKE_mesh_vert_coords_alloc(mesh, &totvert);
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
mti->deformVerts(md, &mectx_deform, mesh, vertex_coords, totvert);
BKE_mesh_vert_coords_apply(mesh, vertex_coords);
@@ -912,7 +912,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
}
else {
if (mti->dependsOnNormals != nullptr && mti->dependsOnNormals(md)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
Mesh *output_mesh = mti->modifyMesh(md, &mectx_apply, mesh);
if (mesh != output_mesh) {
@@ -924,7 +924,7 @@ static GeometrySet curve_calc_modifiers_post(Depsgraph *depsgraph,
if (geometry_set.has_mesh()) {
Mesh *final_mesh = geometry_set.get_mesh_for_write();
- BKE_mesh_calc_normals(final_mesh);
+ BKE_mesh_ensure_normals_for_display(final_mesh);
BLI_strncpy(final_mesh->id.name, cu->id.name, sizeof(final_mesh->id.name));
*((short *)final_mesh->id.name) = ID_ME;
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index ce92a34de47..64e0427a810 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -1789,6 +1789,7 @@ typedef struct DynamicPaintModifierApplyData {
Object *ob;
MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MPoly *mpoly;
@@ -1806,14 +1807,11 @@ static void dynamic_paint_apply_surface_displace_cb(void *__restrict userdata,
const DynamicPaintSurface *surface = data->surface;
MVert *mvert = data->mvert;
- float normal[3];
const float *value = (float *)surface->data->type_data;
const float val = value[i] * surface->disp_factor;
- normal_short_to_float_v3(normal, mvert[i].no);
-
/* same as 'mvert[i].co[0] -= normal[0] * val' etc. */
- madd_v3_v3fl(mvert[i].co, normal, -val);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], -val);
}
/* apply displacing vertex surface to the derived mesh */
@@ -1832,6 +1830,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -1898,10 +1897,8 @@ static void dynamic_paint_apply_surface_wave_cb(void *__restrict userdata,
PaintWavePoint *wPoint = (PaintWavePoint *)data->surface->data->type_data;
MVert *mvert = data->mvert;
- float normal[3];
- normal_short_to_float_v3(normal, mvert[i].no);
- madd_v3_v3fl(mvert[i].co, normal, wPoint[i].height);
+ madd_v3_v3fl(mvert[i].co, data->vert_normals[i], wPoint[i].height);
}
/*
@@ -2030,6 +2027,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object *
DynamicPaintModifierApplyData data = {
.surface = surface,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -4287,6 +4285,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
mesh = BKE_mesh_copy_for_eval(brush_mesh, false);
mvert = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
mlooptri = BKE_mesh_runtime_looptri_ensure(mesh);
mloop = mesh->mloop;
numOfVerts = mesh->totvert;
@@ -4301,7 +4300,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph,
/* for proximity project calculate average normal */
if (brush->flags & MOD_DPAINT_PROX_PROJECT && brush->collision != MOD_DPAINT_COL_VOLUME) {
float nor[3];
- normal_short_to_float_v3(nor, mvert[ii].no);
+ copy_v3_v3(nor, vert_normals[ii]);
mul_mat3_m4_v3(brushOb->obmat, nor);
normalize_v3(nor);
@@ -5909,6 +5908,7 @@ typedef struct DynamicPaintGenerateBakeData {
Object *ob;
const MVert *mvert;
+ const float (*vert_normals)[3];
const Vec3f *canvas_verts;
const bool do_velocity_data;
@@ -5928,7 +5928,6 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
Object *ob = data->ob;
- const MVert *mvert = data->mvert;
const Vec3f *canvas_verts = data->canvas_verts;
const bool do_velocity_data = data->do_velocity_data;
@@ -5962,9 +5961,9 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* Calculate current pixel surface normal */
- normal_short_to_float_v3(n1, mvert[tPoint->v1].no);
- normal_short_to_float_v3(n2, mvert[tPoint->v2].no);
- normal_short_to_float_v3(n3, mvert[tPoint->v3].no);
+ copy_v3_v3(n1, data->vert_normals[tPoint->v1]);
+ copy_v3_v3(n2, data->vert_normals[tPoint->v2]);
+ copy_v3_v3(n3, data->vert_normals[tPoint->v3]);
interp_v3_v3v3v3(
temp_nor, n1, n2, n3, f_data->barycentricWeights[index * bData->s_num[index]].v);
@@ -6006,7 +6005,7 @@ static void dynamic_paint_generate_bake_data_cb(void *__restrict userdata,
}
/* normal */
- normal_short_to_float_v3(temp_nor, mvert[index].no);
+ copy_v3_v3(temp_nor, data->vert_normals[index]);
if (ELEM(surface->type, MOD_DPAINT_SURFACE_T_DISPLACE, MOD_DPAINT_SURFACE_T_WAVE)) {
/* Prepare surface normal directional scale to easily convert
* brush intersection amount between global and local space */
@@ -6145,6 +6144,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface,
.surface = surface,
.ob = ob,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(mesh),
.canvas_verts = canvas_verts,
.do_velocity_data = do_velocity_data,
.new_bdata = new_bdata,
diff --git a/source/blender/blenkernel/intern/editmesh.c b/source/blender/blenkernel/intern/editmesh.c
index 805d3cdb5e3..6ef811c46c7 100644
--- a/source/blender/blenkernel/intern/editmesh.c
+++ b/source/blender/blenkernel/intern/editmesh.c
@@ -229,8 +229,7 @@ struct CageUserData {
static void cage_mapped_verts_callback(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
struct CageUserData *data = userData;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index 8229228976c..bbf9e9edfd2 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -59,6 +59,7 @@
#include "BKE_fluid.h"
#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -715,9 +716,10 @@ bool get_effector_data(EffectorCache *eff,
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */
const Mesh *me_eval = BKE_object_get_evaluated_mesh(eff->ob);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me_eval);
if (me_eval != NULL) {
copy_v3_v3(efd->loc, me_eval->mvert[*efd->index].co);
- normal_short_to_float_v3(efd->nor, me_eval->mvert[*efd->index].no);
+ copy_v3_v3(efd->nor, vert_normals[*efd->index]);
mul_m4_v3(eff->ob->obmat, efd->loc);
mul_mat3_m4_v3(eff->ob->obmat, efd->nor);
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 39122b33683..0c9e352da12 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -1030,7 +1030,6 @@ static void obstacles_from_mesh(Object *coll_ob,
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
looptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -1053,9 +1052,11 @@ static void obstacles_from_mesh(Object *coll_ob,
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
float co[3];
/* Vertex position. */
@@ -1063,11 +1064,9 @@ static void obstacles_from_mesh(Object *coll_ob,
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(coll_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(coll_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
add_v3fl_v3fl_v3i(co, mvert[i].co, fds->shift);
@@ -1826,6 +1825,7 @@ static void update_distances(int index,
static void sample_mesh(FluidFlowSettings *ffs,
const MVert *mvert,
+ const float (*vert_normals)[3],
const MLoop *mloop,
const MLoopTri *mlooptri,
const MLoopUV *mloopuv,
@@ -1906,7 +1906,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
tree_data->tree, ray_start, &nearest, tree_data->nearest_callback, tree_data) != -1) {
float weights[3];
int v1, v2, v3, f_index = nearest.index;
- float n1[3], n2[3], n3[3], hit_normal[3];
+ float hit_normal[3];
/* Calculate barycentric weights for nearest point. */
v1 = mloop[mlooptri[f_index].tri[0]].v;
@@ -1969,10 +1969,8 @@ static void sample_mesh(FluidFlowSettings *ffs,
/* Apply normal directional velocity. */
if (ffs->vel_normal) {
/* Interpolate vertex normal vectors to get nearest point normal. */
- normal_short_to_float_v3(n1, mvert[v1].no);
- normal_short_to_float_v3(n2, mvert[v2].no);
- normal_short_to_float_v3(n3, mvert[v3].no);
- interp_v3_v3v3v3(hit_normal, n1, n2, n3, weights);
+ interp_v3_v3v3v3(
+ hit_normal, vert_normals[v1], vert_normals[v2], vert_normals[v3], weights);
normalize_v3(hit_normal);
/* Apply normal directional velocity. */
@@ -2022,6 +2020,7 @@ typedef struct EmitFromDMData {
FluidFlowSettings *ffs;
const MVert *mvert;
+ const float (*vert_normals)[3];
const MLoop *mloop;
const MLoopTri *mlooptri;
const MLoopUV *mloopuv;
@@ -2056,6 +2055,7 @@ static void emit_from_mesh_task_cb(void *__restrict userdata,
(data->ffs->behavior == FLUID_FLOW_BEHAVIOR_INFLOW)) {
sample_mesh(data->ffs,
data->mvert,
+ data->vert_normals,
data->mloop,
data->mlooptri,
data->mloopuv,
@@ -2117,7 +2117,6 @@ static void emit_from_mesh(
CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
}
- BKE_mesh_ensure_normals(me);
mvert = me->mvert;
mloop = me->mloop;
mlooptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -2140,20 +2139,19 @@ static void emit_from_mesh(
}
}
- /* Transform mesh vertices to domain grid space for fast lookups */
+ /* Transform mesh vertices to domain grid space for fast lookups.
+ * This is valid because the mesh is copied above. */
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
- float n[3];
-
/* Vertex position. */
mul_m4_v3(flow_ob->obmat, mvert[i].co);
manta_pos_to_cell(fds, mvert[i].co);
/* Vertex normal. */
- normal_short_to_float_v3(n, mvert[i].no);
- mul_mat3_m4_v3(flow_ob->obmat, n);
- mul_mat3_m4_v3(fds->imat, n);
- normalize_v3(n);
- normal_float_to_short_v3(mvert[i].no, n);
+ mul_mat3_m4_v3(flow_ob->obmat, vert_normals[i]);
+ mul_mat3_m4_v3(fds->imat, vert_normals[i]);
+ normalize_v3(vert_normals[i]);
/* Vertex velocity. */
if (ffs->flags & FLUID_FLOW_INITVELOCITY) {
@@ -2193,6 +2191,7 @@ static void emit_from_mesh(
.fds = fds,
.ffs = ffs,
.mvert = mvert,
+ .vert_normals = vert_normals,
.mloop = mloop,
.mlooptri = mlooptri,
.mloopuv = mloopuv,
@@ -3265,8 +3264,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
MVert *mverts;
MPoly *mpolys;
MLoop *mloops;
- short *normals, *no_s;
- float no[3];
float min[3];
float max[3];
float size[3];
@@ -3285,26 +3282,23 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
const char mp_flag = mp_example.flag;
int i;
- int num_verts, num_normals, num_faces;
+ int num_verts, num_faces;
if (!fds->fluid) {
return NULL;
}
num_verts = manta_liquid_get_num_verts(fds->fluid);
- num_normals = manta_liquid_get_num_normals(fds->fluid);
num_faces = manta_liquid_get_num_triangles(fds->fluid);
# ifdef DEBUG_PRINT
/* Debugging: Print number of vertices, normals, and faces. */
- printf("num_verts: %d, num_normals: %d, num_faces: %d\n", num_verts, num_normals, num_faces);
+ printf("num_verts: %d, num_faces: %d\n", num_verts, num_faces);
# endif
if (!num_verts || !num_faces) {
return NULL;
}
- /* Normals are per vertex, so these must match. */
- BLI_assert(num_verts == num_normals);
me = BKE_mesh_new_nomain(num_verts, 0, 0, num_faces * 3, num_faces);
if (!me) {
@@ -3334,9 +3328,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
co_offset[1] = (fds->p0[1] + fds->p1[1]) / 2.0f;
co_offset[2] = (fds->p0[2] + fds->p1[2]) / 2.0f;
- /* Normals. */
- normals = MEM_callocN(sizeof(short[3]) * num_normals, "Fluidmesh_tmp_normals");
-
/* Velocities. */
/* If needed, vertex velocities will be read too. */
bool use_speedvectors = fds->flags & FLUID_DOMAIN_USE_SPEED_VECTORS;
@@ -3350,7 +3341,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
}
/* Loop for vertices and normals. */
- for (i = 0, no_s = normals; i < num_verts && i < num_normals; i++, mverts++, no_s += 3) {
+ for (i = 0; i < num_verts; i++, mverts++) {
/* Vertices (data is normalized cube around domain origin). */
mverts->co[0] = manta_liquid_get_vertex_x_at(fds->fluid, i);
@@ -3376,12 +3367,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
mverts->co[2]);
# endif
- /* Normals (data is normalized cube around domain origin). */
- no[0] = manta_liquid_get_normal_x_at(fds->fluid, i);
- no[1] = manta_liquid_get_normal_y_at(fds->fluid, i);
- no[2] = manta_liquid_get_normal_z_at(fds->fluid, i);
-
- normal_float_to_short_v3(no_s, no);
# ifdef DEBUG_PRINT
/* Debugging: Print coordinates of normals. */
printf("no_s[0]: %d, no_s[1]: %d, no_s[2]: %d\n", no_s[0], no_s[1], no_s[2]);
@@ -3425,11 +3410,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
# endif
}
- BKE_mesh_ensure_normals(me);
BKE_mesh_calc_edges(me, false, false);
- BKE_mesh_vert_normals_apply(me, (short(*)[3])normals);
-
- MEM_freeN(normals);
return me;
}
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 88a58220b23..11b350ef2be 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -128,111 +128,45 @@ void MeshComponent::ensure_owns_direct_data()
namespace blender::bke {
-static VArray<float3> mesh_face_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
-{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan({(const float3 *)data, polys.size()});
- }
-
- auto normal_fn = [verts, polys, loops](const int i) -> float3 {
- float3 normal;
- const MPoly &poly = polys[i];
- BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], verts.data(), normal);
- return normal;
- };
-
- return VArray<float3>::ForFunc(mask.min_array_size(), normal_fn);
-}
-
-static VArray<float3> mesh_vertex_normals(const Mesh &mesh,
- const Span<MVert> verts,
- const Span<MPoly> polys,
- const Span<MLoop> loops,
- const IndexMask mask)
-{
- /* Use existing normals to avoid unnecessarily recalculating them, if possible. */
- if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh.vdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan({(const float3 *)data, mesh.totvert});
- }
-
- /* If the normals are dirty, they must be recalculated for the output of this node's field
- * source. Ideally vertex normals could be calculated lazily on a const mesh, but that's not
- * possible at the moment, so we take ownership of the results. Sadly we must also create a copy
- * of MVert to use the mesh normals API. This can be improved by adding mutex-protected lazy
- * calculation of normals on meshes.
- *
- * Use mask.min_array_size() to avoid calculating a final chunk of data if possible. */
- Array<MVert> temp_verts(verts);
- Array<float3> normals(verts.size()); /* Use full size for accumulation from faces. */
- BKE_mesh_calc_normals_poly_and_vertex(temp_verts.data(),
- mask.min_array_size(),
- loops.data(),
- loops.size(),
- polys.data(),
- polys.size(),
- nullptr,
- (float(*)[3])normals.data());
-
- return VArray<float3>::ForContainer(std::move(normals));
-}
-
VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component,
const Mesh &mesh,
const IndexMask mask,
const AttributeDomain domain)
{
- Span<MVert> verts{mesh.mvert, mesh.totvert};
- Span<MEdge> edges{mesh.medge, mesh.totedge};
- Span<MPoly> polys{mesh.mpoly, mesh.totpoly};
- Span<MLoop> loops{mesh.mloop, mesh.totloop};
-
switch (domain) {
case ATTR_DOMAIN_FACE: {
- return mesh_face_normals(mesh, verts, polys, loops, mask);
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly});
}
case ATTR_DOMAIN_POINT: {
- return mesh_vertex_normals(mesh, verts, polys, loops, mask);
+ return VArray<float3>::ForSpan(
+ {(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert});
}
case ATTR_DOMAIN_EDGE: {
/* In this case, start with vertex normals and convert to the edge domain, since the
- * conversion from edges to vertices is very simple. Use the full mask since the edges
- * might use the vertex normal from any index. */
- GVArray vert_normals = mesh_vertex_normals(
- mesh, verts, polys, loops, IndexRange(verts.size()));
- Span<float3> vert_normals_span = vert_normals.get_internal_span().typed<float3>();
+ * conversion from edges to vertices is very simple. Use "manual" domain interpolation
+ * instead of the GeometryComponent API to avoid calculating unnecessary values and to
+ * allow normalizing the result more simply. */
+ Span<float3> vert_normals{(float3 *)BKE_mesh_vertex_normals_ensure(&mesh), mesh.totvert};
Array<float3> edge_normals(mask.min_array_size());
-
- /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid
- * calculating unnecessary values and to allow normalizing the result much more simply. */
+ Span<MEdge> edges{mesh.medge, mesh.totedge};
for (const int i : mask) {
const MEdge &edge = edges[i];
edge_normals[i] = math::normalize(
- math::interpolate(vert_normals_span[edge.v1], vert_normals_span[edge.v2], 0.5f));
+ math::interpolate(vert_normals[edge.v1], vert_normals[edge.v2], 0.5f));
}
return VArray<float3>::ForContainer(std::move(edge_normals));
}
case ATTR_DOMAIN_CORNER: {
/* The normals on corners are just the mesh's face normals, so start with the face normal
- * array and copy the face normal for each of its corners. */
- VArray<float3> face_normals = mesh_face_normals(
- mesh, verts, polys, loops, IndexRange(polys.size()));
-
- /* In this case using the mesh component's generic domain interpolation is fine, the data
- * will still be normalized, since the face normal is just copied to every corner. */
- return mesh_component.attribute_try_adapt_domain<float3>(
- std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER);
+ * array and copy the face normal for each of its corners. In this case using the mesh
+ * component's generic domain interpolation is fine, the data will still be normalized,
+ * since the face normal is just copied to every corner. */
+ return mesh_component.attribute_try_adapt_domain(
+ VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}),
+ ATTR_DOMAIN_FACE,
+ ATTR_DOMAIN_CORNER);
}
default:
return {};
@@ -1276,25 +1210,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
- if (mesh == nullptr) {
+ if (mesh == nullptr || mesh->totpoly == 0) {
return {};
}
-
- /* Use existing normals if possible. */
- if (!(mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL) &&
- CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
-
- return VArray<float3>::ForSpan(Span<float3>((const float3 *)data, mesh->totpoly));
- }
-
- Array<float3> normals(mesh->totpoly);
- for (const int i : IndexRange(mesh->totpoly)) {
- const MPoly *poly = &mesh->mpoly[i];
- BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
- }
-
- return VArray<float3>::ForContainer(std::move(normals));
+ return VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(mesh), mesh->totpoly});
}
WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final
diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc
index 116d77f1a2a..9abdbceec61 100644
--- a/source/blender/blenkernel/intern/gpencil_geom.cc
+++ b/source/blender/blenkernel/intern/gpencil_geom.cc
@@ -60,6 +60,7 @@
#include "BKE_gpencil_geom.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "DEG_depsgraph_query.h"
@@ -2350,6 +2351,7 @@ static void gpencil_generate_edgeloops(Object *ob,
if (me->totedge == 0) {
return;
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
/* Arrays for all edge vertices (forward and backward) that form a edge loop.
* This is reused for each edge-loop to create gpencil stroke. */
@@ -2364,13 +2366,13 @@ static void gpencil_generate_edgeloops(Object *ob,
MEdge *ed = &me->medge[i];
gped = &gp_edges[i];
MVert *mv1 = &me->mvert[ed->v1];
- normal_short_to_float_v3(gped->n1, mv1->no);
+ copy_v3_v3(gped->n1, vert_normals[ed->v1]);
gped->v1 = ed->v1;
copy_v3_v3(gped->v1_co, mv1->co);
MVert *mv2 = &me->mvert[ed->v2];
- normal_short_to_float_v3(gped->n2, mv2->no);
+ copy_v3_v3(gped->n2, vert_normals[ed->v2]);
gped->v2 = ed->v2;
copy_v3_v3(gped->v2_co, mv2->co);
@@ -2439,7 +2441,7 @@ static void gpencil_generate_edgeloops(Object *ob,
/* Add segment. */
bGPDspoint *pt = &gps_stroke->points[i];
- normal_short_to_float_v3(fpt, mv->no);
+ copy_v3_v3(fpt, vert_normals[vertex_index]);
mul_v3_v3fl(fpt, fpt, offset);
add_v3_v3v3(&pt->x, mv->co, fpt);
mul_m4_v3(matrix, &pt->x);
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index ff199794ab3..0df493e28c0 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -2230,13 +2230,20 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
free_polynors = true;
}
- BKE_mesh_calc_normals_poly_and_vertex(
- me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors);
+
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ if (r_vertnors) {
+ memcpy(r_vertnors, vert_normals, sizeof(float[3]) * me.totvert);
+ }
+
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
+ memcpy(r_polynors, face_normals, sizeof(float[3]) * me.totpoly);
if (r_loopnors) {
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
BKE_mesh_normals_loop_split(me.mvert,
+ vert_normals,
me.totvert,
me.medge,
me.totedge,
@@ -2244,7 +2251,7 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
r_loopnors,
me.totloop,
me.mpoly,
- r_polynors,
+ face_normals,
me.totpoly,
(me.flag & ME_AUTOSMOOTH) != 0,
me.smoothresh,
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 8ceaced1972..1aa3477437a 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -94,6 +94,10 @@ static void mesh_init_data(ID *id)
BKE_mesh_runtime_init_data(mesh);
+ /* A newly created mesh does not have normals, so tag them dirty. This will be cleared
+ * by #BKE_mesh_vertex_normals_clear_dirty or #BKE_mesh_poly_normals_ensure. */
+ BKE_mesh_normals_tag_dirty(mesh);
+
mesh->face_sets_color_seed = BLI_hash_int(PIL_check_seconds_timer_i() & UINT_MAX);
}
@@ -150,12 +154,21 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
+ /* Set normal layers dirty, since they aren't included in CD_MASK_MESH and are therefore not
+ * copied to the destination mesh. Alternatively normal layers could be copied if they aren't
+ * dirty, avoiding recomputation in some cases. However, a copied mesh is often changed anyway,
+ * so that idea is not clearly better. With proper reference counting, all custom data layers
+ * could be copied as the cost would be much lower. */
+ BKE_mesh_normals_tag_dirty(mesh_dst);
+
/* TODO: Do we want to add flag to prevent this? */
if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag);
/* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */
mesh_dst->key->from = &mesh_dst->id;
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
}
static void mesh_free_data(ID *id)
@@ -335,6 +348,10 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
BLI_endian_switch_uint32_array(tf->col, 4);
}
}
+
+ /* We don't expect to load normals from files, since they are derived data. */
+ BKE_mesh_normals_tag_dirty(mesh);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
}
static void mesh_blend_read_lib(BlendLibReader *reader, ID *id)
@@ -1036,6 +1053,8 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
BKE_mesh_copy_parameters(me_dst, me_src);
+ BKE_mesh_assert_normals_dirty_or_calculated(me_dst);
+
/* Copy vertex group names. */
BLI_assert(BLI_listbase_is_empty(&me_dst->vertex_group_names));
BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names);
@@ -1083,6 +1102,18 @@ 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)) {
+ me_dst->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&me_dst->pdata, CD_NORMAL)) {
+ me_dst->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
/* 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);
@@ -1882,24 +1913,10 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
BKE_mesh_normals_tag_dirty(mesh);
}
-void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3])
-{
- /* This will just return the pointer if it wasn't a referenced layer. */
- MVert *mv = (MVert *)CustomData_duplicate_referenced_layer(
- &mesh->vdata, CD_MVERT, mesh->totvert);
- mesh->mvert = mv;
- for (int i = 0; i < mesh->totvert; i++, mv++) {
- copy_v3_v3_short(mv->no, vert_normals[i]);
- }
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
-}
-
void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
{
float(*r_loopnors)[3];
- float(*polynors)[3];
short(*clnors)[2] = nullptr;
- bool free_polynors = false;
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
* However, we obviously only use the auto-smooth angle threshold
@@ -1921,26 +1938,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
/* may be nullptr */
clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
- if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
- /* This assume that layer is always up to date, not sure this is the case
- * (esp. in Edit mode?)... */
- polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- free_polynors = false;
- }
- else {
- polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- nullptr);
- free_polynors = true;
- }
-
BKE_mesh_normals_loop_split(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -1948,7 +1947,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
r_loopnors,
mesh->totloop,
mesh->mpoly,
- (const float(*)[3])polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
use_split_normals,
split_angle,
@@ -1956,12 +1955,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
clnors,
nullptr);
- if (free_polynors) {
- MEM_freeN(polynors);
- }
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL;
}
@@ -1989,7 +1984,7 @@ struct SplitFaceNewEdge {
/* Detect needed new vertices, and update accordingly loops' vertex indices.
* WARNING! Leaves mesh in invalid state. */
-static int split_faces_prepare_new_verts(const Mesh *mesh,
+static int split_faces_prepare_new_verts(Mesh *mesh,
MLoopNorSpaceArray *lnors_spacearr,
SplitFaceNewVert **new_verts,
MemArena *memarena)
@@ -2001,8 +1996,9 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
const int loops_len = mesh->totloop;
int verts_len = mesh->totvert;
- MVert *mvert = mesh->mvert;
MLoop *mloop = mesh->mloop;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__);
BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__);
@@ -2046,7 +2042,7 @@ static int split_faces_prepare_new_verts(const Mesh *mesh,
* vnor should always be defined to 'automatic normal' value computed from its polys,
* not some custom normal.
* Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */
- normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor);
+ copy_v3_v3(vert_normals[vert_idx], (*lnor_space)->vec_lnor);
}
else {
/* Add new vert to list. */
@@ -2137,6 +2133,7 @@ static void split_faces_split_new_verts(Mesh *mesh,
{
const int verts_len = mesh->totvert - num_new_verts;
MVert *mvert = mesh->mvert;
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
/* Remember new_verts is a single linklist, so its items are in reversed order... */
MVert *new_mv = &mvert[mesh->totvert - 1];
@@ -2145,9 +2142,10 @@ static void split_faces_split_new_verts(Mesh *mesh,
BLI_assert(new_verts->new_index != new_verts->orig_index);
CustomData_copy_data(&mesh->vdata, &mesh->vdata, new_verts->orig_index, i, 1);
if (new_verts->vnor) {
- normal_float_to_short_v3(new_mv->no, new_verts->vnor);
+ copy_v3_v3(vert_normals[i], new_verts->vnor);
}
}
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
/* Perform actual split of edges. */
@@ -2235,6 +2233,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
/* Also frees new_verts/edges temp data, since we used its memarena to allocate them. */
BKE_lnor_spacearr_free(&lnors_spacearr);
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
#ifdef VALIDATE_MESH
BKE_mesh_validate(mesh, true, true);
#endif
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index 12fa9d16fd1..cbc772d93a6 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "BLI_edgehash.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -65,6 +66,8 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
+using blender::IndexRange;
+
/* Define for cases when you want extra validation of mesh
* after certain modifications.
*/
@@ -85,7 +88,6 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
MVert *mvert;
MLoop *mloop, *allloop;
MPoly *mpoly;
- const float *nors, *verts;
int a, *index;
dl = (DispList *)lb->first;
@@ -104,15 +106,8 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
me->totvert = dl->nr;
me->totpoly = dl->parts;
- a = dl->nr;
- nors = dl->nors;
- verts = dl->verts;
- while (a--) {
- copy_v3_v3(mvert->co, verts);
- normal_float_to_short_v3(mvert->no, nors);
- mvert++;
- nors += 3;
- verts += 3;
+ for (const int i : IndexRange(dl->nr)) {
+ copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]);
}
a = dl->parts;
@@ -139,7 +134,7 @@ void BKE_mesh_from_metaball(ListBase *lb, Mesh *me)
BKE_mesh_update_customdata_pointers(me, true);
- BKE_mesh_calc_normals(me);
+ BKE_mesh_normals_tag_dirty(me);
BKE_mesh_calc_edges(me, true, false);
}
@@ -1476,8 +1471,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
CustomData_reset(&tmp.ldata);
CustomData_reset(&tmp.pdata);
- BKE_mesh_ensure_normals(mesh_src);
-
totvert = tmp.totvert = mesh_src->totvert;
totedge = tmp.totedge = mesh_src->totedge;
totloop = tmp.totloop = mesh_src->totloop;
@@ -1491,6 +1484,18 @@ 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)) {
+ tmp.runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ if (!CustomData_has_layer(&tmp.pdata, CD_NORMAL)) {
+ tmp.runtime.cd_dirty_poly |= CD_MASK_NORMAL;
+ }
+
if (CustomData_has_layer(&mesh_src->vdata, CD_SHAPEKEY)) {
KeyBlock *kb;
int uid;
@@ -1614,6 +1619,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
}
BKE_id_free(nullptr, mesh_src);
}
+
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh_dst);
}
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
diff --git a/source/blender/blenkernel/intern/mesh_iterators.c b/source/blender/blenkernel/intern/mesh_iterators.c
index 3b6afc1f47a..b77d0e38f0f 100644
--- a/source/blender/blenkernel/intern/mesh_iterators.c
+++ b/source/blender/blenkernel/intern/mesh_iterators.c
@@ -34,14 +34,11 @@
#include "MEM_guardedalloc.h"
-void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
- void (*func)(void *userData,
- int index,
- const float co[3],
- const float no_f[3],
- const short no_s[3]),
- void *userData,
- MeshForeachFlag flag)
+void BKE_mesh_foreach_mapped_vert(
+ Mesh *mesh,
+ void (*func)(void *userData, int index, const float co[3], const float no[3]),
+ void *userData,
+ MeshForeachFlag flag)
{
if (mesh->edit_mesh != NULL) {
BMEditMesh *em = mesh->edit_mesh;
@@ -61,34 +58,37 @@ void BKE_mesh_foreach_mapped_vert(Mesh *mesh,
}
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vertexNos[i] : NULL;
- func(userData, i, vertexCos[i], no, NULL);
+ func(userData, i, vertexCos[i], no);
}
}
else {
BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? eve->no : NULL;
- func(userData, i, eve->co, no, NULL);
+ func(userData, i, eve->co, no);
}
}
}
else {
const MVert *mv = mesh->mvert;
const int *index = CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX);
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
if (index) {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
const int orig = *index++;
if (orig == ORIGINDEX_NONE) {
continue;
}
- func(userData, orig, mv->co, NULL, no);
+ func(userData, orig, mv->co, no);
}
}
else {
for (int i = 0; i < mesh->totvert; i++, mv++) {
- const short *no = (flag & MESH_FOREACH_USE_NORMAL) ? mv->no : NULL;
- func(userData, i, mv->co, NULL, no);
+ const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : NULL;
+ func(userData, i, mv->co, no);
}
}
}
@@ -310,8 +310,9 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
const MPoly *mp = mesh->mpoly;
const MLoop *ml;
const MVert *mv;
- float _no_buf[3];
- float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : NULL;
+ const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ?
+ BKE_mesh_vertex_normals_ensure(mesh) :
+ NULL;
const int *index = CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX);
if (index) {
@@ -324,10 +325,11 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, orig, mv->co, no);
+
+ func(userData,
+ orig,
+ mv->co,
+ (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -338,10 +340,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center(
for (int j = 0; j < mp->totloop; j++, ml++) {
mv = &mesh->mvert[ml->v];
if (mv->flag & ME_VERT_FACEDOT) {
- if (flag & MESH_FOREACH_USE_NORMAL) {
- normal_short_to_float_v3(no, mv->no);
- }
- func(userData, i, mv->co, no);
+ func(userData, i, mv->co, (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[ml->v] : NULL);
}
}
}
@@ -358,8 +357,7 @@ typedef struct MappedVCosData {
static void get_vertexcos__mapFunc(void *user_data,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
MappedVCosData *mapped_vcos_data = (MappedVCosData *)user_data;
diff --git a/source/blender/blenkernel/intern/mesh_mirror.c b/source/blender/blenkernel/intern/mesh_mirror.c
index 2d4308945fc..652399a7294 100644
--- a/source/blender/blenkernel/intern/mesh_mirror.c
+++ b/source/blender/blenkernel/intern/mesh_mirror.c
@@ -410,7 +410,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
CustomData *ldata = &result->ldata;
short(*clnors)[2] = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
MLoopNorSpaceArray lnors_spacearr = {NULL};
- float(*poly_normals)[3] = MEM_mallocN(sizeof(*poly_normals) * totpoly, __func__);
/* The transform matrix of a normal must be
* the transpose of inverse of transform matrix of the geometry... */
@@ -420,16 +419,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
- BKE_mesh_calc_normals_poly_and_vertex(result->mvert,
- result->totvert,
- result->mloop,
- totloop,
- result->mpoly,
- totpoly,
- poly_normals,
- NULL);
-
BKE_mesh_normals_loop_split(result->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
result->totvert,
result->medge,
result->totedge,
@@ -437,7 +428,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
loop_normals,
totloop,
result->mpoly,
- poly_normals,
+ BKE_mesh_poly_normals_ensure(mesh),
totpoly,
true,
mesh->smoothresh,
@@ -463,7 +454,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
}
}
- MEM_freeN(poly_normals);
MEM_freeN(loop_normals);
BKE_lnor_spacearr_free(&lnors_spacearr);
}
diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc
index 47ea55be871..08a17060549 100644
--- a/source/blender/blenkernel/intern/mesh_normals.cc
+++ b/source/blender/blenkernel/intern/mesh_normals.cc
@@ -38,7 +38,9 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
#include "BLI_memarena.h"
+#include "BLI_span.hh"
#include "BLI_stack.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
@@ -50,6 +52,8 @@
#include "atomic_ops.h"
+using blender::Span;
+
// #define DEBUG_TIME
#ifdef DEBUG_TIME
@@ -109,6 +113,52 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh)
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
}
+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);
+}
+
+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);
+}
+
+void BKE_mesh_vertex_normals_clear_dirty(Mesh *mesh)
+{
+ mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ 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;
+ 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;
+}
+
+bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh)
+{
+ return mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL;
+}
+
+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.cd_dirty_poly & CD_MASK_NORMAL)) {
+ BLI_assert(CustomData_has_layer(&mesh->pdata, CD_NORMAL) || mesh->totpoly == 0);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -161,8 +211,6 @@ void BKE_mesh_calc_normals_poly(const MVert *mvert,
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons & Vertices)
*
- * Implement #BKE_mesh_calc_normals_poly_and_vertex,
- *
* Take care making optimizations to this function as improvements to low-poly
* meshes can slow down high-poly meshes. For details on performance, see D11993.
* \{ */
@@ -253,18 +301,16 @@ static void mesh_calc_normals_poly_and_vertex_finalize_fn(
/* Following Mesh convention; we use vertex coordinate itself for normal in this case. */
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
-void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
- const int mvert_len,
- const MLoop *mloop,
- const int UNUSED(mloop_len),
- const MPoly *mpoly,
- const int mpoly_len,
- float (*r_poly_normals)[3],
- float (*r_vert_normals)[3])
+static void mesh_calc_normals_poly_and_vertex(MVert *mvert,
+ const int mvert_len,
+ const MLoop *mloop,
+ const int UNUSED(mloop_len),
+ const MPoly *mpoly,
+ const int mpoly_len,
+ float (*r_poly_normals)[3],
+ float (*r_vert_normals)[3])
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
@@ -308,12 +354,81 @@ void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
/** \name Mesh Normal Calculation
* \{ */
-void BKE_mesh_ensure_normals(Mesh *mesh)
+const float (*BKE_mesh_vertex_normals_ensure(const Mesh *mesh))[3]
{
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals(mesh);
+ 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);
+ }
+
+ if (mesh->totvert == 0) {
+ return nullptr;
+ }
+
+ 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_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->vdata, CD_NORMAL);
}
- BLI_assert((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) == 0);
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh_mutable);
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ mesh_calc_normals_poly_and_vertex(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals,
+ vert_normals);
+
+ BKE_mesh_vertex_normals_clear_dirty(&mesh_mutable);
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return vert_normals;
+}
+
+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);
+ }
+
+ if (mesh->totpoly == 0) {
+ return nullptr;
+ }
+
+ 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_mutex_unlock(normals_mutex);
+ return (const float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+
+ Mesh &mesh_mutable = *const_cast<Mesh *>(mesh);
+
+ float(*poly_normals)[3] = BKE_mesh_poly_normals_for_write(&mesh_mutable);
+
+ BKE_mesh_calc_normals_poly(mesh_mutable.mvert,
+ mesh_mutable.totvert,
+ mesh_mutable.mloop,
+ mesh_mutable.totloop,
+ mesh_mutable.mpoly,
+ mesh_mutable.totpoly,
+ poly_normals);
+
+ BKE_mesh_poly_normals_clear_dirty(&mesh_mutable);
+
+ BLI_mutex_unlock(normals_mutex);
+ return poly_normals;
}
void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
@@ -321,7 +436,8 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
switch ((eMeshWrapperType)mesh->runtime.wrapper_type) {
case ME_WRAPPER_TYPE_SUBD:
case ME_WRAPPER_TYPE_MDATA:
- /* Run code below. */
+ BKE_mesh_vertex_normals_ensure(mesh);
+ BKE_mesh_poly_normals_ensure(mesh);
break;
case ME_WRAPPER_TYPE_BMESH: {
struct BMEditMesh *em = mesh->edit_mesh;
@@ -333,47 +449,6 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
return;
}
}
-
- float(*poly_nors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- const bool do_vert_normals = (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) != 0;
- const bool do_poly_normals = (mesh->runtime.cd_dirty_poly & CD_MASK_NORMAL ||
- poly_nors == nullptr);
-
- if (do_vert_normals || do_poly_normals) {
- const bool do_add_poly_nors_cddata = (poly_nors == nullptr);
- if (do_add_poly_nors_cddata) {
- poly_nors = (float(*)[3])MEM_malloc_arrayN(
- (size_t)mesh->totpoly, sizeof(*poly_nors), __func__);
- }
-
- /* Calculate poly/vert normals. */
- if (do_vert_normals) {
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors,
- nullptr);
- }
- else {
- BKE_mesh_calc_normals_poly(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- poly_nors);
- }
-
- if (do_add_poly_nors_cddata) {
- CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
- }
-
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
- mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL;
- }
}
void BKE_mesh_calc_normals(Mesh *mesh)
@@ -381,18 +456,10 @@ void BKE_mesh_calc_normals(Mesh *mesh)
#ifdef DEBUG_TIME
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
#endif
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- nullptr,
- nullptr);
+ BKE_mesh_vertex_normals_ensure(mesh);
#ifdef DEBUG_TIME
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
#endif
- mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
}
void BKE_mesh_calc_normals_looptri(MVert *mverts,
@@ -439,8 +506,6 @@ void BKE_mesh_calc_normals_looptri(MVert *mverts,
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
normalize_v3_v3(no, mv->co);
}
-
- normal_float_to_short_v3(mv->no, no);
}
cleanup:
@@ -753,6 +818,7 @@ struct LoopSplitTaskDataCommon {
int (*edge_to_loops)[2];
int *loop_to_poly;
const float (*polynors)[3];
+ const float (*vert_normals)[3];
int numEdges;
int numLoops;
@@ -769,7 +835,6 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
const float split_angle,
const bool do_sharp_edges_tag)
{
- const MVert *mverts = data->mverts;
const MEdge *medges = data->medges;
const MLoop *mloops = data->mloops;
@@ -808,7 +873,7 @@ static void mesh_edges_sharp_tag(LoopSplitTaskDataCommon *data,
* this way we don't have to compute those later!
*/
if (loopnors) {
- normal_short_to_float_v3(loopnors[ml_curr_index], mverts[ml_curr->v].no);
+ copy_v3_v3(loopnors[ml_curr_index], data->vert_normals[ml_curr->v]);
}
/* Check whether current edge might be smooth or sharp */
@@ -1533,6 +1598,7 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common
}
void BKE_mesh_normals_loop_split(const MVert *mverts,
+ const float (*vert_normals)[3],
const int UNUSED(numVerts),
MEdge *medges,
const int numEdges,
@@ -1575,7 +1641,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
}
else {
- normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ copy_v3_v3(r_loopnors[ml_index], vert_normals[mloops[ml_index].v]);
}
}
}
@@ -1633,6 +1699,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
common_data.edge_to_loops = edge_to_loops;
common_data.loop_to_poly = loop_to_poly;
common_data.polynors = polynors;
+ common_data.vert_normals = vert_normals;
common_data.numEdges = numEdges;
common_data.numLoops = numLoops;
common_data.numPolys = numPolys;
@@ -1684,6 +1751,7 @@ void BKE_mesh_normals_loop_split(const MVert *mverts,
* in which case they will be replaced by default loop/vertex normal.
*/
static void mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1715,6 +1783,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* Compute current lnor spacearr. */
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1734,7 +1803,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
if (use_vertices) {
for (int i = 0; i < numVerts; i++) {
if (is_zero_v3(r_custom_loopnors[i])) {
- normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no);
+ copy_v3_v3(r_custom_loopnors[i], vert_normals[i]);
}
}
}
@@ -1837,6 +1906,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
/* And now, recompute our new auto lnors and lnor spacearr! */
BKE_lnor_spacearr_clear(&lnors_spacearr);
BKE_mesh_normals_loop_split(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1918,6 +1988,7 @@ static void mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
+ const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const int numEdges,
@@ -1930,6 +2001,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1944,6 +2016,7 @@ void BKE_mesh_normals_loop_custom_set(const MVert *mverts,
}
void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
+ const float (*vert_normals)[3],
float (*r_custom_vertnors)[3],
const int numVerts,
MEdge *medges,
@@ -1956,6 +2029,7 @@ void BKE_mesh_normals_loop_custom_from_vertices_set(const MVert *mverts,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(mverts,
+ vert_normals,
numVerts,
medges,
numEdges,
@@ -1983,22 +2057,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops);
}
- float(*polynors)[3] = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- bool free_polynors = false;
- if (polynors == nullptr) {
- polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
- BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
- mesh->totvert,
- mesh->mloop,
- mesh->totloop,
- mesh->mpoly,
- mesh->totpoly,
- polynors,
- nullptr);
- free_polynors = true;
- }
-
mesh_normals_loop_custom_set(mesh->mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
mesh->totvert,
mesh->medge,
mesh->totedge,
@@ -2006,14 +2066,10 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
r_custom_nors,
mesh->totloop,
mesh->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(mesh),
mesh->totpoly,
clnors,
use_vertices);
-
- if (free_polynors) {
- MEM_freeN(polynors);
- }
}
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loopnors)[3])
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 5b5378bd829..a9f61e9827b 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -594,6 +594,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
MPoly *polys_src = me_src->mpoly;
MLoop *loops_src = me_src->mloop;
float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, NULL);
+ const float(*vert_normals_src)[3] = BKE_mesh_vertex_normals_ensure(me_src);
size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE;
float(*vcos)[3] = MEM_mallocN(sizeof(*vcos) * tmp_buff_size, __func__);
@@ -605,7 +606,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
if (mode == MREMAP_MODE_VERT_POLYINTERP_VNORPROJ) {
for (i = 0; i < numverts_dst; i++) {
copy_v3_v3(tmp_co, verts_dst[i].co);
- normal_short_to_float_v3(tmp_no, verts_dst[i].no);
+ copy_v3_v3(tmp_no, vert_normals_src[i]);
/* Convert the vertex to tree coordinates, if needed. */
if (space_transform) {
@@ -951,6 +952,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2);
+ const float(*vert_normals_dst)[3] = BKE_mesh_vertex_normals_ensure(me_src);
+
for (i = 0; i < numedges_dst; i++) {
/* For each dst edge, we sample some rays from it (interpolated from its vertices)
* and use their hits to interpolate from source edges. */
@@ -970,8 +973,8 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
copy_v3_v3(v1_co, verts_dst[me->v1].co);
copy_v3_v3(v2_co, verts_dst[me->v2].co);
- normal_short_to_float_v3(v1_no, verts_dst[me->v1].no);
- normal_short_to_float_v3(v2_no, verts_dst[me->v2].no);
+ copy_v3_v3(v1_no, vert_normals_dst[me->v1]);
+ copy_v3_v3(v2_no, vert_normals_dst[me->v2]);
/* We do our transform here, allows to interpolate from normals already in src space. */
if (space_transform) {
@@ -1242,6 +1245,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
const int numverts_dst,
MEdge *edges_dst,
@@ -1251,7 +1255,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
MPoly *polys_dst,
const int numpolys_dst,
CustomData *ldata_dst,
- CustomData *pdata_dst,
const bool use_split_nors_dst,
const float split_angle_dst,
const bool dirty_nors_dst,
@@ -1297,9 +1300,9 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
1) :
0);
- float(*poly_nors_src)[3] = NULL;
- float(*loop_nors_src)[3] = NULL;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_src)[3] = NULL;
+ const float(*loop_nors_src)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float(*loop_nors_dst)[3] = NULL;
float(*poly_cents_src)[3] = NULL;
@@ -1356,23 +1359,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const bool need_pnors_dst = need_lnors_dst || need_pnors_src;
if (need_pnors_dst) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- const bool do_poly_nors_dst = (poly_nors_dst == NULL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(
- pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst || do_poly_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
if (need_lnors_dst) {
short(*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
@@ -1387,6 +1374,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (dirty_nors_dst || do_loop_nors_dst) {
BKE_mesh_normals_loop_split(verts_dst,
+ BKE_mesh_vertex_normals_ensure(mesh_dst),
numverts_dst,
edges_dst,
numedges_dst,
@@ -1394,7 +1382,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
loop_nors_dst,
numloops_dst,
polys_dst,
- (const float(*)[3])poly_nors_dst,
+ poly_nors_dst,
numpolys_dst,
use_split_nors_dst,
split_angle_dst,
@@ -1405,8 +1393,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
}
if (need_pnors_src || need_lnors_src) {
if (need_pnors_src) {
- poly_nors_src = CustomData_get_layer(&me_src->pdata, CD_NORMAL);
- BLI_assert(poly_nors_src != NULL);
+ poly_nors_src = BKE_mesh_poly_normals_ensure(me_src);
}
if (need_lnors_src) {
loop_nors_src = CustomData_get_layer(&me_src->ldata, CD_NORMAL);
@@ -1648,7 +1635,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (mesh_remap_bvhtree_query_nearest(
tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) {
float(*nor_dst)[3];
- float(*nors_src)[3];
+ const float(*nors_src)[3];
float best_nor_dot = -2.0f;
float best_sqdist_fallback = FLT_MAX;
int best_index_src = -1;
@@ -2188,41 +2175,24 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
const SpaceTransform *space_transform,
const float max_dist,
const float ray_radius,
+ Mesh *mesh_dst,
MVert *verts_dst,
- const int numverts_dst,
MLoop *loops_dst,
- const int numloops_dst,
MPoly *polys_dst,
const int numpolys_dst,
- CustomData *pdata_dst,
- const bool dirty_nors_dst,
Mesh *me_src,
MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
const float max_dist_sq = max_dist * max_dist;
- float(*poly_nors_dst)[3] = NULL;
+ const float(*poly_nors_dst)[3] = NULL;
float tmp_co[3], tmp_no[3];
int i;
BLI_assert(mode & MREMAP_MODE_POLY);
if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) {
- /* Cache poly nors into a temp CDLayer. */
- poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
- if (!poly_nors_dst) {
- poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, numpolys_dst);
- CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst) {
- BKE_mesh_calc_normals_poly(verts_dst,
- numverts_dst,
- loops_dst,
- numloops_dst,
- polys_dst,
- numpolys_dst,
- poly_nors_dst);
- }
+ poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst);
}
BKE_mesh_remap_init(r_map, numpolys_dst);
diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c
index 45c84ed0862..39dbd7d66a4 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.c
+++ b/source/blender/blenkernel/intern/mesh_runtime.c
@@ -53,6 +53,8 @@ static void mesh_runtime_init_mutexes(Mesh *mesh)
{
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
+ mesh->runtime.normals_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime normals_mutex");
+ BLI_mutex_init(mesh->runtime.normals_mutex);
mesh->runtime.render_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime render_mutex");
BLI_mutex_init(mesh->runtime.render_mutex);
}
@@ -67,6 +69,11 @@ static void mesh_runtime_free_mutexes(Mesh *mesh)
MEM_freeN(mesh->runtime.eval_mutex);
mesh->runtime.eval_mutex = NULL;
}
+ if (mesh->runtime.normals_mutex != NULL) {
+ BLI_mutex_end(mesh->runtime.normals_mutex);
+ MEM_freeN(mesh->runtime.normals_mutex);
+ mesh->runtime.normals_mutex = NULL;
+ }
if (mesh->runtime.render_mutex != NULL) {
BLI_mutex_end(mesh->runtime.render_mutex);
MEM_freeN(mesh->runtime.render_mutex);
diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c
index c7a1b22dad1..73cef6b925b 100644
--- a/source/blender/blenkernel/intern/mesh_tangent.c
+++ b/source/blender/blenkernel/intern/mesh_tangent.c
@@ -224,7 +224,8 @@ typedef struct {
MLoopUV *mloopuv; /* texture coordinates */
const MPoly *mpoly; /* indices */
const MLoop *mloop; /* indices */
- const MVert *mvert; /* vertices & normals */
+ const MVert *mvert; /* vertex coordinates */
+ const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
int numTessFaces;
@@ -398,8 +399,7 @@ finally:
}
}
else {
- const short *no = pMesh->mvert[pMesh->mloop[loop_index].v].no;
- normal_short_to_float_v3(r_no, no);
+ copy_v3_v3(r_no, pMesh->vert_normals[pMesh->mloop[loop_index].v]);
}
}
@@ -557,6 +557,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
bool calc_active_tangent,
const char (*tangent_names)[MAX_NAME],
int tangent_names_len,
+ const float (*vert_normals)[3],
const float (*poly_normals)[3],
const float (*loop_normals)[3],
const float (*vert_orco)[3],
@@ -651,6 +652,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
mesh2tangent->num_face_as_quad_map = num_face_as_quad_map;
#endif
mesh2tangent->mvert = mvert;
+ mesh2tangent->vert_normals = vert_normals;
mesh2tangent->mpoly = mpoly;
mesh2tangent->mloop = mloop;
mesh2tangent->looptri = looptri;
@@ -743,7 +745,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
calc_active_tangent,
tangent_names,
tangent_names_len,
- CustomData_get_layer(&me_eval->pdata, CD_NORMAL),
+ BKE_mesh_vertex_normals_ensure(me_eval),
+ BKE_mesh_poly_normals_ensure(me_eval),
CustomData_get_layer(&me_eval->ldata, CD_NORMAL),
CustomData_get_layer(&me_eval->vdata, CD_ORCO), /* may be NULL */
/* result */
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index ba86c0fd449..f11e8b3f93c 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -303,6 +303,12 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
recalc_flag.edges = do_fixes;
}
+ const float(*vert_normals)[3] = NULL;
+ BKE_mesh_assert_normals_dirty_or_calculated(mesh);
+ if (!BKE_mesh_vertex_normals_are_dirty(mesh)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
+
for (i = 0; i < totvert; i++, mv++) {
bool fix_normal = true;
@@ -317,13 +323,13 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
}
}
- if (mv->no[j] != 0) {
+ if (vert_normals && vert_normals[i][j] != 0.0f) {
fix_normal = false;
break;
}
}
- if (fix_normal) {
+ if (vert_normals && fix_normal) {
/* If the vertex normal accumulates to zero or isn't part of a face, the location is used.
* When the location is also zero, a zero normal warning should not be raised.
* since this is the expected behavior of normal calculation.
@@ -336,7 +342,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
if (!is_zero_v3(mv->co)) {
PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i);
if (do_fixes) {
- mv->no[2] = SHRT_MAX;
+ float *normal = (float *)vert_normals[i];
+ normal[2] = 1.0f;
fix_flag.verts = true;
}
}
@@ -1003,6 +1010,11 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata,
mask = CD_MASK_MESH;
}
+ /* Normal data isn't in the mask since it is derived data,
+ * but it is valid and should not be removed. */
+ mask.vmask |= CD_MASK_NORMAL;
+ mask.pmask |= CD_MASK_NORMAL;
+
is_valid &= mesh_validate_customdata(
vdata, mask.vmask, totvert, do_verbose, do_fixes, &is_change_v);
is_valid &= mesh_validate_customdata(
@@ -1098,6 +1110,8 @@ bool BKE_mesh_is_valid(Mesh *me)
bool is_valid = true;
bool changed = true;
+ BKE_mesh_assert_normals_dirty_or_calculated(me);
+
is_valid &= BKE_mesh_validate_all_customdata(
&me->vdata,
me->totvert,
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index f3b6c2544bf..3f9faa415cb 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -984,7 +984,6 @@ struct Mesh *BKE_modifier_modify_mesh(ModifierData *md,
struct Mesh *me)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
if ((mti->flags & eModifierTypeFlag_AcceptsBMesh) == 0) {
@@ -1005,8 +1004,6 @@ void BKE_modifier_deform_verts(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
modwrap_dependsOnNormals(me);
}
@@ -1021,8 +1018,6 @@ void BKE_modifier_deform_vertsEM(ModifierData *md,
int numVerts)
{
const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
- BLI_assert(!me || CustomData_has_layer(&me->pdata, CD_NORMAL) == false);
-
if (me && mti->dependsOnNormals && mti->dependsOnNormals(md)) {
BKE_mesh_calc_normals(me);
}
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 05b20a6879c..5dcb753abf4 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -461,6 +461,7 @@ struct VertexDupliData_Mesh {
int totvert;
const MVert *mvert;
+ const float (*vert_normals)[3];
const float (*orco)[3];
};
@@ -558,12 +559,9 @@ static void make_child_duplis_verts_from_mesh(const DupliContext *ctx,
float child_imat[4][4];
mul_m4_m4m4(child_imat, inst_ob->imat, ctx->object->obmat);
- const MVert *mv = mvert;
- for (int i = 0; i < totvert; i++, mv++) {
- const float *co = mv->co;
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- DupliObject *dob = vertex_dupli(vdd->params.ctx, inst_ob, child_imat, i, co, no, use_rotation);
+ for (int i = 0; i < totvert; i++) {
+ DupliObject *dob = vertex_dupli(
+ vdd->params.ctx, inst_ob, child_imat, i, mvert[i].co, vdd->vert_normals[i], use_rotation);
if (vdd->orco) {
copy_v3_v3(dob->orco, vdd->orco[i]);
}
@@ -640,6 +638,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.params = vdd_params;
vdd.totvert = me_eval->totvert;
vdd.mvert = me_eval->mvert;
+ vdd.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval);
vdd.orco = (const float(*)[3])CustomData_get_layer(&me_eval->vdata, CD_ORCO);
make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh);
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 4c0d0303c1f..904fe9be51f 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -175,6 +175,11 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
cddata_masks.fmask |= CD_MASK_PROP_ALL;
cddata_masks.pmask |= CD_MASK_PROP_ALL;
cddata_masks.lmask |= CD_MASK_PROP_ALL;
+
+ /* Also copy over normal layers to avoid recomputation. */
+ cddata_masks.pmask |= CD_MASK_NORMAL;
+ cddata_masks.vmask |= CD_MASK_NORMAL;
+
/* Make sure Freestyle edge/face marks appear in DM for render (see T40315).
* Due to Line Art implementation, edge marks should also be shown in viewport. */
#ifdef WITH_FREESTYLE
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 674f264feb7..4dba13ce4c2 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -1674,6 +1674,7 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
/************************************************/
void psys_interpolate_face(MVert *mvert,
+ const float (*vert_normals)[3],
MFace *mface,
MTFace *tface,
float (*orcodata)[3],
@@ -1695,13 +1696,13 @@ void psys_interpolate_face(MVert *mvert,
v2 = mvert[mface->v2].co;
v3 = mvert[mface->v3].co;
- normal_short_to_float_v3(n1, mvert[mface->v1].no);
- normal_short_to_float_v3(n2, mvert[mface->v2].no);
- normal_short_to_float_v3(n3, mvert[mface->v3].no);
+ copy_v3_v3(n1, vert_normals[mface->v1]);
+ copy_v3_v3(n2, vert_normals[mface->v2]);
+ copy_v3_v3(n3, vert_normals[mface->v3]);
if (mface->v4) {
v4 = mvert[mface->v4].co;
- normal_short_to_float_v3(n4, mvert[mface->v4].no);
+ copy_v3_v3(n4, vert_normals[mface->v4]);
interp_v3_v3v3v3v3(vec, v1, v2, v3, v4, w);
@@ -2124,13 +2125,13 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
orcodata = CustomData_get_layer(&mesh_final->vdata, CD_ORCO);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh_final);
if (from == PART_FROM_VERT) {
copy_v3_v3(vec, mesh_final->mvert[mapindex].co);
if (nor) {
- normal_short_to_float_v3(nor, mesh_final->mvert[mapindex].no);
- normalize_v3(nor);
+ copy_v3_v3(nor, vert_normals[mapindex]);
}
if (orco) {
@@ -2161,7 +2162,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
}
if (from == PART_FROM_VOLUME) {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, tmpnor, utan, vtan, orco);
if (nor) {
copy_v3_v3(nor, tmpnor);
}
@@ -2173,7 +2175,8 @@ void psys_particle_on_dm(Mesh *mesh_final,
add_v3_v3(vec, tmpnor);
}
else {
- psys_interpolate_face(mvert, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
+ psys_interpolate_face(
+ mvert, vert_normals, mface, mtface, orcodata, mapfw, vec, nor, utan, vtan, orco);
}
}
}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index fd4f89e3f6d..ba3f99a2800 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -626,7 +626,8 @@ static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa,
/* experimental */
tot = mesh->totface;
- psys_interpolate_face(mvert, mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
+ psys_interpolate_face(
+ mvert, BKE_mesh_vertex_normals_ensure(mesh), mface, 0, 0, pa->fuv, co, nor, 0, 0, 0);
normalize_v3(nor);
negate_v3(nor);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 2f22f94d142..ce27fdd28a0 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -32,7 +32,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_ccg.h"
-#include "BKE_mesh.h" /* for BKE_mesh_calc_normals */
+#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
#include "BKE_subdiv_ccg.h"
@@ -552,7 +552,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
}
void BKE_pbvh_build_mesh(PBVH *pbvh,
- const Mesh *mesh,
+ Mesh *mesh,
const MPoly *mpoly,
const MLoop *mloop,
MVert *verts,
@@ -572,6 +572,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mloop = mloop;
pbvh->looptri = looptri;
pbvh->verts = verts;
+ BKE_mesh_vertex_normals_ensure(mesh);
+ pbvh->vert_normals = BKE_mesh_vertex_normals_for_write(mesh);
pbvh->vert_bitmap = BLI_BITMAP_NEW(totvert, "bvh->vert_bitmap");
pbvh->totvert = totvert;
pbvh->leaf_limit = LEAF_LIMIT;
@@ -1076,7 +1078,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
* so we know only this thread will handle this vertex. */
if (mvert->flag & ME_VERT_PBVH_UPDATE) {
normalize_v3(vnors[v]);
- normal_float_to_short_v3(mvert->no, vnors[v]);
mvert->flag &= ~ME_VERT_PBVH_UPDATE;
}
}
@@ -1087,10 +1088,6 @@ static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
{
- /* could be per node to save some memory, but also means
- * we have to store for each vertex which node it is in */
- float(*vnors)[3] = MEM_callocN(sizeof(*vnors) * pbvh->totvert, __func__);
-
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
* adjacent to these vertices have been marked with PBVH_UpdateNormals.
@@ -1104,7 +1101,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
PBVHUpdateData data = {
.pbvh = pbvh,
.nodes = nodes,
- .vnors = vnors,
+ .vnors = pbvh->vert_normals,
};
TaskParallelSettings settings;
@@ -1112,8 +1109,6 @@ static void pbvh_faces_update_normals(PBVH *pbvh, PBVHNode **nodes, int totnode)
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_accum_task_cb, &settings);
BLI_task_parallel_range(0, totnode, &data, pbvh_update_normals_store_task_cb, &settings);
-
- MEM_freeN(vnors);
}
static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
@@ -1300,6 +1295,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
case PBVH_FACES:
GPU_pbvh_mesh_buffers_update(node->draw_buffers,
pbvh->verts,
+ pbvh->vert_normals,
CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK),
CustomData_get_layer(pbvh->ldata, CD_MLOOPCOL),
CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
@@ -2964,6 +2960,9 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m
vi->mask = NULL;
if (pbvh->type == PBVH_FACES) {
+ /* Cast away const because sculpt/paint code can adjust normals when restoring mesh data. */
+ vi->vert_normals = pbvh->vert_normals;
+
vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK);
vi->vcol = CustomData_get_layer(pbvh->vdata, CD_PROP_COLOR);
}
@@ -3037,6 +3036,12 @@ MVert *BKE_pbvh_get_verts(const PBVH *pbvh)
return pbvh->verts;
}
+const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]
+{
+ BLI_assert(pbvh->type == PBVH_FACES);
+ return pbvh->vert_normals;
+}
+
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg)
{
pbvh->subdiv_ccg = subdiv_ccg;
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 12c2d7aac78..9562cda5f28 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -130,6 +130,9 @@ struct PBVH {
/* Mesh data */
const struct Mesh *mesh;
+
+ /* Note: Normals are not const because they can be updated for drawing by sculpt code. */
+ float (*vert_normals)[3];
MVert *verts;
const MPoly *mpoly;
const MLoop *mloop;
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 7618323f488..d51ed2832f0 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -75,7 +75,8 @@ typedef struct ShrinkwrapCalcData {
struct Object *ob; /* object we are applying shrinkwrap to */
- struct MVert *vert; /* Array of verts being projected (to fetch normals or other data) */
+ struct MVert *vert; /* Array of verts being projected. */
+ const float (*vert_normals)[3];
float (*vertexCos)[3]; /* vertexs being shrinkwraped */
int numVerts;
@@ -146,7 +147,7 @@ bool BKE_shrinkwrap_init_tree(
}
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
- data->pnors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ data->pnors = BKE_mesh_poly_normals_ensure(mesh);
if ((mesh->flag & ME_AUTOSMOOTH) != 0) {
data->clnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL);
}
@@ -313,18 +314,18 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(struct Mesh *mesh)
MEM_freeN(vert_status);
/* Finalize average direction and compute normal. */
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
for (int i = 0; i < mesh->totvert; i++) {
int bidx = vert_boundary_id[i];
if (bidx >= 0) {
ShrinkwrapBoundaryVertData *vdata = &boundary_verts[bidx];
- float no[3], tmp[3];
+ float tmp[3];
normalize_v3(vdata->direction);
- normal_short_to_float_v3(no, mesh->mvert[i].no);
- cross_v3_v3v3(tmp, no, vdata->direction);
- cross_v3_v3v3(vdata->normal_plane, tmp, no);
+ cross_v3_v3v3(tmp, vert_normals[i], vdata->direction);
+ cross_v3_v3v3(vdata->normal_plane, tmp, vert_normals[i]);
normalize_v3(vdata->normal_plane);
}
}
@@ -540,7 +541,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(void *__restrict userdata,
* (to get correct normals) for other cases calc->verts contains undeformed coordinates and
* vertexCos should be used */
copy_v3_v3(tmp_co, calc->vert[i].co);
- normal_short_to_float_v3(tmp_no, calc->vert[i].no);
+ copy_v3_v3(tmp_no, calc->vert_normals[i]);
}
else {
copy_v3_v3(tmp_co, co);
@@ -1008,8 +1009,8 @@ static void target_project_edge(const ShrinkwrapTreeData *tree,
CLAMP(x, 0, 1);
float vedge_no[2][3];
- normal_short_to_float_v3(vedge_no[0], data->vert[edge->v1].no);
- normal_short_to_float_v3(vedge_no[1], data->vert[edge->v2].no);
+ copy_v3_v3(vedge_no[0], data->vert_normals[edge->v1]);
+ copy_v3_v3(vedge_no[1], data->vert_normals[edge->v2]);
interp_v3_v3v3(hit_co, vedge_co[0], vedge_co[1], x);
interp_v3_v3v3(hit_no, vedge_no[0], vedge_no[1], x);
@@ -1055,9 +1056,9 @@ static void mesh_looptri_target_project(void *userdata,
}
/* Decode normals */
- normal_short_to_float_v3(vtri_no[0], vtri[0]->no);
- normal_short_to_float_v3(vtri_no[1], vtri[1]->no);
- normal_short_to_float_v3(vtri_no[2], vtri[2]->no);
+ copy_v3_v3(vtri_no[0], tree->treeData.vert_normals[loop[0]->v]);
+ copy_v3_v3(vtri_no[1], tree->treeData.vert_normals[loop[1]->v]);
+ copy_v3_v3(vtri_no[2], tree->treeData.vert_normals[loop[2]->v]);
/* Solve the equations for the triangle */
if (target_project_solve_point_tri(vtri_co, vtri_no, co, raw_hit_co, dist_sq, hit_co, hit_no)) {
@@ -1191,14 +1192,13 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
{
const BVHTreeFromMesh *treeData = &tree->treeData;
const MLoopTri *tri = &treeData->looptri[looptri_idx];
+ const float(*vert_normals)[3] = tree->treeData.vert_normals;
/* Interpolate smooth normals if enabled. */
if ((tree->mesh->mpoly[tri->poly].flag & ME_SMOOTH) != 0) {
- const MVert *verts[] = {
- &treeData->vert[treeData->loop[tri->tri[0]].v],
- &treeData->vert[treeData->loop[tri->tri[1]].v],
- &treeData->vert[treeData->loop[tri->tri[2]].v],
- };
+ const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v,
+ treeData->loop[tri->tri[1]].v,
+ treeData->loop[tri->tri[2]].v};
float w[3], no[3][3], tmp_co[3];
/* Custom and auto smooth split normals. */
@@ -1209,9 +1209,9 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
}
/* Ordinary vertex normals. */
else {
- normal_short_to_float_v3(no[0], verts[0]->no);
- normal_short_to_float_v3(no[1], verts[1]->no);
- normal_short_to_float_v3(no[2], verts[2]->no);
+ copy_v3_v3(no[0], vert_normals[vert_indices[0]]);
+ copy_v3_v3(no[1], vert_normals[vert_indices[1]]);
+ copy_v3_v3(no[2], vert_normals[vert_indices[2]]);
}
/* Barycentric weights from hit point. */
@@ -1221,7 +1221,11 @@ void BKE_shrinkwrap_compute_smooth_normal(const struct ShrinkwrapTreeData *tree,
BLI_space_transform_apply(transform, tmp_co);
}
- interp_weights_tri_v3(w, verts[0]->co, verts[1]->co, verts[2]->co, tmp_co);
+ interp_weights_tri_v3(w,
+ treeData->vert[vert_indices[0]].co,
+ treeData->vert[vert_indices[1]].co,
+ treeData->vert[vert_indices[2]].co,
+ tmp_co);
/* Interpolate using weights. */
interp_v3_v3v3v3(r_no, no[0], no[1], no[2], w);
@@ -1424,6 +1428,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
if (mesh != NULL && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) {
/* Setup arrays to get vertexs positions, normals and deform weights */
calc.vert = mesh->mvert;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
/* Using vertexs positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
@@ -1581,6 +1586,7 @@ void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object
calc.smd = &ssmd;
calc.numVerts = src_me->totvert;
calc.vertexCos = vertexCos;
+ calc.vert_normals = BKE_mesh_vertex_normals_ensure(src_me);
calc.vgroup = -1;
calc.target = target_me;
calc.keepDist = ssmd.keepDist;
diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c
index 51a2aa673bc..b15e18eaa17 100644
--- a/source/blender/blenkernel/intern/subdiv_eval.c
+++ b/source/blender/blenkernel/intern/subdiv_eval.c
@@ -297,18 +297,6 @@ void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
normalize_v3(r_N);
}
-void BKE_subdiv_eval_limit_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- float N_float[3];
- BKE_subdiv_eval_limit_point_and_normal(subdiv, ptex_face_index, u, v, r_P, N_float);
- normal_float_to_short_v3(r_N, N_float);
-}
-
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
const int face_varying_channel,
const int ptex_face_index,
@@ -364,12 +352,6 @@ static void buffer_write_float_value(void **buffer, const float *values_buffer,
memcpy(*buffer, values_buffer, sizeof(float) * num_values);
}
-/* Similar to above, just operates with short values. */
-static void buffer_write_short_value(void **buffer, const short *values_buffer, int num_values)
-{
- memcpy(*buffer, values_buffer, sizeof(short) * num_values);
-}
-
void BKE_subdiv_eval_limit_patch_resolution_point(Subdiv *subdiv,
const int ptex_face_index,
const int resolution,
@@ -444,30 +426,3 @@ void BKE_subdiv_eval_limit_patch_resolution_point_and_normal(Subdiv *subdiv,
}
}
}
-
-void BKE_subdiv_eval_limit_patch_resolution_point_and_short_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const int resolution,
- void *point_buffer,
- const int point_offset,
- const int point_stride,
- void *normal_buffer,
- const int normal_offset,
- const int normal_stride)
-{
- buffer_apply_offset(&point_buffer, point_offset);
- buffer_apply_offset(&normal_buffer, normal_offset);
- const float inv_resolution_1 = 1.0f / (float)(resolution - 1);
- for (int y = 0; y < resolution; y++) {
- const float v = y * inv_resolution_1;
- for (int x = 0; x < resolution; x++) {
- const float u = x * inv_resolution_1;
- short normal[3];
- BKE_subdiv_eval_limit_point_and_short_normal(
- subdiv, ptex_face_index, u, v, point_buffer, normal);
- buffer_write_short_value(&normal_buffer, normal, 3);
- buffer_apply_offset(&point_buffer, point_stride);
- buffer_apply_offset(&normal_buffer, normal_stride);
- }
- }
-}
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c
index 5bf519e5f70..c334d9a2c33 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_mesh.c
@@ -21,6 +21,7 @@
* \ingroup bke
*/
+#include "BKE_mesh.h"
#include "BKE_subdiv_mesh.h"
#include "atomic_ops.h"
@@ -58,23 +59,8 @@ typedef struct SubdivMeshContext {
/* UV layers interpolation. */
int num_uv_layers;
MLoopUV *uv_layers[MAX_MTFACE];
- /* Accumulated values.
- *
- * Averaging is happening for vertices along the coarse edges and corners.
- * This is needed for both displacement and normals.
- *
- * Displacement is being accumulated to a vertices coordinates, since those
- * are not needed during traversal of edge/corner vertices.
- *
- * For normals we are using dedicated array, since we can not use same
- * vertices (normals are `short`, which will cause a lot of precision
- * issues). */
- float (*accumulated_normals)[3];
/* Per-subdivided vertex counter of averaged values. */
int *accumulated_counters;
- /* Denotes whether normals can be evaluated from a limit surface. One case
- * when it's not possible is when displacement is used. */
- bool can_evaluate_normals;
bool have_displacement;
} SubdivMeshContext;
@@ -102,20 +88,12 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx)
static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices)
{
- if (!ctx->can_evaluate_normals && !ctx->have_displacement) {
- return;
- }
- /* TODO(sergey): Technically, this is overallocating, we don't need memory
- * for an inner subdivision vertices. */
- ctx->accumulated_normals = MEM_calloc_arrayN(
- num_vertices, sizeof(*ctx->accumulated_normals), "subdiv accumulated normals");
ctx->accumulated_counters = MEM_calloc_arrayN(
num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters");
}
static void subdiv_mesh_context_free(SubdivMeshContext *ctx)
{
- MEM_SAFE_FREE(ctx->accumulated_normals);
MEM_SAFE_FREE(ctx->accumulated_counters);
}
@@ -450,48 +428,23 @@ static void subdiv_mesh_tls_free(void *tls_v)
/** \} */
-/* -------------------------------------------------------------------- */
-/** \name Evaluation helper functions
- * \{ */
-
-static void eval_final_point_and_vertex_normal(Subdiv *subdiv,
- const int ptex_face_index,
- const float u,
- const float v,
- float r_P[3],
- short r_N[3])
-{
- if (subdiv->displacement_evaluator == NULL) {
- BKE_subdiv_eval_limit_point_and_short_normal(subdiv, ptex_face_index, u, v, r_P, r_N);
- }
- else {
- BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, r_P);
- }
-}
-
/** \} */
/* -------------------------------------------------------------------- */
/** \name Accumulation helpers
* \{ */
-static void subdiv_accumulate_vertex_normal_and_displacement(SubdivMeshContext *ctx,
- const int ptex_face_index,
- const float u,
- const float v,
- MVert *subdiv_vert)
+static void subdiv_accumulate_vertex_displacement(SubdivMeshContext *ctx,
+ const int ptex_face_index,
+ const float u,
+ const float v,
+ MVert *subdiv_vert)
{
Subdiv *subdiv = ctx->subdiv;
const int subdiv_vertex_index = subdiv_vert - ctx->subdiv_mesh->mvert;
float dummy_P[3], dPdu[3], dPdv[3], D[3];
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
- /* Accumulate normal. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- cross_v3_v3v3(N, dPdu, dPdv);
- normalize_v3(N);
- add_v3_v3(ctx->accumulated_normals[subdiv_vertex_index], N);
- }
+
/* Accumulate displacement if needed. */
if (ctx->have_displacement) {
/* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
@@ -589,13 +542,6 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
/* Remove facedot flag. This can happen if there is more than one subsurf modifier. */
subdiv_vert->flag &= ~ME_VERT_FACEDOT;
}
@@ -622,15 +568,6 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co);
/* Apply displacement. */
add_v3_v3(subdiv_vert->co, D);
- /* Copy normal from accumulated storage. */
- if (ctx->can_evaluate_normals) {
- const float inv_num_accumulated = 1.0f / ctx->accumulated_counters[subdiv_vertex_index];
- float N[3];
- copy_v3_v3(N, ctx->accumulated_normals[subdiv_vertex_index]);
- mul_v3_fl(N, inv_num_accumulated);
- normalize_v3(N);
- normal_float_to_short_v3(subdiv_vert->no, N);
- }
}
static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *foreach_context,
@@ -644,7 +581,7 @@ static void subdiv_mesh_vertex_every_corner_or_edge(const SubdivForeachContext *
Mesh *subdiv_mesh = ctx->subdiv_mesh;
MVert *subdiv_mvert = subdiv_mesh->mvert;
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
- subdiv_accumulate_vertex_normal_and_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
+ subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vert);
}
static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
@@ -793,8 +730,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index];
subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_poly, coarse_corner);
subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v);
- eval_final_point_and_vertex_normal(
- subdiv, ptex_face_index, u, v, subdiv_vert->co, subdiv_vert->no);
+ BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_vert->co);
subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vert, u, v);
}
@@ -1141,12 +1077,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *
/* TODO(sergey): This matches old behavior, but we can as well interpolate
* it. Maybe even using vertex varying attributes. */
subdiv_vertex->bweight = 0.0f;
- /* Reset normal, initialize it in a similar way as edit mode does for a
- * vertices adjacent to a loose edges.
- * See `mesh_evaluate#mesh_calc_normals_vert_fallback` */
- float no[3];
- normalize_v3_v3(no, subdiv_vertex->co);
- normal_float_to_short_v3(subdiv_vertex->no, no);
}
/** \} */
@@ -1161,8 +1091,8 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
memset(foreach_context, 0, sizeof(*foreach_context));
/* General information. */
foreach_context->topology_info = subdiv_mesh_topology_info;
- /* Every boundary geometry. Used for displacement and normals averaging. */
- if (subdiv_context->can_evaluate_normals || subdiv_context->have_displacement) {
+ /* Every boundary geometry. Used for displacement averaging. */
+ if (subdiv_context->have_displacement) {
foreach_context->vertex_every_corner = subdiv_mesh_vertex_every_corner;
foreach_context->vertex_every_edge = subdiv_mesh_vertex_every_edge;
}
@@ -1212,8 +1142,6 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
subdiv_context.coarse_mesh = coarse_mesh;
subdiv_context.subdiv = subdiv;
subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL);
- subdiv_context.can_evaluate_normals = !subdiv_context.have_displacement &&
- subdiv_context.subdiv->settings.is_adaptive;
/* Multi-threaded traversal/evaluation. */
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
SubdivForeachContext foreach_context;
@@ -1227,9 +1155,11 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
Mesh *result = subdiv_context.subdiv_mesh;
// BKE_mesh_validate(result, true, true);
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
- if (!subdiv_context.can_evaluate_normals) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ /* Using normals from the limit surface gives different results than Blender's vertex normal
+ * calculation. Since vertex normals are supposed to be a consistent cache, don't bother
+ * calculating them here. The work may have been pointless anyway if the mesh is deformed or
+ * changed afterwards. */
+ BKE_mesh_normals_tag_dirty(result);
/* Free used memory. */
subdiv_mesh_context_free(&subdiv_context);
return result;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 2669da98488..9d66c354b54 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -803,17 +803,11 @@ static int ccgDM_getNumLoops(DerivedMesh *dm)
return 4 * ccgSubSurf_getNumFinalFaces(ccgdm->ss);
}
-static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
+static CCGElem *get_vertex_elem(CCGDerivedMesh *ccgdm, int vertNum)
{
- CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
CCGSubSurf *ss = ccgdm->ss;
- CCGElem *vd;
- CCGKey key;
int i;
- CCG_key_top_level(&key, ss);
- memset(mv, 0, sizeof(*mv));
-
if ((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
/* this vert comes from face data */
int lastface = ccgSubSurf_getNumFaces(ss) - 1;
@@ -842,30 +836,24 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
offset = vertNum - ccgdm->faceMap[i].startVert;
if (offset < 1) {
- vd = ccgSubSurf_getFaceCenterData(f);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceCenterData(f);
}
- else if (offset < gridSideEnd) {
+ if (offset < gridSideEnd) {
offset -= 1;
grid = offset / gridSideVerts;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x);
}
- else if (offset < gridInternalEnd) {
+ if (offset < gridInternalEnd) {
offset -= gridSideEnd;
grid = offset / gridInternalVerts;
offset %= gridInternalVerts;
y = offset / gridSideVerts + 1;
x = offset % gridSideVerts + 1;
- vd = ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getFaceGridData(ss, f, grid, x, y);
}
}
- else if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+ if ((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
/* this vert comes from edge data */
CCGEdge *e;
int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
@@ -879,36 +867,37 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
e = ccgdm->edgeMap[i].edge;
x = vertNum - ccgdm->edgeMap[i].startVert + 1;
- vd = ccgSubSurf_getEdgeData(ss, e, x);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
+ return ccgSubSurf_getEdgeData(ss, e, x);
}
- else {
- /* this vert comes from vert data */
- CCGVert *v;
- i = vertNum - ccgdm->vertMap[0].startVert;
- v = ccgdm->vertMap[i].vert;
- vd = ccgSubSurf_getVertData(ss, v);
- copy_v3_v3(mv->co, CCG_elem_co(&key, vd));
- normal_float_to_short_v3(mv->no, CCG_elem_no(&key, vd));
- }
+ /* this vert comes from vert data */
+ CCGVert *v;
+ i = vertNum - ccgdm->vertMap[0].startVert;
+
+ v = ccgdm->vertMap[i].vert;
+ return ccgSubSurf_getVertData(ss, v);
}
static void ccgDM_getFinalVertCo(DerivedMesh *dm, int vertNum, float r_co[3])
{
- MVert mvert;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- copy_v3_v3(r_co, mvert.co);
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_co, CCG_elem_co(&key, vd));
}
static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
{
- MVert mvert;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+ CCGSubSurf *ss = ccgdm->ss;
- ccgDM_getFinalVert(dm, vertNum, &mvert);
- normal_short_to_float_v3(r_no, mvert.no);
+ CCGElem *vd = get_vertex_elem(ccgdm, vertNum);
+ CCGKey key;
+ CCG_key_top_level(&key, ss);
+ copy_v3_v3(r_no, CCG_elem_no(&key, vd));
}
void subsurf_copy_grid_hidden(DerivedMesh *dm,
@@ -995,7 +984,6 @@ void subsurf_copy_grid_paint_mask(DerivedMesh *dm,
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- normal_float_to_short_v3(mv->no, CCG_elem_no(key, elem));
mv->flag = mv->bweight = 0;
}
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 5e997d94acf..1ed8d4fc005 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -145,7 +145,6 @@ MINLINE void add_v4_v4(float r[4], const float a[4]);
MINLINE void add_v4_v4v4(float r[4], const float a[4], const float b[4]);
MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3]);
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3]);
MINLINE void sub_v2_v2(float r[2], const float a[2]);
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2]);
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 648f876acaa..3022dbbe4ff 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -438,13 +438,6 @@ MINLINE void add_v3fl_v3fl_v3i(float r[3], const float a[3], const int b[3])
r[2] = a[2] + (float)b[2];
}
-MINLINE void add_v3fl_v3fl_v3s(float r[3], const float a[3], const short b[3])
-{
- r[0] = a[0] + (float)b[0];
- r[1] = a[1] + (float)b[1];
- r[2] = a[2] + (float)b[2];
-}
-
MINLINE void add_v4_v4(float r[4], const float a[4])
{
r[0] += a[0];
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index e667505caca..edcd9159520 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -109,7 +109,7 @@ struct BMLog {
typedef struct {
float co[3];
- short no[3];
+ float no[3];
char hflag;
float mask;
} BMLogVert;
@@ -200,7 +200,7 @@ static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mas
static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
{
copy_v3_v3(lv->co, v->co);
- normal_float_to_short_v3(lv->no, v->no);
+ copy_v3_v3(lv->no, v->no);
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
lv->hflag = v->head.hflag;
}
@@ -294,7 +294,7 @@ static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
BMVert *v = BM_vert_create(bm, lv->co, NULL, BM_CREATE_NOP);
vert_mask_set(v, lv->mask, cd_vert_mask_offset);
v->head.hflag = lv->hflag;
- normal_short_to_float_v3(v->no, lv->no);
+ copy_v3_v3(v->no, lv->no);
bm_log_vert_id_set(log, v, POINTER_AS_UINT(key));
}
}
@@ -329,12 +329,9 @@ static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
uint id = POINTER_AS_UINT(key);
BMVert *v = bm_log_vert_from_id(log, id);
float mask;
- short normal[3];
swap_v3_v3(v->co, lv->co);
- copy_v3_v3_short(normal, lv->no);
- normal_float_to_short_v3(lv->no, v->no);
- normal_short_to_float_v3(v->no, normal);
+ swap_v3_v3(v->no, lv->no);
SWAP(char, v->head.hflag, lv->hflag);
mask = lv->mask;
lv->mask = vert_mask_get(v, cd_vert_mask_offset);
@@ -937,7 +934,7 @@ const float *BM_log_original_vert_co(BMLog *log, BMVert *v)
return lv->co;
}
-const short *BM_log_original_vert_no(BMLog *log, BMVert *v)
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
@@ -967,7 +964,7 @@ float BM_log_original_mask(BMLog *log, BMVert *v)
return lv->mask;
}
-void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no)
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
{
BMLogEntry *entry = log->current_entry;
const BMLogVert *lv;
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 1cc860beed1..935cb5aba28 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -196,11 +196,10 @@ void BM_log_before_all_removed(BMesh *bm, BMLog *log);
* Does not modify the log or the vertex */
const float *BM_log_original_vert_co(BMLog *log, BMVert *v);
-/* Get the logged normal of a vertex */
/* Get the logged normal of a vertex
*
* Does not modify the log or the vertex */
-const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
+const float *BM_log_original_vert_no(BMLog *log, BMVert *v);
/* Get the logged mask of a vertex */
/* Get the logged mask of a vertex
@@ -209,7 +208,7 @@ const short *BM_log_original_vert_no(BMLog *log, BMVert *v);
float BM_log_original_mask(BMLog *log, BMVert *v);
/* Get the logged data of a vertex (avoid multiple lookups) */
-void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const short **r_no);
+void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no);
/* For internal use only (unit testing) */
/* For internal use only (unit testing) */
diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.c b/source/blender/bmesh/intern/bmesh_mesh_convert.c
index 544a81f7020..d99fefbcd02 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_convert.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_convert.c
@@ -208,6 +208,14 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
return; /* Sanity check. */
}
+ /* Only copy normals to the new BMesh if they are not already dirty. This avoids unnecessary
+ * work, but also accessing normals on an incomplete mesh, for example when restoring undo steps
+ * in edit mode. */
+ const float(*vert_normals)[3] = NULL;
+ if (!BKE_mesh_vertex_normals_are_dirty(me)) {
+ vert_normals = BKE_mesh_vertex_normals_ensure(me);
+ }
+
if (is_new) {
CustomData_copy(&me->vdata, &bm->vdata, mask.vmask, CD_CALLOC, 0);
CustomData_copy(&me->edata, &bm->edata, mask.emask, CD_CALLOC, 0);
@@ -334,7 +342,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_vert_select_set(bm, v, true);
}
- normal_short_to_float_v3(v->no, mvert->no);
+ if (vert_normals) {
+ copy_v3_v3(v->no, vert_normals[i]);
+ }
/* Copy Custom Data */
CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data, true);
@@ -639,6 +649,10 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+ /* There is no way to tell if BMesh normals are dirty or not. Instead of calculating the normals
+ * on the BMesh possibly unnecessarily, just tag them dirty on the resulting mesh. */
+ BKE_mesh_normals_tag_dirty(me);
+
me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm);
/* This is called again, 'dotess' arg is used there. */
@@ -647,7 +661,6 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
copy_v3_v3(mvert->co, v->co);
- normal_float_to_short_v3(mvert->no, v->no);
mvert->flag = BM_vert_flag_to_mflag(v);
@@ -1041,6 +1054,8 @@ 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);
+
me->runtime.deformed_only = true;
/* Don't add origindex layer if one already exists. */
@@ -1055,8 +1070,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
BM_elem_index_set(eve, i); /* set_inline */
- normal_float_to_short_v3(mv->no, eve->no);
-
mv->flag = BM_vert_flag_to_mflag(eve);
if (cd_vert_bweight_offset != -1) {
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
index 8b0fbf86360..df1758fc1a2 100644
--- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
+++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.c
@@ -379,14 +379,15 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (mr->extract_type != MR_EXTRACT_BMESH) {
/* Mesh */
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mr->me);
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
- BKE_mesh_ensure_normals_for_display(mr->me);
- mr->poly_normals = CustomData_get_layer(&mr->me->pdata, CD_NORMAL);
+ mr->poly_normals = BKE_mesh_poly_normals_ensure(mr->me);
}
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
mr->loop_normals = MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__);
short(*clnors)[2] = CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL);
BKE_mesh_normals_loop_split(mr->me->mvert,
+ mr->vert_normals,
mr->vert_len,
mr->me->medge,
mr->edge_len,
diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
index 372566a8f90..6eb1fbf26fa 100644
--- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc
+++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc
@@ -23,6 +23,7 @@
#include "DNA_scene_types.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -1668,6 +1669,7 @@ void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
mr->mvert = mesh->mvert;
mr->mpoly = mesh->mpoly;
mr->mloop = mesh->mloop;
+ mr->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
mr->vert_len = mesh->totvert;
mr->edge_len = mesh->totedge;
mr->poly_len = mesh->totpoly;
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
index 2db8f721e76..7c6f4dea6c9 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h
@@ -100,8 +100,9 @@ typedef struct MeshRenderData {
BMFace *efa_act_uv;
/* Data created on-demand (usually not for #BMesh based data). */
MLoopTri *mlooptri;
+ const float (*vert_normals)[3];
+ const float (*poly_normals)[3];
float (*loop_normals)[3];
- float (*poly_normals)[3];
int *lverts, *ledges;
struct {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
index 5ee34d7fdb2..8470a71059f 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc
@@ -149,9 +149,8 @@ static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr,
const MLoop *ml_next = &mr->mloop[ml_index_other];
const MVert *v1 = &mr->mvert[ml->v];
const MVert *v2 = &mr->mvert[ml_next->v];
- float vnor_f[3];
- normal_short_to_float_v3(vnor_f, v1->no);
- float ratio = loop_edge_factor_get(mr->poly_normals[mp_index], v1->co, vnor_f, v2->co);
+ float ratio = loop_edge_factor_get(
+ mr->poly_normals[mp_index], v1->co, mr->vert_normals[ml->v], v2->co);
data->vbo_data[ml_index] = ratio * 253 + 1;
}
else {
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
index d30c38ef050..93b94b210b2 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc
@@ -87,7 +87,7 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- *lnor_data = GPU_normal_convert_i10_s3(mr->mvert[ml->v].no);
+ *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
@@ -210,7 +210,7 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
- copy_v3_v3_short(&lnor_data->x, mr->mvert[ml->v].no);
+ normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
index 33a33c81bc2..706c6ad5403 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_mesh_analysis.cc
@@ -460,7 +460,7 @@ static void statvis_calc_distort(const MeshRenderData *mr, float *r_distort)
float fac = -1.0f;
if (mp->totloop > 3) {
- float *f_no = mr->poly_normals[mp_index];
+ const float *f_no = mr->poly_normals[mp_index];
fac = 0.0f;
for (int i = 1; i <= mp->totloop; i++) {
@@ -555,7 +555,7 @@ static void statvis_calc_sharp(const MeshRenderData *mr, float *r_sharp)
void **pval;
bool value_is_init = BLI_edgehash_ensure_p(eh, l_curr->v, l_next->v, &pval);
if (!value_is_init) {
- *pval = mr->poly_normals[mp_index];
+ *pval = (void *)mr->poly_normals[mp_index];
/* non-manifold edge, yet... */
continue;
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
index 00ed4ca6359..5d2ea923658 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc
@@ -74,9 +74,8 @@ static void extract_pos_nor_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- data->normals[v].low = GPU_normal_convert_i10_s3(mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ data->normals[v].low = GPU_normal_convert_i10_v3(mr->vert_normals[v]);
}
}
}
@@ -255,7 +254,7 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
}
static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
- const MeshRenderData *UNUSED(mr),
+ const MeshRenderData *mr,
const MeshExtractLooseGeom *loose_geom,
void *buffer,
void *UNUSED(data))
@@ -285,11 +284,11 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache
const MVert *loose_vert2 = &coarse_verts[loose_edge->v2];
copy_v3_v3(edge_data[0].pos, loose_vert1->co);
- normal_short_to_float_v3(edge_data[0].nor, loose_vert1->no);
+ copy_v3_v3(edge_data[0].nor, mr->vert_normals[loose_edge->v1]);
edge_data[0].flag = 0.0f;
copy_v3_v3(edge_data[1].pos, loose_vert2->co);
- normal_short_to_float_v3(edge_data[1].nor, loose_vert2->no);
+ copy_v3_v3(edge_data[1].nor, mr->vert_normals[loose_edge->v2]);
edge_data[1].flag = 0.0f;
GPU_vertbuf_update_sub(
@@ -304,7 +303,7 @@ static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache
const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]];
copy_v3_v3(vert_data.pos, loose_vertex->co);
- normal_short_to_float_v3(vert_data.nor, loose_vertex->no);
+ copy_v3_v3(vert_data.nor, mr->vert_normals[loose_geom->verts[i]]);
GPU_vertbuf_update_sub(
vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data);
@@ -380,9 +379,8 @@ static void extract_pos_nor_hq_init(const MeshRenderData *mr,
}
}
else {
- const MVert *mv = mr->mvert;
- for (int v = 0; v < mr->vert_len; v++, mv++) {
- copy_v3_v3_short(data->normals[v].high, mv->no);
+ for (int v = 0; v < mr->vert_len; v++) {
+ normal_float_to_short_v3(data->normals[v].high, mr->vert_normals[v]);
}
}
}
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
index 7a3b2cf49ff..03d1b327689 100644
--- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
+++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc
@@ -138,6 +138,7 @@ static void extract_tan_ex_init(const MeshRenderData *mr,
calc_active_tangent,
tangent_names,
tan_len,
+ mr->vert_normals,
mr->poly_normals,
mr->loop_normals,
orco,
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 990e7589d9d..787d7cbaab0 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1618,8 +1618,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin
mdb->cagemesh_cache.mpoly = me->mpoly;
mdb->cagemesh_cache.mloop = me->mloop;
mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me);
- /* can be NULL */
- mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL);
+ mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me);
}
/* make bounding box equal size in all directions, add padding, and compute
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index d7d1dc7dcae..0f58752f323 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -1019,11 +1019,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve autosmooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
- float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
-
- BKE_mesh_calc_normals_poly(
- me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors);
-
BKE_edges_sharp_from_angle_set(me->mvert,
me->totvert,
me->medge,
@@ -1031,11 +1026,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
me->mloop,
me->totloop,
me->mpoly,
- polynors,
+ BKE_mesh_poly_normals_ensure(me),
me->totpoly,
me->smoothresh);
-
- MEM_freeN(polynors);
}
CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index ebe8b758aa2..c9615698c46 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -1363,8 +1363,7 @@ typedef struct VertPickData {
static void ed_mesh_pick_vert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
VertPickData *data = userData;
if ((data->mvert[index].flag & ME_HIDE) == 0) {
diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc
index 4737de4d8fa..e4103db8e21 100644
--- a/source/blender/editors/object/object_remesh.cc
+++ b/source/blender/editors/object/object_remesh.cc
@@ -168,8 +168,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
new_mesh = mesh_fixed_poles;
}
- BKE_mesh_calc_normals(new_mesh);
-
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK ||
mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) {
BKE_mesh_runtime_clear_geometry(mesh);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f1e6f02cb39..ea35ad6dcd0 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -1463,26 +1463,28 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
vec = edit->emitter_cosnos;
nor = vec + 3;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
for (i = 0; i < totface; i++, vec += 6, nor += 6) {
MFace *mface = &mesh->mface[i];
MVert *mvert;
mvert = &mesh->mvert[mface->v1];
copy_v3_v3(vec, mvert->co);
- copy_v3fl_v3s(nor, mvert->no);
+ copy_v3_v3(nor, vert_normals[mface->v1]);
mvert = &mesh->mvert[mface->v2];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v2]);
mvert = &mesh->mvert[mface->v3];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v3]);
if (mface->v4) {
mvert = &mesh->mvert[mface->v4];
add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ add_v3_v3(nor, vert_normals[mface->v4]);
mul_v3_fl(vec, 0.25);
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 27d19532785..ca012f20f01 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -414,6 +414,7 @@ typedef struct ProjPaintState {
int totvert_eval;
const MVert *mvert_eval;
+ const float (*vert_normals)[3];
const MEdge *medge_eval;
const MPoly *mpoly_eval;
const MLoop *mloop_eval;
@@ -1718,10 +1719,10 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
- const short *no1, *no2, *no3;
- no1 = ps->mvert_eval[lt_vtri[0]].no;
- no2 = ps->mvert_eval[lt_vtri[1]].no;
- no3 = ps->mvert_eval[lt_vtri[2]].no;
+ const float *no1, *no2, *no3;
+ no1 = ps->vert_normals[lt_vtri[0]];
+ no2 = ps->vert_normals[lt_vtri[1]];
+ no3 = ps->vert_normals[lt_vtri[2]];
no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0];
no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1];
@@ -3871,7 +3872,6 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di
static void proj_paint_state_cavity_init(ProjPaintState *ps)
{
- const MVert *mv;
const MEdge *me;
float *cavities;
int a;
@@ -3891,13 +3891,11 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps)
sub_v3_v3(edges[me->v1], e);
counter[me->v1]++;
}
- for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
+ for (a = 0; a < ps->totvert_eval; a++) {
if (counter[a] > 0) {
- float no[3];
mul_v3_fl(edges[a], 1.0f / counter[a]);
- normal_short_to_float_v3(no, mv->no);
/* Augment the difference. */
- cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI;
+ cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI;
}
else {
cavities[a] = 0.0;
@@ -3964,7 +3962,7 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags");
for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) {
- normal_short_to_float_v3(no, mv->no);
+ copy_v3_v3(no, ps->vert_normals[a]);
if (UNLIKELY(ps->is_flip_object)) {
negate_v3(no);
}
@@ -4064,6 +4062,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
ps->mat_array[totmat - 1] = NULL;
ps->mvert_eval = ps->me_eval->mvert;
+ ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval);
if (ps->do_mask_cavity) {
ps->medge_eval = ps->me_eval->medge;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 23e03f3e576..df323baa2a9 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -1735,13 +1735,6 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
return true;
}
-static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3])
-{
- float normal[3];
- normal_short_to_float_v3(normal, vertexNormal);
- return dot_v3v3(brushNormal, normal);
-}
-
static void get_brush_alpha_data(const Scene *scene,
const SculptSession *ss,
const Brush *brush,
@@ -1868,7 +1861,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata,
if (total_hit_loops != 0) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -1948,7 +1941,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata,
if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) {
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
@@ -2054,9 +2047,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected */
if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2111,7 +2103,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex(
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
/* Test to see if the vertex coordinates are within the spherical brush region. */
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (angle_cos > 0.0 &&
BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) {
@@ -2895,9 +2887,8 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata,
/* Calc the dot prod. between ray norm on surf and current vert
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -2990,9 +2981,8 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata,
/* If the vertex is selected for painting. */
if (!use_vert_sel || mv->flag & SELECT) {
float brush_strength = cache->bstrength;
- const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
- 1.0f;
+ const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) :
+ 1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
view_angle_limits_apply_falloff(
@@ -3116,7 +3106,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata,
* (ie splash prevention factor), and only paint front facing verts. */
float brush_strength = cache->bstrength;
const float angle_cos = (use_normal && vd.no) ?
- dot_vf3vs3(sculpt_normal_frontface, vd.no) :
+ dot_v3v3(sculpt_normal_frontface, vd.no) :
1.0f;
if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) &&
((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 ||
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
index 85cd211367a..9d5fffdcfcc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c
@@ -72,8 +72,10 @@ struct VertProjUpdate {
/* -------------------------------------------------------------------- */
/* Internal Init */
-static void vpaint_proj_dm_map_cosnos_init__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjHandle *vp_handle = userData;
CoNo *co_no = &vp_handle->vcosnos[index];
@@ -86,12 +88,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb(
}
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
@@ -116,8 +113,10 @@ static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph,
/* Same as init but take mouse location into account */
-static void vpaint_proj_dm_map_cosnos_update__map_cb(
- void *userData, int index, const float co[3], const float no_f[3], const short no_s[3])
+static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData,
+ int index,
+ const float co[3],
+ const float no[3])
{
struct VertProjUpdate *vp_update = userData;
struct VertProjHandle *vp_handle = vp_update->vp_handle;
@@ -148,12 +147,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb(
/* continue with regular functionality */
copy_v3_v3(co_no->co, co);
- if (no_f) {
- copy_v3_v3(co_no->no, no_f);
- }
- else {
- normal_short_to_float_v3(co_no->no, no_s);
- }
+ copy_v3_v3(co_no->no, no);
}
static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
index d10a56be866..1dfc4db6ac3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -665,8 +665,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index)
static void gradientVertUpdate__mapFunc(void *userData,
int index,
const float UNUSED(co[3]),
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index];
@@ -681,8 +680,7 @@ static void gradientVertUpdate__mapFunc(void *userData,
static void gradientVertInit__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
WPGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 02886643cb4..5ac13ebdd93 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -177,11 +177,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
if (ss->shapekey_active || ss->deform_modifiers_active) {
- const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
- normal_short_to_float_v3(no, mverts[index].no);
+ const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh);
+ copy_v3_v3(no, vert_normals[index]);
}
else {
- normal_short_to_float_v3(no, ss->mvert[index].no);
+ copy_v3_v3(no, ss->vert_normals[index]);
}
break;
}
@@ -1387,10 +1387,10 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata,
if (orig_data.unode->type == SCULPT_UNDO_COORDS) {
copy_v3_v3(vd.co, orig_data.co);
if (vd.no) {
- copy_v3_v3_short(vd.no, orig_data.no);
+ copy_v3_v3(vd.no, orig_data.no);
}
else {
- normal_short_to_float_v3(vd.fno, orig_data.no);
+ copy_v3_v3(vd.fno, orig_data.no);
}
}
else if (orig_data.unode->type == SCULPT_UNDO_MASK) {
@@ -1689,7 +1689,7 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss,
static float frontface(const Brush *br,
const float sculpt_normal[3],
- const short no[3],
+ const float no[3],
const float fno[3])
{
if (!(br->flag & BRUSH_FRONTFACE)) {
@@ -1698,10 +1698,7 @@ static float frontface(const Brush *br,
float dot;
if (no) {
- float tmp[3];
-
- normal_short_to_float_v3(tmp, no);
- dot = dot_v3v3(tmp, sculpt_normal);
+ dot = dot_v3v3(no, sculpt_normal);
}
else {
dot = dot_v3v3(fno, sculpt_normal);
@@ -1938,19 +1935,19 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
float co[3];
/* For bm_vert only. */
- short no_s[3];
+ float no_s[3];
if (use_original) {
if (unode->bm_entry) {
const float *temp_co;
- const short *temp_no_s;
+ const float *temp_no_s;
BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
copy_v3_v3(co, temp_co);
- copy_v3_v3_short(no_s, temp_no_s);
+ copy_v3_v3(no_s, temp_no_s);
}
else {
copy_v3_v3(co, unode->co[vd.i]);
- copy_v3_v3_short(no_s, unode->no[vd.i]);
+ copy_v3_v3(no_s, unode->no[vd.i]);
}
}
else {
@@ -1970,11 +1967,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no, no_s);
+ copy_v3_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no, vd.no);
+ copy_v3_v3(no, vd.no);
}
else {
copy_v3_v3(no, vd.fno);
@@ -2350,7 +2347,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss,
const Brush *br,
const float brush_point[3],
const float len,
- const short vno[3],
+ const float vno[3],
const float fno[3],
const float mask,
const int vertex_index,
@@ -3652,11 +3649,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
}
MEM_SAFE_FREE(nodes);
-
- /* Modifiers could depend on mesh normals, so we should update them.
- * NOTE: then if sculpting happens on locked key, normals should be re-calculate after applying
- * coords from key-block on base mesh. */
- BKE_mesh_calc_normals(me);
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c
index e238fafb063..1e41c5cdbdf 100644
--- a/source/blender/editors/sculpt_paint/sculpt_boundary.c
+++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c
@@ -772,12 +772,10 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
- float normal[3];
- normal_short_to_float_v3(normal, orig_data.no);
float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
madd_v3_v3v3fl(target_co,
orig_data.co,
- normal,
+ orig_data.no,
boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
strength);
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
index 8842d93410c..c2acc361a79 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_types.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c
@@ -1544,7 +1544,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor);
}
else {
- normal_short_to_float_v3(normal, orig_data.no);
+ copy_v3_v3(normal, orig_data.no);
mul_v3_fl(normal, brush->height);
madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
}
@@ -1623,7 +1623,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
copy_v3_v3(val, vd.fno);
}
else {
- normal_short_to_float_v3(val, vd.no);
+ copy_v3_v3(val, vd.no);
}
mul_v3_fl(val, fade * ss->cache->radius);
@@ -2002,7 +2002,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
mul_v3_fl(silhouette_test_dir, -1.0f);
}
float vno[3];
- normal_short_to_float_v3(vno, orig_data.no);
+ copy_v3_v3(vno, orig_data.no);
fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index dcfd7f7bcdc..3ac57d73d37 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -560,13 +560,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
thread_id);
float brush_disp[3];
- float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
switch (brush->cloth_deform_type) {
case BRUSH_CLOTH_DEFORM_DRAG:
@@ -621,7 +614,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, disp_center, fade);
} break;
case BRUSH_CLOTH_DEFORM_INFLATE:
- mul_v3_v3fl(force, normal, fade);
+ mul_v3_v3fl(force, vd.no ? vd.no : vd.fno, fade);
break;
case BRUSH_CLOTH_DEFORM_EXPAND:
cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f;
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
index 10f141e2311..cf45e25142b 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -334,14 +334,7 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
+ float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno);
float angle = max_ff(saacosf(dot), 0.0f);
return angle;
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
index ff1a8935ba0..2d8bdc4e4ac 100644
--- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -303,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3];
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1.0f - fade;
fade *= data->filter_strength;
@@ -339,8 +339,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
sub_v3_v3v3(disp, val, orig_co);
break;
case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
+ mul_v3_v3fl(disp, orig_data.no, fade);
break;
case MESH_FILTER_SCALE:
unit_m3(transform);
@@ -372,7 +371,8 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
+ float normal[3];
+ copy_v3_v3(normal, orig_data.no);
/* Index is not unique for multires, so hash by vertex coordinates. */
const uint *hash_co = (const uint *)orig_co;
const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
@@ -432,7 +432,6 @@ static void mesh_filter_task_cb(void *__restrict userdata,
/* Intensify details. */
if (ss->filter_cache->sharpen_intensify_detail_strength > 0.0f) {
float detail_strength[3];
- normal_short_to_float_v3(detail_strength, orig_data.no);
copy_v3_v3(detail_strength, ss->filter_cache->detail_directions[vd.index]);
madd_v3_v3fl(disp,
detail_strength,
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index c5abc0b1640..5034251e973 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -262,13 +262,13 @@ typedef struct {
struct SculptUndoNode *unode;
float (*coords)[3];
- short (*normals)[3];
+ float (*normals)[3];
const float *vmasks;
float (*colors)[4];
/* Original coordinate, normal, and mask. */
const float *co;
- const short *no;
+ const float *no;
float mask;
const float *col;
} SculptOrigVertData;
@@ -723,7 +723,7 @@ typedef struct SculptUndoNode {
float (*co)[3];
float (*orig_co)[3];
- short (*no)[3];
+ float (*no)[3];
float (*col)[4];
float *mask;
int totvert;
@@ -967,7 +967,7 @@ float SCULPT_brush_strength_factor(struct SculptSession *ss,
const struct Brush *br,
const float point[3],
float len,
- const short vno[3],
+ const float vno[3],
const float fno[3],
float mask,
int vertex_index,
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index 05db799cb00..0fec7a9c4bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -92,12 +92,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
}
float local_co[3];
float normal[3];
- if (vd.no) {
- normal_short_to_float_v3(normal, vd.no);
- }
- else {
- copy_v3_v3(normal, vd.fno);
- }
+ copy_v3_v3(normal, vd.no ? vd.no : vd.fno);
mul_v3_m4v3(local_co, mat, vd.co);
/* Use the brush falloff to weight the sampled normals. */
const float fade = SCULPT_brush_strength_factor(ss,
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 4a88b75cf25..8819496c168 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -1107,10 +1107,10 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if (vd.no) {
- copy_v3_v3_short(unode->no[vd.i], vd.no);
+ copy_v3_v3(unode->no[vd.i], vd.no);
}
else {
- normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ copy_v3_v3(unode->no[vd.i], vd.fno);
}
if (ss->deform_modifiers_active) {
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index 16d9b9182cf..990b4fc85b1 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -272,8 +272,7 @@ typedef struct foreachScreenFace_userData {
static void meshobject_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenObjectVert_userData *data = userData;
struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index];
@@ -322,8 +321,7 @@ void meshobject_foreachScreenVert(
static void mesh_foreachScreenVert__mapFunc(void *userData,
int index,
const float co[3],
- const float UNUSED(no_f[3]),
- const short UNUSED(no_s[3]))
+ const float UNUSED(no[3]))
{
foreachScreenVert_userData *data = userData;
BMVert *eve = BM_vert_at_index(data->vc.em->bm, index);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index e3a2d1f6531..b5a27547e61 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -1211,9 +1211,7 @@ static void cb_bvert_co_get(const int index, const void *user_data, const float
static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3])
{
const BVHTreeFromMesh *data = user_data;
- const MVert *vert = data->vert + index;
-
- normal_short_to_float_v3(r_no, vert->no);
+ copy_v3_v3(r_no, data->vert_normals[index]);
}
static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3])
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index b4a93eb996c..705dfff7260 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -168,11 +168,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
}
-static void set_mapped_co(void *vuserdata,
- int index,
- const float co[3],
- const float UNUSED(no[3]),
- const short UNUSED(no_s[3]))
+static void set_mapped_co(void *vuserdata, int index, const float co[3], const float UNUSED(no[3]))
{
void **userdata = vuserdata;
BMEditMesh *em = userdata[0];
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index a2d5ffb1392..455d3b5b236 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -685,9 +685,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[0]->point2d()[0];
vertices->co[1] = svRep[0]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -695,9 +693,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[1]->point2d()[0];
vertices->co[1] = svRep[1]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
+
++vertices;
++vertex_index;
@@ -713,9 +709,6 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
vertices->co[0] = svRep[2]->point2d()[0];
vertices->co[1] = svRep[2]->point2d()[1];
vertices->co[2] = get_stroke_vertex_z();
- vertices->no[0] = 0;
- vertices->no[1] = 0;
- vertices->no[2] = SHRT_MAX;
++vertices;
++vertex_index;
@@ -821,6 +814,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
} // loop over strokes
BKE_object_materials_test(freestyle_bmain, object_mesh, (ID *)mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
#if 0 // XXX
BLI_assert(mesh->totvert == vertex_index);
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 598d4961e05..0a1d9c3b6d5 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -96,6 +96,7 @@ enum {
*/
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const struct MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const struct MLoopCol *vcol,
const int *sculpt_face_sets,
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index bd24616820a..dd53bea4eca 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -210,6 +210,7 @@ static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
const MVert *mvert,
+ const float (*vert_normals)[3],
const float *vmask,
const MLoopCol *vcol,
const int *sculpt_face_sets,
@@ -292,7 +293,7 @@ void GPU_pbvh_mesh_buffers_update(GPU_PBVH_Buffers *buffers,
copy_v3_v3(GPU_vertbuf_raw_step(&pos_step), v->co);
if (buffers->smooth) {
- copy_v3_v3_short(no, v->no);
+ normal_float_to_short_v3(no, vert_normals[vtri[j]]);
}
copy_v3_v3_short(GPU_vertbuf_raw_step(&nor_step), no);
diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc
index 80f2cadd08c..e8c156a2b8d 100644
--- a/source/blender/io/alembic/exporter/abc_writer_hair.cc
+++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc
@@ -136,6 +136,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MFace *mface = mesh->mface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
if ((!mtface || !mface) && !uv_warning_shown_) {
std::fprintf(stderr,
@@ -173,8 +174,17 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pa->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, normal, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ normal,
+ nullptr,
+ nullptr,
+ nullptr);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
@@ -206,10 +216,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context,
if (vtx[o] == num) {
uv_values.emplace_back(tface->uv[o][0], tface->uv[o][1]);
-
- MVert *mv = mverts + vtx[o];
-
- normal_short_to_float_v3(normal, mv->no);
+ copy_v3_v3(normal, vert_normals[vtx[o]]);
copy_yup_from_zup(tmp_nor.getValue(), normal);
norm_values.push_back(tmp_nor);
found = true;
@@ -250,6 +257,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
MTFace *mtface = mesh->mtface;
MVert *mverts = mesh->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
ParticleSystem *psys = context.particle_system;
ParticleSettings *part = psys->part;
@@ -281,8 +289,17 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context,
psys_interpolate_uvs(tface, face->v4, pc->fuv, r_uv);
uv_values.emplace_back(r_uv[0], r_uv[1]);
- psys_interpolate_face(
- mverts, face, tface, nullptr, mapfw, vec, tmpnor, nullptr, nullptr, nullptr);
+ psys_interpolate_face(mverts,
+ vert_normals,
+ face,
+ tface,
+ nullptr,
+ mapfw,
+ vec,
+ tmpnor,
+ nullptr,
+ nullptr,
+ nullptr);
/* Convert Z-up to Y-up. */
norm_values.emplace_back(tmpnor[0], tmpnor[2], -tmpnor[1]);
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc
index 83ca3399db5..3c1ac8ceeaf 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.cc
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc
@@ -34,6 +34,7 @@
#include "DNA_object_types.h"
#include "BLI_compiler_compat.h"
+#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
@@ -160,27 +161,26 @@ static void read_mverts(CDStreamConfig &config, const AbcMeshData &mesh_data)
return;
}
- read_mverts(mverts, positions, nullptr);
+ read_mverts(*config.mesh, positions, nullptr);
}
-void read_mverts(MVert *mverts, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
+void read_mverts(Mesh &mesh, const P3fArraySamplePtr positions, const N3fArraySamplePtr normals)
{
for (int i = 0; i < positions->size(); i++) {
- MVert &mvert = mverts[i];
+ MVert &mvert = mesh.mvert[i];
Imath::V3f pos_in = (*positions)[i];
copy_zup_from_yup(mvert.co, pos_in.getValue());
mvert.bweight = 0;
-
- if (normals) {
+ }
+ if (normals) {
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(&mesh);
+ for (const int i : IndexRange(normals->size())) {
Imath::V3f nor_in = (*normals)[i];
-
- short no[3];
- normal_float_to_short_v3(no, nor_in.getValue());
-
- copy_zup_from_yup(mvert.no, no);
+ copy_zup_from_yup(vert_normals[i], nor_in.getValue());
}
+ BKE_mesh_vertex_normals_clear_dirty(&mesh);
}
}
diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.h b/source/blender/io/alembic/intern/abc_reader_mesh.h
index e78f2186eda..1123616943e 100644
--- a/source/blender/io/alembic/intern/abc_reader_mesh.h
+++ b/source/blender/io/alembic/intern/abc_reader_mesh.h
@@ -81,7 +81,7 @@ class AbcSubDReader final : public AbcObjectReader {
const char **err_str) override;
};
-void read_mverts(MVert *mverts,
+void read_mverts(Mesh &mesh,
const Alembic::AbcGeom::P3fArraySamplePtr positions,
const Alembic::AbcGeom::N3fArraySamplePtr normals);
diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc
index 75ed18f57f2..0135e150097 100644
--- a/source/blender/io/alembic/intern/abc_reader_points.cc
+++ b/source/blender/io/alembic/intern/abc_reader_points.cc
@@ -121,7 +121,7 @@ void read_points_sample(const IPointsSchema &schema,
}
}
- read_mverts(config.mvert, positions, vnormals);
+ read_mverts(*config.mesh, positions, vnormals);
}
struct Mesh *AbcPointsReader::read_mesh(struct Mesh *existing_mesh,
diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp
index eeee220fd2c..73e3eeda462 100644
--- a/source/blender/io/collada/GeometryExporter.cpp
+++ b/source/blender/io/collada/GeometryExporter.cpp
@@ -631,6 +631,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
int last_normal_index = -1;
MVert *verts = me->mvert;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
MLoop *mloops = me->mloop;
float(*lnors)[3] = nullptr;
bool use_custom_normals = false;
@@ -666,7 +667,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
normalize_v3_v3(normalized, lnors[loop_idx]);
}
else {
- normal_short_to_float_v3(normalized, verts[mloops[loop_index].v].no);
+ copy_v3_v3(normalized, vert_normals[mloops[loop_index].v]);
normalize_v3(normalized);
}
Normal n = {normalized[0], normalized[1], normalized[2]};
diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc
index 3ad1d4adf18..53dbaac99fd 100644
--- a/source/blender/io/usd/intern/usd_reader_mesh.cc
+++ b/source/blender/io/usd/intern/usd_reader_mesh.cc
@@ -30,6 +30,8 @@
#include "BLI_math.h"
#include "BLI_math_geom.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_span.hh"
#include "BLI_string.h"
#include "DNA_customdata_types.h"
@@ -527,34 +529,32 @@ void USDMeshReader::process_normals_vertex_varying(Mesh *mesh)
}
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
return;
}
if (normals_.size() != mesh->totvert) {
std::cerr << "WARNING: vertex varying normals count mismatch for mesh " << prim_path_
<< std::endl;
- BKE_mesh_calc_normals(mesh);
return;
}
- for (int i = 0; i < normals_.size(); i++) {
- MVert &mvert = mesh->mvert[i];
- normal_float_to_short_v3(mvert.no, normals_[i].data());
- }
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_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(), static_cast<int64_t>(normals_.size())});
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
void USDMeshReader::process_normals_face_varying(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totloop) {
std::cerr << "WARNING: loop normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -592,14 +592,14 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
void USDMeshReader::process_normals_uniform(Mesh *mesh)
{
if (normals_.empty()) {
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
/* Check for normals count mismatches to prevent crashes. */
if (normals_.size() != mesh->totpoly) {
std::cerr << "WARNING: uniform normal count mismatch for mesh " << mesh->id.name << std::endl;
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
return;
}
@@ -652,14 +652,11 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
}
else {
/* Default */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
}
- /* Process point normals after reading polys. This
- * is important in the case where the normals are empty
- * and we invoke BKE_mesh_calc_normals(mesh), which requires
- * edges to be defined. */
+ /* Process point normals after reading polys. */
if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0 &&
normal_interpolation_ == pxr::UsdGeomTokens->vertex) {
process_normals_vertex_varying(mesh);
diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc
index 61b14155dd0..b21dd8ac1fd 100644
--- a/source/blender/io/usd/intern/usd_writer_mesh.cc
+++ b/source/blender/io/usd/intern/usd_writer_mesh.cc
@@ -378,16 +378,15 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
}
else {
/* Compute the loop normals based on the 'smooth' flag. */
- float normal[3];
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
MPoly *mpoly = mesh->mpoly;
- const MVert *mvert = mesh->mvert;
for (int poly_idx = 0, totpoly = mesh->totpoly; poly_idx < totpoly; ++poly_idx, ++mpoly) {
MLoop *mloop = mesh->mloop + mpoly->loopstart;
if ((mpoly->flag & ME_SMOOTH) == 0) {
/* Flat shaded, use common normal for all verts. */
- BKE_mesh_calc_poly_normal(mpoly, mloop, mvert, normal);
- pxr::GfVec3f pxr_normal(normal);
+ pxr::GfVec3f pxr_normal(face_normals[poly_idx]);
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx) {
loop_normals.push_back(pxr_normal);
}
@@ -395,8 +394,7 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
else {
/* Smooth shaded, use individual vert normals. */
for (int loop_idx = 0; loop_idx < mpoly->totloop; ++loop_idx, ++mloop) {
- normal_short_to_float_v3(normal, mvert[mloop->v].no);
- loop_normals.push_back(pxr::GfVec3f(normal));
+ loop_normals.push_back(pxr::GfVec3f(vert_normals[mloop->v]));
}
}
}
diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
index efe17c7d1a2..ab1448aa10c 100644
--- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
+++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc
@@ -156,7 +156,6 @@ int OBJMesh::ith_smooth_group(const int poly_index) const
void OBJMesh::ensure_mesh_normals() const
{
- BKE_mesh_ensure_normals(export_mesh_eval_);
BKE_mesh_calc_normals_split(export_mesh_eval_);
}
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 94e88bdaca6..fdd389c9c50 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -82,6 +82,10 @@ typedef struct Mesh_Runtime {
struct Mesh *mesh_eval;
void *eval_mutex;
+ /* A separate mutex is needed for normal calculation, because sometimes
+ * the normals are needed while #eval_mutex is already locked. */
+ void *normals_mutex;
+
/** Needed to ensure some thread-safety during render data pre-processing. */
void *render_mutex;
@@ -129,6 +133,17 @@ typedef struct Mesh_Runtime {
char wrapper_type_finalize;
/**
+ * 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;
+
+ void *_pad2;
+
+ /**
* Used to mark when derived data needs to be recalculated for a certain layer.
* Currently only normals.
*/
@@ -138,15 +153,6 @@ typedef struct Mesh_Runtime {
int64_t cd_dirty_loop;
int64_t cd_dirty_poly;
- /**
- * 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;
-
} Mesh_Runtime;
typedef struct Mesh {
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index d32470c0dcc..22c523901c0 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -41,12 +41,8 @@ extern "C" {
*/
typedef struct MVert {
float co[3];
- /**
- * Cache the normal, can always be recalculated from surrounding faces.
- * See #CD_CUSTOMLOOPNORMAL for custom normals.
- */
- short no[3];
char flag, bweight;
+ char _pad[2];
} MVert;
/** #MVert.flag */
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 5a937e6b06b..c1aea33b9a5 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -317,18 +317,26 @@ static void rna_Mesh_update_facemask(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_MeshVertex_normal_get(PointerRNA *ptr, float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- normal_short_to_float_v3(value, mvert->no);
+ Mesh *mesh = rna_mesh(ptr);
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
+
+ copy_v3_v3(value, vert_normals[index]);
}
static void rna_MeshVertex_normal_set(PointerRNA *ptr, const float *value)
{
- MVert *mvert = (MVert *)ptr->data;
- float no[3];
+ Mesh *mesh = rna_mesh(ptr);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(mesh);
+
+ const int index = (MVert *)ptr->data - mesh->mvert;
+ BLI_assert(index >= 0);
+ BLI_assert(index < mesh->totvert);
- copy_v3_v3(no, value);
- normalize_v3(no);
- normal_float_to_short_v3(mvert->no, no);
+ copy_v3_v3(vert_normals[index], value);
}
static float rna_MeshVertex_bevel_weight_get(PointerRNA *ptr)
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index fa5149a45ba..56db68b163c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -306,14 +306,14 @@ static void mesh_merge_transform(Mesh *result,
mul_m4_v3(cap_offset, mv->co);
/* Reset MVert flags for caps */
mv->flag = mv->bweight = 0;
+ }
- /* We have to correct normals too, if we do not tag them as dirty later! */
- if (!recalc_normals_later) {
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- mul_mat3_m4_v3(cap_offset, no);
- normalize_v3(no);
- normal_float_to_short_v3(mv->no, no);
+ /* 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_vertex_normals_for_write(result);
+ 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]);
}
}
@@ -370,7 +370,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
Mesh *mesh)
{
const MVert *src_mvert;
- MVert *mv, *mv_prev, *result_dm_verts;
+ MVert *result_dm_verts;
MEdge *me;
MLoop *ml;
@@ -582,6 +582,14 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
first_chunk_nverts = chunk_nverts;
unit_m4(current_offset);
+ const float(*src_vert_normals)[3] = NULL;
+ float(*dst_vert_normals)[3] = NULL;
+ if (!use_recalc_normals) {
+ src_vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ dst_vert_normals = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
+ }
+
for (c = 1; c < count; c++) {
/* copy customdata to new geometry */
CustomData_copy_data(&mesh->vdata, &result->vdata, 0, c * chunk_nverts, chunk_nverts);
@@ -589,23 +597,21 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
CustomData_copy_data(&mesh->ldata, &result->ldata, 0, c * chunk_nloops, chunk_nloops);
CustomData_copy_data(&mesh->pdata, &result->pdata, 0, c * chunk_npolys, chunk_npolys);
- mv_prev = result_dm_verts;
- mv = mv_prev + c * chunk_nverts;
+ const int vert_offset = c * chunk_nverts;
/* recalculate cumulative offset here */
mul_m4_m4m4(current_offset, current_offset, offset);
/* apply offset to all new verts */
- for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
- mul_m4_v3(current_offset, mv->co);
+ for (i = 0; i < chunk_nverts; i++) {
+ const int i_dst = vert_offset + i;
+ mul_m4_v3(current_offset, result_dm_verts[i_dst].co);
/* We have to correct normals too, if we do not tag them as dirty! */
if (!use_recalc_normals) {
- float no[3];
- normal_short_to_float_v3(no, mv->no);
- mul_mat3_m4_v3(current_offset, no);
- normalize_v3(no);
- normal_float_to_short_v3(mv->no, no);
+ 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]);
}
}
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 6cd8d70383d..86f0df1418b 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -280,9 +280,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, struct
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
- if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_normals_tag_dirty(result);
- }
+ BKE_mesh_normals_tag_dirty(result);
/* TODO(sybren): also copy flags & tags? */
return result;
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 07da18f990d..010292d2ebb 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -177,6 +177,7 @@ typedef struct DisplaceUserdata {
float (*vertexCos)[3];
float local_mat[4][4];
MVert *mvert;
+ const float (*vert_normals)[3];
float (*vert_clnors)[3];
} DisplaceUserdata;
@@ -194,7 +195,6 @@ static void displaceModifier_do_task(void *__restrict userdata,
bool use_global_direction = data->use_global_direction;
float(*tex_co)[3] = data->tex_co;
float(*vertexCos)[3] = data->vertexCos;
- MVert *mvert = data->mvert;
float(*vert_clnors)[3] = data->vert_clnors;
const float delta_fixed = 1.0f -
@@ -272,9 +272,7 @@ static void displaceModifier_do_task(void *__restrict userdata,
add_v3_v3(vertexCos[iter], local_vec);
break;
case MOD_DISP_DIR_NOR:
- vertexCos[iter][0] += delta * (mvert[iter].no[0] / 32767.0f);
- vertexCos[iter][1] += delta * (mvert[iter].no[1] / 32767.0f);
- vertexCos[iter][2] += delta * (mvert[iter].no[2] / 32767.0f);
+ madd_v3_v3fl(vertexCos[iter], data->vert_normals[iter], delta);
break;
case MOD_DISP_DIR_CLNOR:
madd_v3_v3fl(vertexCos[iter], vert_clnors[iter], delta);
@@ -363,6 +361,9 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
data.vertexCos = vertexCos;
copy_m4_m4(data.local_mat, local_mat);
data.mvert = mvert;
+ if (direction == MOD_DISP_DIR_NOR) {
+ data.vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
+ }
data.vert_clnors = vert_clnors;
if (tex_target != NULL) {
data.pool = BKE_image_pool_new();
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 493b59b3a1a..68d6b4a3626 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1118,7 +1118,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
/* finalization */
BKE_mesh_calc_edges_tessface(explode);
BKE_mesh_convert_mfaces_to_mpolys(explode);
- explode->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(explode);
if (psmd->psys->lattice_deform_data) {
BKE_lattice_deform_data_destroy(psmd->psys->lattice_deform_data);
diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc
index 28ab25f6a42..0de8b26a1b7 100644
--- a/source/blender/modifiers/intern/MOD_mask.cc
+++ b/source/blender/modifiers/intern/MOD_mask.cc
@@ -427,16 +427,6 @@ static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh,
MVert &v2 = src_mesh.mvert[e_src.v2];
interp_v3_v3v3(v.co, v1.co, v2.co, fac);
-
- float no1[3];
- float no2[3];
- normal_short_to_float_v3(no1, v1.no);
- normal_short_to_float_v3(no2, v2.no);
- mul_v3_fl(no1, weights[0]);
- madd_v3_v3fl(no1, no2, weights[1]);
- normalize_v3(no1);
- normal_float_to_short_v3(v.no, no1);
-
vert_index++;
}
}
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index db2eedf9c02..61099fedf46 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -227,7 +227,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -334,14 +334,16 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
/* XXX TODO: is this still needed? */
// mesh->dirty |= DM_DIRTY_TESS_CDLAYERS;
/* We need to recompute vertex normals! */
- BKE_mesh_calc_normals(mesh);
+ BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -349,7 +351,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -364,7 +366,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
Mesh *mesh,
short (*clnors)[2],
float (*loopnors)[3],
- float (*polynors)[3],
+ const float (*polynors)[3],
const short mix_mode,
const float mix_factor,
const float mix_limit,
@@ -449,11 +451,13 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
}
if (do_polynors_fix &&
- polygons_check_flip(mloop, nos, &mesh->ldata, mpoly, polynors, num_polys)) {
+ polygons_check_flip(
+ mloop, nos, &mesh->ldata, mpoly, BKE_mesh_poly_normals_for_write(mesh), num_polys)) {
BKE_mesh_normals_tag_dirty(mesh);
}
BKE_mesh_normals_loop_custom_set(mvert,
+ BKE_mesh_vertex_normals_ensure(mesh),
num_verts,
medge,
num_edges,
@@ -461,7 +465,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
nos,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ polynors,
num_polys,
clnors);
@@ -545,26 +549,10 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
float(*loopnors)[3] = NULL;
short(*clnors)[2] = NULL;
- float(*polynors)[3];
-
CustomData *ldata = &result->ldata;
- /* Compute poly (always needed) and vert normals. */
- CustomData *pdata = &result->pdata;
- polynors = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors, NULL);
- }
- else {
- BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors);
- }
-
- result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
if (use_current_clnors) {
@@ -572,6 +560,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors = MEM_malloc_arrayN((size_t)num_loops, sizeof(*loopnors), __func__);
BKE_mesh_normals_loop_split(mvert,
+ vert_normals,
num_verts,
medge,
num_edges,
@@ -579,7 +568,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
loopnors,
num_loops,
mpoly,
- (const float(*)[3])polynors,
+ poly_normals,
num_polys,
true,
result->smoothresh,
@@ -601,7 +590,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -624,7 +613,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result,
clnors,
loopnors,
- polynors,
+ poly_normals,
enmd->mix_mode,
enmd->mix_factor,
enmd->mix_limit,
@@ -641,8 +630,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
num_polys);
}
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, num_polys);
MEM_SAFE_FREE(loopnors);
result->runtime.is_original = false;
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 4566cf93dd7..d821caf25a7 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -376,7 +376,7 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes
if (omd->geometry_mode == MOD_OCEAN_GEOM_GENERATE) {
result = generate_ocean_geometry(omd, mesh, resolution);
- BKE_mesh_ensure_normals(result);
+ BKE_mesh_normals_tag_dirty(result);
}
else if (omd->geometry_mode == MOD_OCEAN_GEOM_DISPLACE) {
result = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE);
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index f24f6951690..f5db3bced7a 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -395,6 +395,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
medge_orig = mesh->medge;
mvert_new = result->mvert;
+ float(*vert_normals_new)[3] = BKE_mesh_vertex_normals_for_write(result);
+ BKE_mesh_vertex_normals_clear_dirty(result);
mpoly_new = result->mpoly;
mloop_new = result->mloop;
medge_new = result->medge;
@@ -835,7 +837,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
}
normalize_v3(vc->no);
- normal_float_to_short_v3(mvert_new[i].no, vc->no);
+ copy_v3_v3(vert_normals_new[i], vc->no);
/* Done with normals */
}
@@ -884,7 +886,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
mul_v3_m3v3(nor_tx, mat3, vert_connect[j].no);
/* set the normal now its transformed */
- normal_float_to_short_v3(mv_new->no, nor_tx);
+ copy_v3_v3(vert_normals_new[mv_new - mvert_new], nor_tx);
}
/* set location */
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
index 20d65b9d9f8..fa8d08bf839 100644
--- a/source/blender/modifiers/intern/MOD_solidify_extrude.c
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -43,20 +43,6 @@
#endif
/* -------------------------------------------------------------------- */
-/** \name Local Utilities
- * \{ */
-
-/* specific function for solidify - define locally */
-BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
-{
- r[0] += (float)a[0] * f;
- r[1] += (float)a[1] * f;
- r[2] += (float)a[2] * f;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name High Quality Normal Calculation Function
* \{ */
@@ -81,20 +67,18 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
* \param poly_nors: Precalculated face normals.
* \param r_vert_nors: Return vert normals.
*/
-static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
+static void mesh_calc_hq_normal(Mesh *mesh, const float (*poly_nors)[3], float (*r_vert_nors)[3])
{
int i, numVerts, numEdges, numPolys;
MPoly *mpoly, *mp;
MLoop *mloop, *ml;
MEdge *medge, *ed;
- MVert *mvert, *mv;
numVerts = mesh->totvert;
numEdges = mesh->totedge;
numPolys = mesh->totpoly;
mpoly = mesh->mpoly;
medge = mesh->medge;
- mvert = mesh->mvert;
mloop = mesh->mloop;
/* we don't want to overwrite any referenced layers */
@@ -105,7 +89,6 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
cddm->mvert = mv;
#endif
- mv = mvert;
mp = mpoly;
{
@@ -171,9 +154,10 @@ static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_ver
}
/* normalize vertex normals and assign */
- for (i = 0; i < numVerts; i++, mv++) {
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ for (i = 0; i < numVerts; i++) {
if (normalize_v3(r_vert_nors[i]) == 0.0f) {
- normal_short_to_float_v3(r_vert_nors[i], mv->no);
+ copy_v3_v3(r_vert_nors[i], vert_normals[i]);
}
}
}
@@ -220,7 +204,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
int *edge_order = NULL;
float(*vert_nors)[3] = NULL;
- float(*poly_nors)[3] = NULL;
+ const float(*poly_nors)[3] = NULL;
const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
(smd->flag & MOD_SOLIDIFY_EVEN) ||
@@ -249,6 +233,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
/* array size is doubled in case of using a shell */
const uint stride = do_shell ? 2 : 1;
+ const float(*mesh_vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+
MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
orig_mvert = mesh->mvert;
@@ -258,14 +244,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (need_poly_normals) {
/* calculate only face normals */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(orig_mvert,
- (int)numVerts,
- orig_mloop,
- (int)numLoops,
- orig_mpoly,
- (int)numPolys,
- poly_nors);
+ poly_nors = BKE_mesh_poly_normals_ensure(mesh);
}
STACK_INIT(new_vert_arr, numVerts * 2);
@@ -636,7 +615,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -687,7 +666,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new_vgroup);
}
else {
- madd_v3v3short_fl(mv->co, mv->no, ofs_new_vgroup / 32767.0f);
+ madd_v3_v3fl(mv->co, mesh_vert_normals[i], ofs_new_vgroup);
}
}
}
@@ -740,7 +719,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
if (vert_nors == NULL) {
vert_nors = MEM_malloc_arrayN(numVerts, sizeof(float[3]), "mod_solid_vno");
for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
- normal_short_to_float_v3(vert_nors[i], mv->no);
+ copy_v3_v3(vert_nors[i], mesh_vert_normals[i]);
}
}
@@ -995,8 +974,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
uint i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
- for (i = 0; i < numVerts; i++, mv++) {
- negate_v3_short(mv->no);
+ for (i = 0; i < numVerts; i++) {
+ negate_v3((float *)mesh_vert_normals[i]);
}
}
@@ -1201,7 +1180,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
ed = medge + (numEdges * stride);
for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
float nor_cpy[3];
- short *nor_short;
int k;
/* NOTE: only the first vertex (lower half of the index) is calculated. */
@@ -1209,11 +1187,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
- nor_short = mvert[*(&ed->v1 + k)].no;
- normal_short_to_float_v3(nor, nor_short);
+ copy_v3_v3(nor, mesh_vert_normals[*(&ed->v1 + k)]);
add_v3_v3(nor, nor_cpy);
normalize_v3(nor);
- normal_float_to_short_v3(nor_short, nor);
+ copy_v3_v3((float *)mesh_vert_normals[*(&ed->v1 + k)], nor);
}
}
@@ -1232,10 +1209,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
MEM_freeN(old_vert_arr);
}
- if (poly_nors) {
- MEM_freeN(poly_nors);
- }
-
return result;
}
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
index 997f5943060..1aa52d44509 100644
--- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -158,7 +158,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const uint numVerts = (uint)mesh->totvert;
const uint numEdges = (uint)mesh->totedge;
const uint numPolys = (uint)mesh->totpoly;
- const uint numLoops = (uint)mesh->totloop;
if (numPolys == 0 && numVerts != 0) {
return mesh;
@@ -170,8 +169,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
- float(*poly_nors)[3] = NULL;
-
/* #ofs_front and #ofs_back are the offset from the original
* surface along the normal, where #oft_front is along the positive
* and #oft_back is along the negative normal. */
@@ -217,10 +214,9 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
#define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1)
- /* Calculate only face normals. */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(
- orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors);
+ /* Calculate only face normals. Copied because they are modified directly below. */
+ float(*poly_nors)[3] = MEM_malloc_arrayN(numPolys, sizeof(float[3]), __func__);
+ memcpy(poly_nors, BKE_mesh_poly_normals_ensure(mesh), sizeof(float[3]) * numPolys);
NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 16ef65f7838..d04aee91c71 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -234,9 +234,11 @@ Mesh *MOD_deform_mesh_eval_get(Object *ob,
}
}
+ /* TODO: Remove this "use_normals" argument, since the caller should retrieve normals afterwards
+ * if necessary. */
if (use_normals) {
if (LIKELY(mesh)) {
- BKE_mesh_ensure_normals(mesh);
+ BKE_mesh_vertex_normals_ensure(mesh);
}
}
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 03f8e3a1dfb..b7ab5dac388 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -163,8 +163,10 @@ static void waveModifier_do(WaveModifierData *md,
float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */
const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0;
+ const float(*vert_normals)[3] = NULL;
if ((wmd->flag & MOD_WAVE_NORM) && (mesh != NULL)) {
mvert = mesh->mvert;
+ vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
}
if (wmd->objectcenter != NULL) {
@@ -288,13 +290,13 @@ static void waveModifier_do(WaveModifierData *md,
if (mvert) {
/* move along normals */
if (wmd->flag & MOD_WAVE_NORM_X) {
- co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
+ co[0] += (lifefac * amplit) * vert_normals[i][0];
}
if (wmd->flag & MOD_WAVE_NORM_Y) {
- co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
+ co[1] += (lifefac * amplit) * vert_normals[i][1];
}
if (wmd->flag & MOD_WAVE_NORM_Z) {
- co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
+ co[2] += (lifefac * amplit) * vert_normals[i][2];
}
}
else {
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
index 1ee64b935b7..bfe389eb080 100644
--- a/source/blender/modifiers/intern/MOD_weighted_normal.c
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -85,6 +85,7 @@ typedef struct WeightedNormalData {
const int numPolys;
MVert *mvert;
+ const float (*vert_normals)[3];
MEdge *medge;
MLoop *mloop;
@@ -93,7 +94,7 @@ typedef struct WeightedNormalData {
const float split_angle;
MPoly *mpoly;
- float (*polynors)[3];
+ const float (*polynors)[3];
int *poly_strength;
MDeformVert *dvert;
@@ -143,7 +144,7 @@ static void aggregate_item_normal(WeightedNormalModifierData *wnmd,
const float curr_val,
const bool use_face_influence)
{
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
MDeformVert *dvert = wn_data->dvert;
const int defgrp_index = wn_data->defgrp_index;
@@ -206,7 +207,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
int *loop_to_poly = wn_data->loop_to_poly;
MPoly *mpoly = wn_data->mpoly;
- float(*polynors)[3] = wn_data->polynors;
+ const float(*polynors)[3] = wn_data->polynors;
int *poly_strength = wn_data->poly_strength;
MDeformVert *dvert = wn_data->dvert;
@@ -234,6 +235,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
* we do not actually care about computed loop_normals for now... */
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -360,6 +362,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -390,6 +393,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_from_vertices_set(mvert,
+ wn_data->vert_normals,
vert_normals,
numVerts,
medge,
@@ -407,6 +411,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
BKE_mesh_normals_loop_split(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -430,6 +435,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
}
BKE_mesh_normals_loop_custom_set(mvert,
+ wn_data->vert_normals,
numVerts,
medge,
numEdges,
@@ -609,15 +615,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
weight = (weight - 1) * 25;
}
- CustomData *pdata = &result->pdata;
- float(*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
- if (!polynors) {
- polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
- CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- BKE_mesh_calc_normals_poly_and_vertex(
- mvert, numVerts, mloop, numLoops, mpoly, numPolys, polynors, NULL);
-
const float split_angle = mesh->smoothresh;
short(*clnors)[2];
CustomData *ldata = &result->ldata;
@@ -641,6 +638,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.numPolys = numPolys,
.mvert = mvert,
+ .vert_normals = BKE_mesh_vertex_normals_ensure(result),
.medge = medge,
.mloop = mloop,
@@ -649,7 +647,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
.split_angle = split_angle,
.mpoly = mpoly,
- .polynors = polynors,
+ .polynors = BKE_mesh_poly_normals_ensure(mesh),
.poly_strength = CustomData_get_layer_named(
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
@@ -677,9 +675,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
MEM_SAFE_FREE(wn_data.mode_pair);
MEM_SAFE_FREE(wn_data.items_data);
- /* Currently Modifier stack assumes there is no poly normal data passed around... */
- CustomData_free_layers(pdata, CD_NORMAL, numPolys);
-
result->runtime.is_original = false;
return result;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index b07d809a091..b3b11b2e0e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -138,12 +138,6 @@ static Mesh *create_circle_mesh(const float radius,
copy_v3_v3(verts.last().co, float3(0));
}
- /* Point all vertex normals in the up direction. */
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
- }
-
/* Create outer edges. */
const short edge_flag = (fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE) ?
ME_LOOSEEDGE :
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 2aa9522cf56..e0923344421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -676,8 +676,6 @@ static Mesh *create_vertex_mesh()
/* Returns a mesh with a single vertex at the origin. */
Mesh *mesh = BKE_mesh_new_nomain(1, 0, 0, 0, 0);
copy_v3_fl3(mesh->mvert[0].co, 0.0f, 0.0f, 0.0f);
- const short up[3] = {0, 0, SHRT_MAX};
- copy_v3_v3_short(mesh->mvert[0].no, up);
return mesh;
}
@@ -720,8 +718,6 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
calculate_cone_uvs(mesh, config);
calculate_selection_outputs(mesh, config, attribute_outputs);
- BKE_mesh_normals_tag_dirty(mesh);
-
return mesh;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 2c4b5df6030..ecb3c785212 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -89,14 +89,6 @@ Mesh *create_grid_mesh(const int verts_x,
});
}
- /* Point all vertex normals in the up direction. */
- {
- const short up_normal[3] = {0, 0, SHRT_MAX};
- for (MVert &vert : verts) {
- copy_v3_v3_short(vert.no, up_normal);
- }
- }
-
const int y_edges_start = 0;
const int x_edges_start = verts_x * edges_y;
const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE :
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 8a2b054ece0..691267bccb8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -203,12 +203,8 @@ Mesh *create_line_mesh(const float3 start, const float3 delta, const int count)
MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
- short normal[3];
- normal_float_to_short_v3(normal, math::normalize(delta));
-
for (const int i : verts.index_range()) {
copy_v3_v3(verts[i].co, start + delta * i);
- copy_v3_v3_short(verts[i].no, normal);
}
fill_edge_data(edges);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index 41178d5c4e6..751cf917f6f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -71,7 +71,12 @@ static int sphere_face_total(const int segments, const int rings)
return quads + triangles;
}
+/**
+ * Also calculate vertex normals here, since the calculation is trivial, and it allows avoiding the
+ * calculation later, if it's necessary. The vertex normals are just the normalized positions.
+ */
static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
+ MutableSpan<float3> vert_normals,
const float radius,
const int segments,
const int rings)
@@ -80,7 +85,7 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float delta_phi = (2.0f * M_PI) / segments;
copy_v3_v3(verts[0].co, float3(0.0f, 0.0f, radius));
- normal_float_to_short_v3(verts[0].no, float3(0.0f, 0.0f, 1.0f));
+ vert_normals.first() = float3(0.0f, 0.0f, 1.0f);
int vert_index = 1;
for (const int ring : IndexRange(1, rings - 1)) {
@@ -92,13 +97,13 @@ static void calculate_sphere_vertex_data(MutableSpan<MVert> verts,
const float x = sin_theta * std::cos(phi);
const float y = sin_theta * std::sin(phi);
copy_v3_v3(verts[vert_index].co, float3(x, y, z) * radius);
- normal_float_to_short_v3(verts[vert_index].no, float3(x, y, z));
+ vert_normals[vert_index] = float3(x, y, z);
vert_index++;
}
}
copy_v3_v3(verts.last().co, float3(0.0f, 0.0f, -radius));
- normal_float_to_short_v3(verts.last().no, float3(0.0f, 0.0f, -1.0f));
+ vert_normals.last() = float3(0.0f, 0.0f, -1.0f);
}
static void calculate_sphere_edge_indices(MutableSpan<MEdge> edges,
@@ -279,7 +284,9 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MPoly> polys{mesh->mpoly, mesh->totpoly};
- calculate_sphere_vertex_data(verts, radius, segments, rings);
+ MutableSpan vert_normals{(float3 *)BKE_mesh_vertex_normals_for_write(mesh), mesh->totvert};
+ calculate_sphere_vertex_data(verts, vert_normals, radius, segments, rings);
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
calculate_sphere_edge_indices(edges, segments, rings);
diff --git a/source/blender/render/intern/bake.c b/source/blender/render/intern/bake.c
index 6794a9cd1ad..2d7f964a968 100644
--- a/source/blender/render/intern/bake.c
+++ b/source/blender/render/intern/bake.c
@@ -107,6 +107,7 @@ typedef struct TSpace {
typedef struct TriTessFace {
const MVert *mverts[3];
+ const float *vert_normals[3];
const TSpace *tspace[3];
float *loop_normal[3];
float normal[3]; /* for flat faces */
@@ -241,9 +242,9 @@ static void calc_point_from_barycentric_extrusion(TriTessFace *triangles,
interp_barycentric_tri_v3(data, u, v, coord);
if (is_smooth) {
- normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
- normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
- normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
+ copy_v3_v3(data[0], triangle->vert_normals[0]);
+ copy_v3_v3(data[1], triangle->vert_normals[1]);
+ copy_v3_v3(data[2], triangle->vert_normals[2]);
interp_barycentric_tri_v3(data, u, v, dir);
normalize_v3(dir);
@@ -488,6 +489,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
loop_normals = CustomData_get_layer(&me_eval->ldata, CD_NORMAL);
}
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me);
for (i = 0; i < tottri; i++) {
const MLoopTri *lt = &looptri[i];
const MPoly *mp = &me->mpoly[lt->poly];
@@ -495,6 +497,9 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
triangles[i].mverts[0] = &mvert[me->mloop[lt->tri[0]].v];
triangles[i].mverts[1] = &mvert[me->mloop[lt->tri[1]].v];
triangles[i].mverts[2] = &mvert[me->mloop[lt->tri[2]].v];
+ triangles[i].vert_normals[0] = &vert_normals[me->mloop[lt->tri[0]].v][0];
+ triangles[i].vert_normals[1] = &vert_normals[me->mloop[lt->tri[1]].v][1];
+ triangles[i].vert_normals[2] = &vert_normals[me->mloop[lt->tri[2]].v][2];
triangles[i].is_smooth = (mp->flag & ME_SMOOTH) != 0;
if (tangent) {
@@ -878,7 +883,7 @@ void RE_bake_normal_world_to_tangent(const BakePixel pixel_array[],
copy_v3_v3(normals[j], triangle->loop_normal[j]);
}
else {
- normal_short_to_float_v3(normals[j], triangle->mverts[j]->no);
+ copy_v3_v3(normals[j], triangle->vert_normals[j]);
}
}
diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c
index 930c7580f32..d3e7dca2035 100644
--- a/source/blender/render/intern/multires_bake.c
+++ b/source/blender/render/intern/multires_bake.c
@@ -72,6 +72,7 @@ typedef struct MultiresBakeResult {
typedef struct {
MVert *mvert;
+ const float (*vert_normals)[3];
MPoly *mpoly;
MLoop *mloop;
MLoopUV *mloopuv;
@@ -135,10 +136,7 @@ static void multiresbake_get_normal(const MResolvePixelData *data,
}
else {
const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v;
- const short *no = data->mvert[vi].no;
-
- normal_short_to_float_v3(norm, no);
- normalize_v3(norm);
+ copy_v3_v3(norm, data->vert_normals[vi]);
}
}
diff --git a/source/blender/render/intern/texture_pointdensity.c b/source/blender/render/intern/texture_pointdensity.c
index 8ca1decdea7..683260f86cb 100644
--- a/source/blender/render/intern/texture_pointdensity.c
+++ b/source/blender/render/intern/texture_pointdensity.c
@@ -47,6 +47,7 @@
#include "BKE_customdata.h"
#include "BKE_deform.h"
#include "BKE_lattice.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_scene.h"
@@ -368,19 +369,11 @@ static void pointdensity_cache_vertex_weight(PointDensity *pd,
}
}
-static void pointdensity_cache_vertex_normal(PointDensity *pd,
- Object *UNUSED(ob),
- Mesh *mesh,
- float *data_color)
+static void pointdensity_cache_vertex_normal(Mesh *mesh, float *data_color)
{
- MVert *mvert = mesh->mvert, *mv;
- int i;
-
BLI_assert(data_color);
-
- for (i = 0, mv = mvert; i < pd->totpoints; i++, mv++, data_color += 3) {
- normal_short_to_float_v3(data_color, mv->no);
- }
+ const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
+ memcpy(data_color, vert_normals, sizeof(float[3]) * mesh->totvert);
}
static void pointdensity_cache_object(PointDensity *pd, Object *ob)
@@ -442,7 +435,7 @@ static void pointdensity_cache_object(PointDensity *pd, Object *ob)
pointdensity_cache_vertex_weight(pd, ob, mesh, data_color);
break;
case TEX_PD_COLOR_VERTNOR:
- pointdensity_cache_vertex_normal(pd, ob, mesh, data_color);
+ pointdensity_cache_vertex_normal(mesh, data_color);
break;
}