diff options
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; } |