diff options
Diffstat (limited to 'source/blender/blenkernel')
45 files changed, 597 insertions, 788 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; } |