Mesh: Replace auto smooth with node group #108014

Merged
Hans Goudey merged 149 commits from HooglyBoogly/blender:refactor-mesh-corner-normals-lazy into main 2023-10-20 16:54:20 +02:00
72 changed files with 589 additions and 825 deletions
Showing only changes of commit f44e13579a - Show all commits

View File

@ -119,10 +119,6 @@ const float (*BKE_editmesh_vert_coords_when_deformed(struct Depsgraph *depsgraph
bool *r_is_alloc))[3]; bool *r_is_alloc))[3];
void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me); void BKE_editmesh_lnorspace_update(BMEditMesh *em, struct Mesh *me);
/**
* If auto-smooth not already set, set it.
*/
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, struct Mesh *me);
struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em); struct BoundBox *BKE_editmesh_cage_boundbox_get(struct Object *object, BMEditMesh *em);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -208,7 +208,7 @@ bool BKE_mesh_material_index_used(struct Mesh *me, short index);
void BKE_mesh_material_index_clear(struct Mesh *me); void BKE_mesh_material_index_clear(struct Mesh *me);
void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len); void BKE_mesh_material_remap(struct Mesh *me, const unsigned int *remap, unsigned int remap_len);
void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth); void BKE_mesh_smooth_flag_set(struct Mesh *me, bool use_smooth);
void BKE_mesh_auto_smooth_flag_set(struct Mesh *me, bool use_auto_smooth, float auto_smooth_angle); void BKE_mesh_sharp_edges_set_from_angle(struct Mesh *me, float auto_smooth_angle);
/** /**
* Used for unit testing; compares two meshes, checking only * Used for unit testing; compares two meshes, checking only
@ -321,6 +321,10 @@ const float (*BKE_mesh_vert_normals_ensure(const struct Mesh *mesh))[3];
*/ */
const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3]; const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3];
/**
* See #Mesh::corner_normals().
* \warning May return null if the mesh is empty or has no polygons.
*/
const float (*BKE_mesh_corner_normals_ensure(const struct Mesh *mesh))[3]; const float (*BKE_mesh_corner_normals_ensure(const struct Mesh *mesh))[3];
/** /**
@ -342,8 +346,6 @@ float (*BKE_mesh_vert_normals_for_write(struct Mesh *mesh))[3];
*/ */
void BKE_mesh_vert_normals_clear_dirty(struct Mesh *mesh); void BKE_mesh_vert_normals_clear_dirty(struct Mesh *mesh);
void BKE_mesh_corner_normals_clear_dirty(struct Mesh *mesh);
/** /**
* Return true if the mesh vertex normals either are not stored or are dirty. * 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. * This can be used to help decide whether to transfer them when copying a mesh.

View File

@ -6,6 +6,8 @@
* \ingroup bke * \ingroup bke
*/ */
#include "BLI_virtual_array.hh"
#include "BKE_mesh.h" #include "BKE_mesh.h"
namespace blender::bke::mesh { namespace blender::bke::mesh {
@ -94,10 +96,8 @@ void normals_calc_loop(Span<float3> vert_positions,
Span<int> loop_to_poly_map, Span<int> loop_to_poly_map,
Span<float3> vert_normals, Span<float3> vert_normals,
Span<float3> poly_normals, Span<float3> poly_normals,
const bool *sharp_edges, const VArray<bool> &sharp_edges,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
bool use_split_normals,
float split_angle,
short (*clnors_data)[2], short (*clnors_data)[2],
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
MutableSpan<float3> r_loop_normals); MutableSpan<float3> r_loop_normals);
@ -109,7 +109,7 @@ void normals_loop_custom_set(Span<float3> vert_positions,
Span<int> corner_edges, Span<int> corner_edges,
Span<float3> vert_normals, Span<float3> vert_normals,
Span<float3> poly_normals, Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
MutableSpan<bool> sharp_edges, MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_loop_normals, MutableSpan<float3> r_custom_loop_normals,
short (*r_clnors_data)[2]); short (*r_clnors_data)[2]);
@ -121,7 +121,7 @@ void normals_loop_custom_set_from_verts(Span<float3> vert_positions,
Span<int> corner_edges, Span<int> corner_edges,
Span<float3> vert_normals, Span<float3> vert_normals,
Span<float3> poly_normals, Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
MutableSpan<bool> sharp_edges, MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_vert_normals, MutableSpan<float3> r_custom_vert_normals,
short (*r_clnors_data)[2]); short (*r_clnors_data)[2]);
@ -138,7 +138,7 @@ void edges_sharp_from_angle_set(OffsetIndices<int> polys,
Span<int> corner_verts, Span<int> corner_verts,
Span<int> corner_edges, Span<int> corner_edges,
Span<float3> poly_normals, Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
const float split_angle, const float split_angle,
MutableSpan<bool> sharp_edges); MutableSpan<bool> sharp_edges);

View File

@ -143,13 +143,6 @@ enum {
MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY, MREMAP_MODE_TOPOLOGY = MREMAP_MODE_VERT | MREMAP_MODE_EDGE | MREMAP_MODE_LOOP | MREMAP_MODE_POLY,
}; };
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
int vert_mode,
int edge_mode,
int loop_mode,
int poly_mode,
struct CustomData_MeshMasks *cddata_mask);
/** /**
* Compute a value of the difference between both given meshes. * Compute a value of the difference between both given meshes.
* The smaller the result, the better the match. * The smaller the result, the better the match.
@ -179,7 +172,6 @@ void BKE_mesh_remap_calc_verts_from_mesh(int mode,
float ray_radius, float ray_radius,
const float (*vert_positions_dst)[3], const float (*vert_positions_dst)[3],
int numverts_dst, int numverts_dst,
bool dirty_nors_dst,
const struct Mesh *me_src, const struct Mesh *me_src,
struct Mesh *me_dst, struct Mesh *me_dst,
MeshPairRemap *r_map); MeshPairRemap *r_map);
@ -192,7 +184,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(int mode,
int numverts_dst, int numverts_dst,
const struct MEdge *edges_dst, const struct MEdge *edges_dst,
int numedges_dst, int numedges_dst,
bool dirty_nors_dst,
const struct Mesh *me_src, const struct Mesh *me_src,
struct Mesh *me_dst, struct Mesh *me_dst,
MeshPairRemap *r_map); MeshPairRemap *r_map);
@ -207,19 +198,14 @@ void BKE_mesh_remap_calc_loops_from_mesh(int mode,
const struct SpaceTransform *space_transform, const struct SpaceTransform *space_transform,
float max_dist, float max_dist,
float ray_radius, float ray_radius,
struct Mesh *mesh_dst, const struct Mesh *mesh_dst,
const float (*vert_positions_dst)[3], const float (*vert_positions_dst)[3],
int numverts_dst, int numverts_dst,
const struct MEdge *edges_dst, const struct MEdge *edges_dst,
int numedges_dst, int numedges_dst,
const int *corner_verts_dst, const int *corner_verts_dst,
const int *corner_edges_dst,
int numloops_dst, int numloops_dst,
const blender::OffsetIndices<int> polys_dst, const blender::OffsetIndices<int> polys_dst,
struct CustomData *ldata_dst,
bool use_split_nors_dst,
float split_angle_dst,
bool dirty_nors_dst,
const struct Mesh *me_src, const struct Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, MeshRemapIslandsCalc gen_islands_src,
float islands_precision_src, float islands_precision_src,

View File

@ -45,8 +45,7 @@ void BKE_mesh_runtime_reset_edit_data(struct Mesh *mesh);
* For "smaller" changes to meshes like updating positions, consider calling a more specific update * For "smaller" changes to meshes like updating positions, consider calling a more specific update
* function like #BKE_mesh_tag_positions_changed. * function like #BKE_mesh_tag_positions_changed.
* *
* Also note that some derived caches like #CD_NORMAL and #CD_TANGENT are stored directly in * Also note that some derived caches like #CD_TANGENT are stored directly in #CustomData.
* #CustomData.
*/ */
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh); void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh);

View File

@ -440,27 +440,13 @@ static void add_orco_mesh(
} }
} }
static bool mesh_has_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask,
Mesh *mesh_final)
{
/* Test if mesh has the required loop normals, in case an additional modifier
* evaluation from another instance or from an operator requests it but the
* initial normals were not loop normals. */
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 ||
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
return (!calc_loop_normals || CustomData_has_layer(&mesh_final->ldata, CD_NORMAL));
}
static void mesh_calc_modifier_final_normals(const Mesh *mesh_input, static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
const CustomData_MeshMasks *final_datamask, const CustomData_MeshMasks *final_datamask,
const bool sculpt_dyntopo, const bool sculpt_dyntopo,
Mesh *mesh_final) Mesh *mesh_final)
{ {
/* Compute normals. */ /* Compute normals. */
const bool calc_loop_normals = ((mesh_input->flag & ME_AUTOSMOOTH) != 0 || const bool calc_loop_normals = mesh_final->normal_domain_all_info() == ATTR_DOMAIN_CORNER;
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
/* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */ /* Needed as `final_datamask` is not preserved outside modifier stack evaluation. */
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data; SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
@ -1007,13 +993,6 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
mesh_final = runtime->mesh_eval; mesh_final = runtime->mesh_eval;
} }
} }
else if (!mesh_has_modifier_final_normals(mesh_input, &final_datamask, runtime->mesh_eval)) {
/* Modifier stack was (re-)evaluated with a request for additional normals
* different than the instanced mesh, can't instance anymore now. */
mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final);
mesh_calc_finalize(mesh_input, mesh_final);
}
else { else {
/* Already finalized by another instance, reuse. */ /* Already finalized by another instance, reuse. */
mesh_final = runtime->mesh_eval; mesh_final = runtime->mesh_eval;
@ -1071,8 +1050,7 @@ bool editbmesh_modifier_is_enabled(const Scene *scene,
static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final, static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
const CustomData_MeshMasks *final_datamask) const CustomData_MeshMasks *final_datamask)
{ {
const bool calc_loop_normals = ((mesh_final->flag & ME_AUTOSMOOTH) != 0 || const bool calc_loop_normals = mesh_final->normal_domain_all_info() == ATTR_DOMAIN_CORNER;
(final_datamask->lmask & CD_MASK_NORMAL) != 0);
SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data; SubsurfRuntimeData *subsurf_runtime_data = mesh_final->runtime->subsurf_runtime_data;
if (subsurf_runtime_data) { if (subsurf_runtime_data) {

View File

@ -692,8 +692,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
Mesh *mesh = BKE_mesh_new_nomain( Mesh *mesh = BKE_mesh_new_nomain(
offsets.vert.last(), offsets.edge.last(), offsets.loop.last(), offsets.poly.last()); offsets.vert.last(), offsets.edge.last(), offsets.loop.last(), offsets.poly.last());
mesh->flag |= ME_AUTOSMOOTH;
mesh->smoothresh = DEG2RADF(180.0f);
MutableSpan<float3> positions = mesh->vert_positions_for_write(); MutableSpan<float3> positions = mesh->vert_positions_for_write();
MutableSpan<MEdge> edges = mesh->edges_for_write(); MutableSpan<MEdge> edges = mesh->edges_for_write();
MutableSpan<int> poly_offsets = mesh->poly_offsets_for_write(); MutableSpan<int> poly_offsets = mesh->poly_offsets_for_write();

View File

@ -71,7 +71,7 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types,
r_data_masks->lmask |= CD_MASK_PROP_FLOAT2; r_data_masks->lmask |= CD_MASK_PROP_FLOAT2;
} }
else if (cddata_type == CD_FAKE_LNOR) { else if (cddata_type == CD_FAKE_LNOR) {
r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; r_data_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
} }
} }
} }
@ -347,60 +347,6 @@ static void data_transfer_mesh_attributes_transfer_default_color_string(
/* ********** */ /* ********** */
/* Generic pre/post processing, only used by custom loop normals currently. */
static void data_transfer_dtdata_type_preprocess(const Mesh *me_src,
Mesh *me_dst,
const int dtdata_type,
const bool dirty_nors_dst)
{
if (dtdata_type == DT_TYPE_LNOR) {
/* Compute custom normals into regular loop normals, which will be used for the transfer. */
CustomData *ldata_dst = &me_dst->ldata;
const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
const float split_angle_dst = me_dst->smoothresh;
/* This should be ensured by cddata_masks we pass to code generating/giving us me_src now. */
BLI_assert(CustomData_get_layer(&me_src->ldata, CD_NORMAL) != nullptr);
(void)me_src;
short(*custom_nors_dst)[2] = static_cast<short(*)[2]>(
CustomData_get_layer_for_write(ldata_dst, CD_CUSTOMLOOPNORMAL, me_dst->totloop));
/* Cache loop nors into a temp CDLayer. */
blender::float3 *loop_nors_dst = static_cast<blender::float3 *>(
CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, me_dst->totloop));
const bool do_loop_nors_dst = (loop_nors_dst == nullptr);
if (do_loop_nors_dst) {
loop_nors_dst = static_cast<blender::float3 *>(
CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, me_dst->totloop));
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst || do_loop_nors_dst) {
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face"));
blender::bke::mesh::normals_calc_loop(me_dst->vert_positions(),
me_dst->edges(),
me_dst->polys(),
me_dst->corner_verts(),
me_dst->corner_edges(),
{},
me_dst->vert_normals(),
me_dst->poly_normals(),
sharp_edges,
sharp_faces,
use_split_nors_dst,
split_angle_dst,
custom_nors_dst,
nullptr,
{loop_nors_dst, me_dst->totloop});
}
}
}
static void data_transfer_dtdata_type_postprocess(Mesh *me_dst, static void data_transfer_dtdata_type_postprocess(Mesh *me_dst,
const int dtdata_type, const int dtdata_type,
const bool changed) const bool changed)
@ -426,8 +372,8 @@ static void data_transfer_dtdata_type_postprocess(Mesh *me_dst,
bke::MutableAttributeAccessor attributes = me_dst->attributes_for_write(); bke::MutableAttributeAccessor attributes = me_dst->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>( bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE); "sharp_edge", ATTR_DOMAIN_EDGE);
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
/* Note loop_nors_dst contains our custom normals as transferred from source... */ /* Note loop_nors_dst contains our custom normals as transferred from source... */
blender::bke::mesh::normals_loop_custom_set(me_dst->vert_positions(), blender::bke::mesh::normals_loop_custom_set(me_dst->vert_positions(),
me_dst->edges(), me_dst->edges(),
@ -1303,8 +1249,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
SpaceTransform auto_space_transform; SpaceTransform auto_space_transform;
const Mesh *me_src; const Mesh *me_src;
/* Assumed always true if not using an evaluated mesh as destination. */
bool dirty_nors_dst = true;
const MDeformVert *mdef = nullptr; const MDeformVert *mdef = nullptr;
int vg_idx = -1; int vg_idx = -1;
@ -1323,7 +1267,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH)); BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
if (me_dst) { if (me_dst) {
dirty_nors_dst = BKE_mesh_vert_normals_are_dirty(me_dst);
/* Never create needed custom layers on passed destination mesh /* Never create needed custom layers on passed destination mesh
* (assumed to *not* be ob_dst->data, aka modifier case). */ * (assumed to *not* be ob_dst->data, aka modifier case). */
use_create = false; use_create = false;
@ -1342,8 +1285,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
/* Get source evaluated mesh. */ /* Get source evaluated mesh. */
BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask); BKE_object_data_transfer_dttypes_to_cdmask(data_types, &me_src_mask);
BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
map_vert_mode, map_edge_mode, map_loop_mode, map_poly_mode, &me_src_mask);
if (is_modifier) { if (is_modifier) {
me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src); me_src = BKE_modifier_get_evaluated_mesh_from_evaluated_object(ob_src);
@ -1381,8 +1322,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
continue; continue;
} }
data_transfer_dtdata_type_preprocess(me_src, me_dst, dtdata_type, dirty_nors_dst);
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type); cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type); fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
@ -1436,7 +1375,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
ray_radius, ray_radius,
positions_dst, positions_dst,
num_verts_dst, num_verts_dst,
dirty_nors_dst,
me_src, me_src,
me_dst, me_dst,
&geom_map[VDATA]); &geom_map[VDATA]);
@ -1516,7 +1454,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
num_verts_dst, num_verts_dst,
edges_dst.data(), edges_dst.data(),
edges_dst.size(), edges_dst.size(),
dirty_nors_dst,
me_src, me_src,
me_dst, me_dst,
&geom_map[EDATA]); &geom_map[EDATA]);
@ -1569,8 +1506,6 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
const blender::Span<MEdge> edges_dst = me_dst->edges(); const blender::Span<MEdge> edges_dst = me_dst->edges();
const blender::OffsetIndices polys_dst = me_dst->polys(); const blender::OffsetIndices polys_dst = me_dst->polys();
const blender::Span<int> corner_verts_dst = me_dst->corner_verts(); const blender::Span<int> corner_verts_dst = me_dst->corner_verts();
const blender::Span<int> corner_edges_dst = me_dst->corner_edges();
CustomData *ldata_dst = &me_dst->ldata;
MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type); MeshRemapIslandsCalc island_callback = data_transfer_get_loop_islands_generator(cddata_type);
@ -1610,13 +1545,8 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph,
edges_dst.data(), edges_dst.data(),
edges_dst.size(), edges_dst.size(),
corner_verts_dst.data(), corner_verts_dst.data(),
corner_edges_dst.data(),
corner_verts_dst.size(), corner_verts_dst.size(),
polys_dst, polys_dst,
ldata_dst,
(me_dst->flag & ME_AUTOSMOOTH) != 0,
me_dst->smoothresh,
dirty_nors_dst,
me_src, me_src,
island_callback, island_callback,
islands_handling_precision, islands_handling_precision,

View File

@ -263,31 +263,7 @@ float (*BKE_editmesh_vert_coords_alloc_orco(BMEditMesh *em, int *r_vert_len))[3]
void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me) void BKE_editmesh_lnorspace_update(BMEditMesh *em, Mesh *me)
{ {
BMesh *bm = em->bm; BM_lnorspace_update(em->bm);
/* We need to create custom-loop-normals (CLNORS) data if none exist yet,
* otherwise there is no way to edit them.
* Similar code to #MESH_OT_customdata_custom_splitnormals_add operator,
* we want to keep same shading in case we were using auto-smooth so far.
* NOTE: there is a problem here, which is that if someone starts a normal editing operation on
* previously auto-smooth-ed mesh, and cancel that operation, generated CLNORS data remain,
* with related sharp edges (and hence auto-smooth is 'lost').
* Not sure how critical this is, and how to fix that issue? */
if (!CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
if (me->flag & ME_AUTOSMOOTH) {
BM_edges_sharp_from_angle_set(bm, me->smoothresh);
}
}
BM_lnorspace_update(bm);
}
void BKE_editmesh_ensure_autosmooth(BMEditMesh *em, Mesh *me)
{
if (!(me->flag & ME_AUTOSMOOTH)) {
me->flag |= ME_AUTOSMOOTH;
BKE_editmesh_lnorspace_update(em, me);
}
} }
BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh * /*em*/) BoundBox *BKE_editmesh_cage_boundbox_get(Object *object, BMEditMesh * /*em*/)

View File

@ -32,6 +32,7 @@
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "BKE_anim_data.h" #include "BKE_anim_data.h"
#include "BKE_attribute.hh"
#include "BKE_curve.h" #include "BKE_curve.h"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_deform.h" #include "BKE_deform.h"
@ -2274,12 +2275,13 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
{reinterpret_cast<blender::float3 *>(vert_normals), mesh->totvert}); {reinterpret_cast<blender::float3 *>(vert_normals), mesh->totvert});
} }
if (loop_normals_needed) { if (loop_normals_needed) {
short(*clnors)[2] = static_cast<short(*)[2]>(CustomData_get_layer_for_write( const blender::bke::AttributeAccessor attributes = mesh->attributes();
&mesh->ldata, CD_CUSTOMLOOPNORMAL, corner_verts.size())); /* May be nullptr. */ const blender::VArray<bool> sharp_edges = attributes.lookup_or_default<bool>(
const bool *sharp_edges = static_cast<const bool *>( "sharp_edge", ATTR_DOMAIN_EDGE, false);
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")); const blender::VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
const bool *sharp_faces = static_cast<const bool *>( "sharp_face", ATTR_DOMAIN_FACE, false);
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); const short(*custom_normals)[2] = static_cast<const short(*)[2]>(
CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL));
blender::bke::mesh::normals_calc_loop( blender::bke::mesh::normals_calc_loop(
{reinterpret_cast<const blender::float3 *>(positions), mesh->totvert}, {reinterpret_cast<const blender::float3 *>(positions), mesh->totvert},
edges, edges,
@ -2291,9 +2293,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
{reinterpret_cast<blender::float3 *>(poly_normals), polys.size()}, {reinterpret_cast<blender::float3 *>(poly_normals), polys.size()},
sharp_edges, sharp_edges,
sharp_faces, sharp_faces,
(mesh->flag & ME_AUTOSMOOTH) != 0, custom_normals,
mesh->smoothresh,
clnors,
nullptr, nullptr,
{reinterpret_cast<blender::float3 *>(r_loop_normals), corner_verts.size()}); {reinterpret_cast<blender::float3 *>(r_loop_normals), corner_verts.size()});
} }

View File

@ -1035,7 +1035,6 @@ void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
/* Copy general settings. */ /* Copy general settings. */
me_dst->editflag = me_src->editflag; me_dst->editflag = me_src->editflag;
me_dst->flag = me_src->flag; me_dst->flag = me_src->flag;
me_dst->smoothresh = me_src->smoothresh;
me_dst->remesh_voxel_size = me_src->remesh_voxel_size; me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity; me_dst->remesh_voxel_adaptivity = me_src->remesh_voxel_adaptivity;
me_dst->remesh_mode = me_src->remesh_mode; me_dst->remesh_mode = me_src->remesh_mode;
@ -1521,17 +1520,23 @@ void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
} }
} }
void BKE_mesh_auto_smooth_flag_set(Mesh *me, void BKE_mesh_sharp_edges_set_from_angle(Mesh *me, const float auto_smooth_angle)
const bool use_auto_smooth,
const float auto_smooth_angle)
{ {
if (use_auto_smooth) { using namespace blender;
me->flag |= ME_AUTOSMOOTH; using namespace blender::bke;
me->smoothresh = auto_smooth_angle; bke::MutableAttributeAccessor attributes = me->attributes_for_write();
} bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
else { "sharp_edge", ATTR_DOMAIN_EDGE);
me->flag &= ~ME_AUTOSMOOTH; const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
} "sharp_face", ATTR_DOMAIN_FACE, false);
bke::mesh::edges_sharp_from_angle_set(me->polys(),
me->corner_verts(),
me->corner_edges(),
me->poly_normals(),
sharp_faces,
auto_smooth_angle,
sharp_edges.span);
sharp_edges.finish();
} }
void BKE_mesh_looptri_get_real_edges(const MEdge *edges, void BKE_mesh_looptri_get_real_edges(const MEdge *edges,

View File

@ -1029,7 +1029,6 @@ Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain,
mesh_in_bmain->mat = mesh->mat; mesh_in_bmain->mat = mesh->mat;
mesh_in_bmain->totcol = mesh->totcol; mesh_in_bmain->totcol = mesh->totcol;
mesh_in_bmain->flag = mesh->flag; mesh_in_bmain->flag = mesh->flag;
mesh_in_bmain->smoothresh = mesh->smoothresh;
mesh->mat = nullptr; mesh->mat = nullptr;
BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr); BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr);

View File

@ -165,9 +165,10 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos; const float(*vertexCos)[3] = mesh->runtime->edit_data->vertexCos;
/* XXX: investigate using EditMesh data. */ /* XXX: investigate using EditMesh data. */
const float(*loop_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? blender::Span<blender::float3> corner_normals;
BKE_mesh_corner_normals_ensure(mesh) : if (flag & MESH_FOREACH_USE_NORMAL) {
nullptr; corner_normals = mesh->corner_normals();
}
int f_idx; int f_idx;
@ -180,15 +181,17 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
do { do {
const BMVert *eve = l_iter->v; const BMVert *eve = l_iter->v;
const int v_idx = BM_elem_index_get(eve); const int v_idx = BM_elem_index_get(eve);
const float *no = loop_normals ? *loop_normals++ : nullptr; const float *no = corner_normals.is_empty() ? nullptr :
&corner_normals[BM_elem_index_get(l_iter)].x;
func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no); func(userData, v_idx, f_idx, vertexCos ? vertexCos[v_idx] : eve->co, no);
} while ((l_iter = l_iter->next) != l_first); } while ((l_iter = l_iter->next) != l_first);
} }
} }
else { else {
const float(*loop_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? blender::Span<blender::float3> corner_normals;
BKE_mesh_corner_normals_ensure(mesh) : if (flag & MESH_FOREACH_USE_NORMAL) {
nullptr; corner_normals = mesh->corner_normals();
}
const float(*positions)[3] = BKE_mesh_vert_positions(mesh); const float(*positions)[3] = BKE_mesh_vert_positions(mesh);
const blender::OffsetIndices polys = mesh->polys(); const blender::OffsetIndices polys = mesh->polys();
@ -200,10 +203,11 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
if (v_index || f_index) { if (v_index || f_index) {
for (const int poly_i : polys.index_range()) { for (const int poly_i : polys.index_range()) {
for (const int vert : corner_verts.slice(polys[poly_i])) { for (const int corner : polys[poly_i]) {
const int vert = corner_verts[corner];
const int v_idx = v_index ? v_index[vert] : vert; const int v_idx = v_index ? v_index[vert] : vert;
const int f_idx = f_index ? f_index[poly_i] : poly_i; const int f_idx = f_index ? f_index[poly_i] : poly_i;
const float *no = loop_normals ? *loop_normals++ : nullptr; const float *no = corner_normals.is_empty() ? nullptr : &corner_normals[corner].x;
if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) { if (ELEM(ORIGINDEX_NONE, v_idx, f_idx)) {
continue; continue;
} }
@ -213,11 +217,10 @@ void BKE_mesh_foreach_mapped_loop(Mesh *mesh,
} }
else { else {
for (const int poly_i : polys.index_range()) { for (const int poly_i : polys.index_range()) {
for (const int vert : corner_verts.slice(polys[poly_i])) { for (const int corner : polys[poly_i]) {
const int v_idx = vert; const int vert = corner_verts[corner];
const int f_idx = poly_i; const float *no = corner_normals.is_empty() ? nullptr : &corner_normals[corner].x;
const float *no = loop_normals ? *loop_normals++ : nullptr; func(userData, vert, poly_i, positions[vert], no);
func(userData, v_idx, f_idx, positions[vert], no);
} }
} }
} }

View File

@ -12,6 +12,7 @@
#include "DNA_meshdata_types.h" #include "DNA_meshdata_types.h"
#include "DNA_object_types.h" #include "DNA_object_types.h"
#include "BKE_attribute.hh"
#include "BKE_deform.h" #include "BKE_deform.h"
#include "BKE_lib_id.h" #include "BKE_lib_id.h"
#include "BKE_lib_query.h" #include "BKE_lib_query.h"
@ -375,8 +376,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
} }
/* handle custom split normals */ /* handle custom split normals */
if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && if (ob->type == OB_MESH && CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL) &&
CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL) && result->totpoly > 0) { result->totpoly > 0) {
blender::Array<blender::float3> loop_normals(result_corner_verts.size()); blender::Array<blender::float3> loop_normals(result_corner_verts.size());
CustomData *ldata = &result->ldata; CustomData *ldata = &result->ldata;
short(*clnors)[2] = static_cast<short(*)[2]>( short(*clnors)[2] = static_cast<short(*)[2]>(
@ -391,10 +392,11 @@ 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 */ /* calculate custom normals into loop_normals, then mirror first half into second half */
const bool *sharp_edges = static_cast<const bool *>( const blender::bke::AttributeAccessor attributes = result->attributes();
CustomData_get_layer_named(&result->edata, CD_PROP_BOOL, "sharp_edge")); const blender::VArray<bool> sharp_edges = attributes.lookup_or_default<bool>(
const bool *sharp_faces = static_cast<const bool *>( "sharp_edge", ATTR_DOMAIN_EDGE, false);
CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); const blender::VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
blender::bke::mesh::normals_calc_loop(result->vert_positions(), blender::bke::mesh::normals_calc_loop(result->vert_positions(),
result_edges, result_edges,
result_polys, result_polys,
@ -405,8 +407,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
result->poly_normals(), result->poly_normals(),
sharp_edges, sharp_edges,
sharp_faces, sharp_faces,
true,
result->smoothresh,
clnors, clnors,
&lnors_spacearr, &lnors_spacearr,
loop_normals); loop_normals);

View File

@ -313,6 +313,103 @@ void normals_calc_poly_vert(const Span<float3> positions,
/** \name Mesh Normal Calculation /** \name Mesh Normal Calculation
* \{ */ * \{ */
enum class BoolArrayMix {
None,
AllFalse,
AllTrue,
Mixed,
};
BoolArrayMix bool_array_mix_calc(const VArray<bool> &varray,
const blender::IndexRange range_to_check)
{
using namespace blender;
if (varray.is_empty()) {
return BoolArrayMix::None;
}
const CommonVArrayInfo info = varray.common_info();
if (info.type == CommonVArrayInfo::Type::Single) {
return *static_cast<const bool *>(info.data) ? BoolArrayMix::AllTrue : BoolArrayMix::AllFalse;
}
if (info.type == CommonVArrayInfo::Type::Span) {
const Span<bool> span(static_cast<const bool *>(info.data), varray.size());
return threading::parallel_reduce(
range_to_check,
4096,
BoolArrayMix::None,
[&](const IndexRange range, const BoolArrayMix init) {
if (init == BoolArrayMix::Mixed) {
return init;
}
const Span<bool> slice = span.slice(range);
const bool first = slice.first();
for (const bool value : slice.drop_front(1)) {
if (value != first) {
return BoolArrayMix::Mixed;
}
}
return first ? BoolArrayMix::AllTrue : BoolArrayMix::AllFalse;
},
[&](BoolArrayMix a, BoolArrayMix b) { return (a == b) ? a : BoolArrayMix::Mixed; });
}
return threading::parallel_reduce(
range_to_check,
2048,
BoolArrayMix::None,
[&](const IndexRange range, const BoolArrayMix init) {
if (init == BoolArrayMix::Mixed) {
return init;
}
/* Alternatively, this could use #materialize to retrieve many values at once. */
const bool first = varray[range.first()];
for (const int64_t i : range.drop_front(1)) {
if (varray[i] != first) {
return BoolArrayMix::Mixed;
}
}
return first ? BoolArrayMix::AllTrue : BoolArrayMix::AllFalse;
},
[&](BoolArrayMix a, BoolArrayMix b) { return (a == b) ? a : BoolArrayMix::Mixed; });
}
BoolArrayMix bool_array_mix_calc(const VArray<bool> &varray)
{
return bool_array_mix_calc(varray, varray.index_range());
}
eAttrDomain Mesh::normal_domain_all_info() const
{
using namespace blender;
using namespace blender::bke;
const short(*custom_normals)[2] = static_cast<const short(*)[2]>(
CustomData_get_layer(&this->ldata, CD_CUSTOMLOOPNORMAL));
if (custom_normals) {
return ATTR_DOMAIN_CORNER;
}
const AttributeAccessor attributes = this->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const BoolArrayMix face_mix = bool_array_mix_calc(sharp_faces);
if (face_mix == BoolArrayMix::AllTrue) {
return ATTR_DOMAIN_FACE;
}
const VArray<bool> sharp_edges = attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const BoolArrayMix edge_mix = bool_array_mix_calc(sharp_edges);
if (edge_mix == BoolArrayMix::AllTrue) {
return ATTR_DOMAIN_FACE;
}
if (edge_mix == BoolArrayMix::AllFalse && face_mix == BoolArrayMix::AllFalse) {
return ATTR_DOMAIN_POINT;
}
return ATTR_DOMAIN_CORNER;
}
blender::Span<blender::float3> Mesh::vert_normals() const blender::Span<blender::float3> Mesh::vert_normals() const
{ {
if (!this->runtime->vert_normals_dirty) { if (!this->runtime->vert_normals_dirty) {
@ -383,63 +480,77 @@ const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3]
return reinterpret_cast<const float(*)[3]>(mesh->vert_normals().data()); return reinterpret_cast<const float(*)[3]>(mesh->vert_normals().data());
} }
const float (*BKE_mesh_corner_normals_ensure(const Mesh *mesh))[3] blender::Span<blender::float3> Mesh::corner_normals() const
{ {
if (!BKE_mesh_corner_normals_are_dirty(mesh)) { using namespace blender;
BLI_assert(mesh->runtime->corner_normals != nullptr || mesh->totloop == 0); using namespace blender::bke;
return mesh->runtime->corner_normals; if (!this->runtime->corner_normals_dirty) {
BLI_assert(this->runtime->corner_normals.size() == this->totloop);
return this->runtime->corner_normals;
} }
if (mesh->totpoly == 0) { std::lock_guard lock{this->runtime->normals_mutex};
return nullptr; if (!this->runtime->corner_normals_dirty) {
BLI_assert(this->runtime->corner_normals.size() == this->totloop);
return this->runtime->corner_normals;
} }
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
std::lock_guard lock{mesh->runtime->normals_mutex};
if (!BKE_mesh_corner_normals_are_dirty(mesh)) {
BLI_assert(mesh->runtime->corner_normals != nullptr);
return mesh->runtime->corner_normals;
}
float(*corner_normals)[3];
/* Isolate task because a mutex is locked and computing normals is multi-threaded. */ /* Isolate task because a mutex is locked and computing normals is multi-threaded. */
blender::threading::isolate_task([&]() { threading::isolate_task([&]() {
Mesh &mesh_mutable = *const_cast<Mesh *>(mesh); const OffsetIndices polys = this->polys();
const Span<MVert> verts = mesh_mutable.verts(); this->runtime->corner_normals.reinitialize(this->totloop);
const Span<MEdge> edges = mesh_mutable.edges(); MutableSpan<float3> corner_normals = this->runtime->corner_normals;
const Span<MPoly> polys = mesh_mutable.polys(); switch (this->normal_domain_all_info()) {
const Span<MLoop> loops = mesh_mutable.loops(); case ATTR_DOMAIN_POINT: {
array_utils::gather(this->vert_normals(), this->corner_verts(), corner_normals);
break;
}
case ATTR_DOMAIN_FACE: {
const Span<float3> poly_normals = this->poly_normals();
threading::parallel_for(poly_normals.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
corner_normals.slice(polys[i]).fill(poly_normals[i]);
}
});
break;
}
case ATTR_DOMAIN_CORNER: {
const AttributeAccessor attributes = this->attributes();
const VArray<bool> sharp_edges = attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const short(*custom_normals)[2] = static_cast<const short(*)[2]>(
CustomData_get_layer(&this->ldata, CD_CUSTOMLOOPNORMAL));
if (mesh_mutable.runtime->corner_normals == nullptr) { bke::mesh::normals_calc_loop(this->vert_positions(),
mesh_mutable.runtime->corner_normals = (float(*)[3])MEM_malloc_arrayN( this->edges(),
mesh_mutable.totloop, sizeof(float[3]), __func__); this->polys(),
this->corner_verts(),
this->corner_edges(),
{},
this->vert_normals(),
this->poly_normals(),
sharp_edges,
sharp_faces,
custom_normals,
nullptr,
this->runtime->corner_normals);
break;
}
default:
BLI_assert_unreachable();
} }
const short(*custom_normals)[2] = (const short(*)[2])CustomData_get_layer(&mesh->ldata, this->runtime->corner_normals_dirty = false;
CD_CUSTOMLOOPNORMAL);
BKE_mesh_normals_loop_split(verts.data(),
vert_normals,
verts.size(),
edges.data(),
edges.size(),
loops.data(),
corner_normals,
loops.size(),
polys.data(),
poly_normals,
polys.size(),
true,
mesh->smoothresh,
nullptr,
custom_normals,
nullptr);
BKE_mesh_corner_normals_clear_dirty(&mesh_mutable);
}); });
return this->runtime->corner_normals;
}
const float (*BKE_mesh_corner_normals_ensure(const Mesh *mesh))[3]
{
return reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data());
} }
void BKE_mesh_ensure_normals_for_display(Mesh *mesh) void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
@ -782,17 +893,14 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> polys,
const Span<int> corner_edges, const Span<int> corner_edges,
const Span<int> loop_to_poly_map, const Span<int> loop_to_poly_map,
const Span<float3> poly_normals, const Span<float3> poly_normals,
const Span<bool> sharp_faces, const VArray<bool> &sharp_faces,
const Span<bool> sharp_edges, const VArray<bool> &sharp_edges,
const bool check_angle, const bool check_angle,
const float split_angle, const float split_angle,
MutableSpan<int2> edge_to_loops, MutableSpan<int2> edge_to_loops,
MutableSpan<bool> r_sharp_edges) MutableSpan<bool> r_sharp_edges)
{ {
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
auto poly_is_smooth = [&](const int poly_i) {
return sharp_faces.is_empty() || !sharp_faces[poly_i];
};
for (const int poly_i : polys.index_range()) { for (const int poly_i : polys.index_range()) {
for (const int loop_index : polys[poly_i]) { for (const int loop_index : polys[poly_i]) {
@ -806,7 +914,7 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> polys,
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = loop_index; e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */ /* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = (poly_is_smooth(poly_i)) ? INDEX_UNSET : INDEX_INVALID; e2l[1] = sharp_faces[poly_i] ? INDEX_INVALID : INDEX_UNSET;
} }
else if (e2l[1] == INDEX_UNSET) { else if (e2l[1] == INDEX_UNSET) {
const bool is_angle_sharp = (check_angle && const bool is_angle_sharp = (check_angle &&
@ -818,14 +926,14 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> polys,
* or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its polys' normals is above split_angle value. * same vertex, or angle between both its polys' normals is above split_angle value.
*/ */
if (!poly_is_smooth(poly_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) || if (sharp_faces[poly_i] || sharp_edges[edge_i] || vert_i == corner_verts[e2l[0]] ||
vert_i == corner_verts[e2l[0]] || is_angle_sharp) { is_angle_sharp) {
/* NOTE: we are sure that loop != 0 here ;). */ /* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID; e2l[1] = INDEX_INVALID;
/* We want to avoid tagging edges as sharp when it is already defined as such by /* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */ * other causes than angle threshold. */
if (!r_sharp_edges.is_empty() && is_angle_sharp) { if (is_angle_sharp) {
r_sharp_edges[edge_i] = true; r_sharp_edges[edge_i] = true;
} }
} }
@ -839,9 +947,52 @@ static void mesh_edges_sharp_tag(const OffsetIndices<int> polys,
/* We want to avoid tagging edges as sharp when it is already defined as such by /* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */ * other causes than angle threshold. */
if (!r_sharp_edges.is_empty()) {
r_sharp_edges[edge_i] = false; r_sharp_edges[edge_i] = false;
} }
/* Else, edge is already 'disqualified' (i.e. sharp)! */
}
}
}
static void build_edge_to_loop_map(const OffsetIndices<int> polys,
const Span<int> corner_verts,
const Span<int> corner_edges,
const VArray<bool> &sharp_faces,
const VArray<bool> &sharp_edges,
MutableSpan<int2> edge_to_loops)
{
for (const int poly_i : polys.index_range()) {
for (const int loop_index : polys[poly_i]) {
const int vert_i = corner_verts[loop_index];
const int edge_i = corner_edges[loop_index];
int2 &e2l = edge_to_loops[edge_i];
/* Check whether current edge might be smooth or sharp */
if ((e2l[0] | e2l[1]) == 0) {
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = sharp_faces[poly_i] ? INDEX_INVALID : INDEX_UNSET;
}
else if (e2l[1] == INDEX_UNSET) {
/* Second loop using this edge, time to test its sharpness.
* An edge is sharp if it is tagged as such, or its face is not smooth,
* or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its polys' normals is above split_angle value.
*/
if (sharp_faces[poly_i] || sharp_edges[edge_i] || vert_i == corner_verts[e2l[0]]) {
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
}
else {
e2l[1] = loop_index;
}
}
else if (!IS_EDGE_SHARP(e2l)) {
/* More than two loops using this edge, tag as sharp if not yet done. */
e2l[1] = INDEX_INVALID;
} }
/* Else, edge is already 'disqualified' (i.e. sharp)! */ /* Else, edge is already 'disqualified' (i.e. sharp)! */
} }
@ -852,7 +1003,7 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> polys,
const Span<int> corner_verts, const Span<int> corner_verts,
const Span<int> corner_edges, const Span<int> corner_edges,
const Span<float3> poly_normals, const Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
const float split_angle, const float split_angle,
MutableSpan<bool> sharp_edges) MutableSpan<bool> sharp_edges)
{ {
@ -872,8 +1023,8 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> polys,
corner_edges, corner_edges,
loop_to_poly, loop_to_poly,
poly_normals, poly_normals,
Span<bool>(sharp_faces, sharp_faces ? polys.size() : 0), sharp_faces,
sharp_edges, VArray<bool>::ForSpan(sharp_edges),
true, true,
split_angle, split_angle,
edge_to_loops, edge_to_loops,
@ -1436,39 +1587,12 @@ void normals_calc_loop(const Span<float3> vert_positions,
const Span<int> loop_to_poly_map, const Span<int> loop_to_poly_map,
const Span<float3> vert_normals, const Span<float3> vert_normals,
const Span<float3> poly_normals, const Span<float3> poly_normals,
const bool *sharp_edges, const VArray<bool> &sharp_edges,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
bool use_split_normals,
float split_angle,
short (*clnors_data)[2], short (*clnors_data)[2],
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
MutableSpan<float3> r_loop_normals) MutableSpan<float3> r_loop_normals)
{ {
/* For now this is not supported.
* If we do not use split normals, we do not generate anything fancy! */
BLI_assert(use_split_normals || !(r_lnors_spacearr));
if (!use_split_normals) {
/* In this case, simply fill `r_loop_normals` with `vert_normals`
* (or `poly_normals` for flat faces), quite simple!
* Note this is done here to keep some logic and consistency in this quite complex code,
* since we may want to use loop_normals even when mesh's 'autosmooth' is disabled
* (see e.g. mesh mapping code). As usual, we could handle that on case-by-case basis,
* but simpler to keep it well confined here. */
for (const int poly_index : polys.index_range()) {
const bool is_poly_flat = sharp_faces && sharp_faces[poly_index];
for (const int corner : polys[poly_index]) {
if (is_poly_flat) {
copy_v3_v3(r_loop_normals[corner], poly_normals[poly_index]);
}
else {
copy_v3_v3(r_loop_normals[corner], vert_normals[corner_verts[corner]]);
}
}
}
return;
}
/** /**
* Mapping edge -> loops. * Mapping edge -> loops.
* If that edge is used by more than two loops (polys), * If that edge is used by more than two loops (polys),
@ -1496,9 +1620,6 @@ void normals_calc_loop(const Span<float3> vert_positions,
loop_to_poly = loop_to_poly_map; loop_to_poly = loop_to_poly_map;
} }
/* When using custom loop normals, disable the angle feature! */
const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr);
MLoopNorSpaceArray _lnors_spacearr = {nullptr}; MLoopNorSpaceArray _lnors_spacearr = {nullptr};
#ifdef DEBUG_TIME #ifdef DEBUG_TIME
@ -1534,17 +1655,8 @@ void normals_calc_loop(const Span<float3> vert_positions,
array_utils::gather(vert_normals, corner_verts, r_loop_normals, 1024); array_utils::gather(vert_normals, corner_verts, r_loop_normals, 1024);
/* This first loop check which edges are actually smooth, and compute edge vectors. */ /* This first loop check which edges are actually smooth, and compute edge vectors. */
mesh_edges_sharp_tag(polys, build_edge_to_loop_map(
corner_verts, polys, corner_verts, corner_edges, sharp_faces, sharp_edges, edge_to_loops);
corner_edges,
loop_to_poly,
poly_normals,
Span<bool>(sharp_faces, sharp_faces ? polys.size() : 0),
Span<bool>(sharp_edges, sharp_edges ? edges.size() : 0),
check_angle,
split_angle,
edge_to_loops,
{});
if (corner_verts.size() < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { if (corner_verts.size() < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead. */ /* Not enough loops to be worth the whole threading overhead. */
@ -1588,7 +1700,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
Span<int> corner_edges, Span<int> corner_edges,
Span<float3> vert_normals, Span<float3> vert_normals,
Span<float3> poly_normals, Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
const bool use_vertices, const bool use_vertices,
MutableSpan<float3> r_custom_loop_normals, MutableSpan<float3> r_custom_loop_normals,
MutableSpan<bool> sharp_edges, MutableSpan<bool> sharp_edges,
@ -1603,10 +1715,6 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
BitVector<> done_loops(corner_verts.size(), false); BitVector<> done_loops(corner_verts.size(), false);
Array<float3> loop_normals(corner_verts.size()); Array<float3> loop_normals(corner_verts.size());
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map(polys);
/* In this case we always consider split nors as ON,
* and do not want to use angle to define smooth fans! */
const bool use_split_normals = true;
const float split_angle = float(M_PI);
BLI_SMALLSTACK_DECLARE(clnors_data, short *); BLI_SMALLSTACK_DECLARE(clnors_data, short *);
@ -1619,10 +1727,8 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
loop_to_poly, loop_to_poly,
vert_normals, vert_normals,
poly_normals, poly_normals,
sharp_edges.data(), VArray<bool>::ForSpan(sharp_edges),
sharp_faces, sharp_faces,
use_split_normals,
split_angle,
r_clnors_data, r_clnors_data,
&lnors_spacearr, &lnors_spacearr,
loop_normals); loop_normals);
@ -1745,10 +1851,8 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
loop_to_poly, loop_to_poly,
vert_normals, vert_normals,
poly_normals, poly_normals,
sharp_edges.data(), VArray<bool>::ForSpan(sharp_edges),
sharp_faces, sharp_faces,
use_split_normals,
split_angle,
r_clnors_data, r_clnors_data,
&lnors_spacearr, &lnors_spacearr,
loop_normals); loop_normals);
@ -1819,7 +1923,7 @@ void normals_loop_custom_set(const Span<float3> vert_positions,
const Span<int> corner_edges, const Span<int> corner_edges,
const Span<float3> vert_normals, const Span<float3> vert_normals,
const Span<float3> poly_normals, const Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
MutableSpan<bool> sharp_edges, MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_loop_normals, MutableSpan<float3> r_custom_loop_normals,
short (*r_clnors_data)[2]) short (*r_clnors_data)[2])
@ -1845,7 +1949,7 @@ void normals_loop_custom_set_from_verts(const Span<float3> vert_positions,
const Span<int> corner_edges, const Span<int> corner_edges,
const Span<float3> vert_normals, const Span<float3> vert_normals,
const Span<float3> poly_normals, const Span<float3> poly_normals,
const bool *sharp_faces, const VArray<bool> &sharp_faces,
MutableSpan<bool> sharp_edges, MutableSpan<bool> sharp_edges,
MutableSpan<float3> r_custom_vert_normals, MutableSpan<float3> r_custom_vert_normals,
short (*r_clnors_data)[2]) short (*r_clnors_data)[2])
@ -1881,8 +1985,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
MutableAttributeAccessor attributes = mesh->attributes_for_write(); MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>( SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE); "sharp_edge", ATTR_DOMAIN_EDGE);
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
mesh_normals_loop_custom_set(mesh->vert_positions(), mesh_normals_loop_custom_set(mesh->vert_positions(),
mesh->edges(), mesh->edges(),

View File

@ -296,20 +296,6 @@ void BKE_mesh_remap_find_best_match_from_mesh(const float (*vert_positions_dst)[
/** \name Mesh to Mesh Mapping /** \name Mesh to Mesh Mapping
* \{ */ * \{ */
void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int /*vert_mode*/,
const int /*edge_mode*/,
const int loop_mode,
const int /*poly_mode*/,
CustomData_MeshMasks *r_cddata_mask)
{
/* vert, edge and poly mapping modes never need extra cddata from source object. */
const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL);
if (need_lnors_src) {
r_cddata_mask->lmask |= CD_MASK_NORMAL;
}
}
void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num) void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num)
{ {
MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); MemArena *mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
@ -462,7 +448,6 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode,
const float ray_radius, const float ray_radius,
const float (*vert_positions_dst)[3], const float (*vert_positions_dst)[3],
const int numverts_dst, const int numverts_dst,
const bool /*dirty_nors_dst*/,
const Mesh *me_src, const Mesh *me_src,
Mesh *me_dst, Mesh *me_dst,
MeshPairRemap *r_map) MeshPairRemap *r_map)
@ -685,7 +670,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode,
const int numverts_dst, const int numverts_dst,
const MEdge *edges_dst, const MEdge *edges_dst,
const int numedges_dst, const int numedges_dst,
const bool /*dirty_nors_dst*/,
const Mesh *me_src, const Mesh *me_src,
Mesh *me_dst, Mesh *me_dst,
MeshPairRemap *r_map) MeshPairRemap *r_map)
@ -1219,19 +1203,14 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
const SpaceTransform *space_transform, const SpaceTransform *space_transform,
const float max_dist, const float max_dist,
const float ray_radius, const float ray_radius,
Mesh *mesh_dst, const Mesh *mesh_dst,
const float (*vert_positions_dst)[3], const float (*vert_positions_dst)[3],
const int numverts_dst, const int numverts_dst,
const MEdge *edges_dst, const MEdge *edges_dst,
const int numedges_dst, const int numedges_dst,
const int *corner_verts_dst, const int *corner_verts_dst,
const int *corner_edges_dst,
const int numloops_dst, const int numloops_dst,
const blender::OffsetIndices<int> polys_dst, const blender::OffsetIndices<int> polys_dst,
CustomData *ldata_dst,
const bool use_split_nors_dst,
const float split_angle_dst,
const bool dirty_nors_dst,
const Mesh *me_src, const Mesh *me_src,
MeshRemapIslandsCalc gen_islands_src, MeshRemapIslandsCalc gen_islands_src,
const float islands_precision_src, const float islands_precision_src,
@ -1276,7 +1255,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
blender::Span<blender::float3> loop_normals_src; blender::Span<blender::float3> loop_normals_src;
blender::Span<blender::float3> poly_normals_dst; blender::Span<blender::float3> poly_normals_dst;
blender::float3 *loop_normals_dst; blender::Span<blender::float3> loop_normals_dst;
blender::Array<blender::float3> poly_cents_src; blender::Array<blender::float3> poly_cents_src;
@ -1333,13 +1312,13 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
poly_normals_dst = mesh_dst->poly_normals(); poly_normals_dst = mesh_dst->poly_normals();
} }
if (need_lnors_dst) { if (need_lnors_dst) {
loop_normals_dst = BKE_mesh_corner_normals_ensure(mesh_dst); loop_normals_dst = mesh_dst->corner_normals();
} }
if (need_pnors_src) { if (need_pnors_src) {
poly_normals_src = BKE_mesh_poly_normals_ensure(me_src); poly_normals_src = me_src->poly_normals();
} }
if (need_lnors_src) { if (need_lnors_src) {
loop_normals_src = BKE_mesh_corner_normals_ensure(me_src); loop_normals_src = me_src->corner_normals();
} }
} }

View File

@ -135,11 +135,12 @@ void BKE_mesh_calc_loop_tangent_single(Mesh *mesh,
return; return;
} }
BKE_mesh_calc_loop_tangent_single_ex(BKE_mesh_vert_positions(mesh), BKE_mesh_calc_loop_tangent_single_ex(
BKE_mesh_vert_positions(mesh),
mesh->totvert, mesh->totvert,
mesh->corner_verts().data(), mesh->corner_verts().data(),
r_looptangents, r_looptangents,
BKE_mesh_corner_normals_ensure(mesh), reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
reinterpret_cast<const float(*)[2]>(uv_map.data()), reinterpret_cast<const float(*)[2]>(uv_map.data()),
mesh->totloop, mesh->totloop,
mesh->polys(), mesh->polys(),
@ -579,7 +580,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
tangent_names_len, tangent_names_len,
reinterpret_cast<const float(*)[3]>(me_eval->vert_normals().data()), reinterpret_cast<const float(*)[3]>(me_eval->vert_normals().data()),
reinterpret_cast<const float(*)[3]>(me_eval->poly_normals().data()), reinterpret_cast<const float(*)[3]>(me_eval->poly_normals().data()),
BKE_mesh_corner_normals_ensure(me_eval), reinterpret_cast<const float(*)[3]>(me_eval->corner_normals().data()),
/* may be nullptr */ /* may be nullptr */
static_cast<const float(*)[3]>(CustomData_get_layer(&me_eval->vdata, CD_ORCO)), static_cast<const float(*)[3]>(CustomData_get_layer(&me_eval->vdata, CD_ORCO)),
/* result */ /* result */

View File

@ -338,8 +338,8 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me)
Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me); Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me);
if (use_clnors) { if (use_clnors) {
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(subdiv_mesh); BKE_mesh_set_custom_normals(
BKE_mesh_set_custom_normals(subdiv_mesh, lnors); subdiv_mesh, reinterpret_cast<const float(*)[3]>(subdiv_mesh->corner_normals().data()));
} }
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) { if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {

View File

@ -138,8 +138,8 @@ bool BKE_shrinkwrap_init_tree(
if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) { if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) {
data->poly_normals = reinterpret_cast<const float(*)[3]>(mesh->poly_normals().data()); data->poly_normals = reinterpret_cast<const float(*)[3]>(mesh->poly_normals().data());
if ((mesh->flag & ME_AUTOSMOOTH) != 0) { if (mesh->normal_domain_all_info() == ATTR_DOMAIN_CORNER) {
data->clnors = BKE_mesh_corner_normals_ensure(mesh); data->clnors = reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data());
} }
} }

View File

@ -84,14 +84,8 @@ static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene,
bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh) bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd, const Mesh *mesh)
{ {
return (smd->flags & eSubsurfModifierFlag_UseCustomNormals) && (mesh->flag & ME_AUTOSMOOTH) && return smd->flags & eSubsurfModifierFlag_UseCustomNormals &&
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); mesh->normal_domain_all_info() == ATTR_DOMAIN_CORNER;
}
static bool subsurf_modifier_use_autosmooth_or_split_normals(const SubsurfModifierData *smd,
const Mesh *mesh)
{
return (mesh->flag & ME_AUTOSMOOTH) || BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
} }
static bool is_subdivision_evaluation_possible_on_gpu() static bool is_subdivision_evaluation_possible_on_gpu()
@ -125,7 +119,7 @@ bool BKE_subsurf_modifier_force_disable_gpu_evaluation_for_mesh(const SubsurfMod
return false; return false;
} }
return subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh); return BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
} }
bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene, bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
@ -140,7 +134,7 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
/* Deactivate GPU subdivision if autosmooth or custom split normals are used as those are /* Deactivate GPU subdivision if autosmooth or custom split normals are used as those are
* complicated to support on GPU, and should really be separate workflows. */ * complicated to support on GPU, and should really be separate workflows. */
if (subsurf_modifier_use_autosmooth_or_split_normals(smd, mesh)) { if (BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh)) {
return false; return false;
} }

View File

@ -989,7 +989,6 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors(
const float (*fnos)[3], const float (*fnos)[3],
float (*r_lnos)[3], float (*r_lnos)[3],
const bool do_rebuild, const bool do_rebuild,
const float split_angle_cos,
/* TLS */ /* TLS */
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
BLI_Stack *edge_vectors, BLI_Stack *edge_vectors,
@ -1067,8 +1066,7 @@ static void bm_mesh_loops_calc_normals__single_threaded(BMesh *bm,
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
const short (*clnors_data)[2], const short (*clnors_data)[2],
const int cd_loop_clnors_offset, const int cd_loop_clnors_offset,
const bool do_rebuild, const bool do_rebuild)
const float split_angle_cos)
{ {
BMIter fiter; BMIter fiter;
BMFace *f_curr; BMFace *f_curr;
@ -1161,7 +1159,6 @@ typedef struct BMLoopsCalcNormalsWithCoordsData {
const short (*clnors_data)[2]; const short (*clnors_data)[2];
int cd_loop_clnors_offset; int cd_loop_clnors_offset;
bool do_rebuild; bool do_rebuild;
float split_angle_cos;
/* Output. */ /* Output. */
float (*r_lnos)[3]; float (*r_lnos)[3];
@ -1254,7 +1251,6 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors_fn(
data->r_lnos, data->r_lnos,
data->do_rebuild, data->do_rebuild,
data->split_angle_cos,
/* Thread local. */ /* Thread local. */
tls_data->lnors_spacearr, tls_data->lnors_spacearr,
tls_data->edge_vectors, tls_data->edge_vectors,
@ -1269,8 +1265,7 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
const short (*clnors_data)[2], const short (*clnors_data)[2],
const int cd_loop_clnors_offset, const int cd_loop_clnors_offset,
const bool do_rebuild, const bool do_rebuild)
const float split_angle_cos)
{ {
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
MLoopNorSpaceArray _lnors_spacearr = {nullptr}; MLoopNorSpaceArray _lnors_spacearr = {nullptr};
@ -1321,7 +1316,6 @@ static void bm_mesh_loops_calc_normals__multi_threaded(BMesh *bm,
data.clnors_data = clnors_data; data.clnors_data = clnors_data;
data.cd_loop_clnors_offset = cd_loop_clnors_offset; data.cd_loop_clnors_offset = cd_loop_clnors_offset;
data.do_rebuild = do_rebuild; data.do_rebuild = do_rebuild;
data.split_angle_cos = split_angle_cos;
BM_iter_parallel(bm, BM_iter_parallel(bm,
BM_VERTS_OF_MESH, BM_VERTS_OF_MESH,
@ -1344,30 +1338,15 @@ static void bm_mesh_loops_calc_normals(BMesh *bm,
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
const short (*clnors_data)[2], const short (*clnors_data)[2],
const int cd_loop_clnors_offset, const int cd_loop_clnors_offset,
const bool do_rebuild, const bool do_rebuild)
const float split_angle_cos)
{ {
if (bm->totloop < BM_OMP_LIMIT) { if (bm->totloop < BM_OMP_LIMIT) {
bm_mesh_loops_calc_normals__single_threaded(bm, bm_mesh_loops_calc_normals__single_threaded(
vcos, bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
fnos,
r_lnos,
r_lnors_spacearr,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
split_angle_cos);
} }
else { else {
bm_mesh_loops_calc_normals__multi_threaded(bm, bm_mesh_loops_calc_normals__multi_threaded(
vcos, bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
fnos,
r_lnos,
r_lnors_spacearr,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
split_angle_cos);
} }
} }
@ -1689,7 +1668,6 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vnos)[3], const float (*vnos)[3],
const float (*fnos)[3], const float (*fnos)[3],
const bool use_split_normals, const bool use_split_normals,
const float split_angle,
float (*r_lnos)[3], float (*r_lnos)[3],
MLoopNorSpaceArray *r_lnors_spacearr, MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2], short (*clnors_data)[2],
@ -1699,15 +1677,8 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1); const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
if (use_split_normals) { if (use_split_normals) {
bm_mesh_loops_calc_normals(bm, bm_mesh_loops_calc_normals(
vcos, bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset, do_rebuild);
fnos,
r_lnos,
r_lnors_spacearr,
clnors_data,
cd_loop_clnors_offset,
do_rebuild,
has_clnors ? -1.0f : cosf(split_angle));
} }
else { else {
BLI_assert(!r_lnors_spacearr); BLI_assert(!r_lnors_spacearr);
@ -1736,7 +1707,6 @@ void BM_lnorspacearr_store(BMesh *bm, float (*r_lnors)[3])
nullptr, nullptr,
nullptr, nullptr,
true, true,
M_PI,
r_lnors, r_lnors,
bm->lnor_spacearr, bm->lnor_spacearr,
nullptr, nullptr,
@ -1861,7 +1831,6 @@ void BM_lnorspace_rebuild(BMesh *bm, bool preserve_clnor)
nullptr, nullptr,
nullptr, nullptr,
true, true,
M_PI,
r_lnors, r_lnors,
bm->lnor_spacearr, bm->lnor_spacearr,
nullptr, nullptr,
@ -1937,17 +1906,8 @@ void BM_lnorspace_err(BMesh *bm)
int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL); int cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__)); float(*lnors)[3] = static_cast<float(*)[3]>(MEM_callocN(sizeof(*lnors) * bm->totloop, __func__));
BM_loops_calc_normal_vcos(bm, BM_loops_calc_normal_vcos(
nullptr, bm, nullptr, nullptr, nullptr, true, lnors, temp, nullptr, cd_loop_clnors_offset, true);
nullptr,
nullptr,
true,
M_PI,
lnors,
temp,
nullptr,
cd_loop_clnors_offset,
true);
for (int i = 0; i < bm->totloop; i++) { for (int i = 0; i < bm->totloop; i++) {
int j = 0; int j = 0;

View File

@ -60,7 +60,6 @@ void BM_loops_calc_normal_vcos(BMesh *bm,
const float (*vnos)[3], const float (*vnos)[3],
const float (*fnos)[3], const float (*fnos)[3],
bool use_split_normals, bool use_split_normals,
float split_angle,
float (*r_lnos)[3], float (*r_lnos)[3],
struct MLoopNorSpaceArray *r_lnors_spacearr, struct MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2], short (*clnors_data)[2],

View File

@ -1329,7 +1329,6 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0;
if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) { if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) {
add_customdata_mask(ct->tar, add_customdata_mask(ct->tar,
DEGCustomDataMeshMasks::MaskVert(CD_MASK_NORMAL) |
DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL)); DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL));
} }
if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) {

View File

@ -338,8 +338,6 @@ void mesh_render_data_update_looptris(MeshRenderData *mr,
void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag) void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag)
{ {
Mesh *me = mr->me; Mesh *me = mr->me;
const bool is_auto_smooth = (me->flag & ME_AUTOSMOOTH) != 0;
const float split_angle = is_auto_smooth ? me->smoothresh : float(M_PI);
if (mr->extract_type != MR_EXTRACT_BMESH) { if (mr->extract_type != MR_EXTRACT_BMESH) {
HooglyBoogly marked this conversation as resolved Outdated

Looks like there is a "not" missing. Same below.

Looks like there is a "not" missing. Same below.
/* Mesh */ /* Mesh */
@ -347,7 +345,9 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) { if (data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR | MR_DATA_TAN_LOOP_NOR)) {
mr->poly_normals = mr->me->poly_normals(); mr->poly_normals = mr->me->poly_normals();
} }
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { if (((data_flag & MR_DATA_LOOP_NOR) &&
mr->me->normal_domain_all_info() == ATTR_DOMAIN_CORNER) ||
(data_flag & MR_DATA_TAN_LOOP_NOR)) {
mr->corner_normals = mr->me->corner_normals(); mr->corner_normals = mr->me->corner_normals();
} }
} }
@ -356,7 +356,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
if (data_flag & MR_DATA_POLY_NOR) { if (data_flag & MR_DATA_POLY_NOR) {
/* Use #BMFace.no instead. */ /* Use #BMFace.no instead. */
} }
if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { if (((data_flag & MR_DATA_LOOP_NOR)) || (data_flag & MR_DATA_TAN_LOOP_NOR)) {
const float(*vert_coords)[3] = nullptr; const float(*vert_coords)[3] = nullptr;
const float(*vert_normals)[3] = nullptr; const float(*vert_normals)[3] = nullptr;
@ -374,8 +374,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
vert_coords, vert_coords,
vert_normals, vert_normals,
poly_normals, poly_normals,
is_auto_smooth, true,
split_angle,
reinterpret_cast<float(*)[3]>(mr->bm_loop_normals.data()), reinterpret_cast<float(*)[3]>(mr->bm_loop_normals.data()),
nullptr, nullptr,
nullptr, nullptr,

View File

@ -2161,9 +2161,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
runtime_data->stats_totloop = draw_cache->num_subdiv_loops; runtime_data->stats_totloop = draw_cache->num_subdiv_loops;
draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) && draw_cache->use_custom_loop_normals = (runtime_data->use_loop_normals) &&
(mesh_eval->flag & ME_AUTOSMOOTH) && mesh_eval->normal_domain_all_info() == ATTR_DOMAIN_CORNER;
CustomData_has_layer(&mesh_eval->ldata,
CD_CUSTOMLOOPNORMAL);
if (DRW_ibo_requested(mbc->buff.ibo.tris)) { if (DRW_ibo_requested(mbc->buff.ibo.tris)) {
draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len); draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len);

View File

@ -66,6 +66,7 @@ struct MeshRenderData {
const float (*bm_vert_normals)[3]; const float (*bm_vert_normals)[3];
const float (*bm_poly_normals)[3]; const float (*bm_poly_normals)[3];
const float (*bm_poly_centers)[3]; const float (*bm_poly_centers)[3];
blender::Array<blender::float3> bm_loop_normals;
const int *v_origindex, *e_origindex, *p_origindex; const int *v_origindex, *e_origindex, *p_origindex;
int edge_crease_ofs; int edge_crease_ofs;
@ -98,8 +99,6 @@ struct MeshRenderData {
const bool *select_poly; const bool *select_poly;
const bool *sharp_faces; const bool *sharp_faces;
blender::Array<blender::float3> bm_loop_normals;
blender::Span<int> loose_verts; blender::Span<int> loose_verts;
blender::Span<int> loose_edges; blender::Span<int> loose_edges;
const SortedPolyData *poly_sorted; const SortedPolyData *poly_sorted;

View File

@ -41,8 +41,9 @@ static void extract_lnor_iter_poly_bm(const MeshRenderData *mr,
l_iter = l_first = BM_FACE_FIRST_LOOP(f); l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do { do {
const int l_index = BM_elem_index_get(l_iter); const int l_index = BM_elem_index_get(l_iter);
if (!mr->loop_normals.is_empty()) { if (!mr->corner_normals.is_empty()) {
(*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(
mr->corner_normals[l_index]);
} }
else { else {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
@ -64,8 +65,8 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, const int poly
for (const int ml_index : mr->polys[poly_index]) { for (const int ml_index : mr->polys[poly_index]) {
const int vert = mr->corner_verts[ml_index]; const int vert = mr->corner_verts[ml_index];
GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index]; GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index];
if (!mr->loop_normals.is_empty()) { if (!mr->corner_normals.is_empty()) {
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); *lnor_data = GPU_normal_convert_i10_v3(mr->corner_normals[ml_index]);
} }
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]); *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]);
@ -163,8 +164,8 @@ static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr,
l_iter = l_first = BM_FACE_FIRST_LOOP(f); l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do { do {
const int l_index = BM_elem_index_get(l_iter); const int l_index = BM_elem_index_get(l_iter);
if (!mr->loop_normals.is_empty()) { if (!mr->corner_normals.is_empty()) {
normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->loop_normals[l_index]); normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->corner_normals[l_index]);
} }
else { else {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
@ -186,8 +187,8 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
for (const int ml_index : mr->polys[poly_index]) { for (const int ml_index : mr->polys[poly_index]) {
const int vert = mr->corner_verts[ml_index]; const int vert = mr->corner_verts[ml_index];
gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index]; gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index];
if (!mr->loop_normals.is_empty()) { if (!mr->corner_normals.is_empty()) {
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); normal_float_to_short_v3(&lnor_data->x, mr->corner_normals[ml_index]);
} }
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]); normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]);

View File

@ -257,15 +257,14 @@ static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache,
draw_subdiv_extract_pos_nor(subdiv_cache, flags_buffer, vbo, orco_vbo); draw_subdiv_extract_pos_nor(subdiv_cache, flags_buffer, vbo, orco_vbo);
if (subdiv_cache->use_custom_loop_normals) { if (subdiv_cache->use_custom_loop_normals) {
Mesh *coarse_mesh = subdiv_cache->mesh; const Mesh *coarse_mesh = subdiv_cache->mesh;
const float(*loop_normals)[3] = BKE_mesh_corner_normals_ensure(coarse_mesh);
GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc(); GPUVertBuf *src_custom_normals = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format()); GPU_vertbuf_init_with_format(src_custom_normals, get_custom_normals_format());
GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop); GPU_vertbuf_data_alloc(src_custom_normals, coarse_mesh->totloop);
memcpy(GPU_vertbuf_get_data(src_custom_normals), memcpy(GPU_vertbuf_get_data(src_custom_normals),
loop_normals, coarse_mesh->corner_normals().data(),
sizeof(float[3]) * coarse_mesh->totloop); sizeof(float[3]) * coarse_mesh->totloop);
GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc(); GPUVertBuf *dst_custom_normals = GPU_vertbuf_calloc();

View File

@ -102,12 +102,13 @@ static void extract_tan_init_common(const MeshRenderData *mr,
short tangent_mask = 0; short tangent_mask = 0;
bool calc_active_tangent = false; bool calc_active_tangent = false;
if (mr->extract_type == MR_EXTRACT_BMESH) { if (mr->extract_type == MR_EXTRACT_BMESH) {
BKE_editmesh_loop_tangent_calc(mr->edit_bmesh, BKE_editmesh_loop_tangent_calc(
mr->edit_bmesh,
calc_active_tangent, calc_active_tangent,
r_tangent_names, r_tangent_names,
tan_len, tan_len,
reinterpret_cast<const float(*)[3]>(mr->poly_normals.data()), reinterpret_cast<const float(*)[3]>(mr->poly_normals.data()),
reinterpret_cast<const float(*)[3]>(mr->loop_normals.data()), reinterpret_cast<const float(*)[3]>(mr->corner_normals.data()),
orco, orco,
r_loop_data, r_loop_data,
mr->loop_len, mr->loop_len,
@ -126,7 +127,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
tan_len, tan_len,
reinterpret_cast<const float(*)[3]>(mr->vert_normals.data()), reinterpret_cast<const float(*)[3]>(mr->vert_normals.data()),
reinterpret_cast<const float(*)[3]>(mr->poly_normals.data()), reinterpret_cast<const float(*)[3]>(mr->poly_normals.data()),
reinterpret_cast<const float(*)[3]>(mr->loop_normals.data()), reinterpret_cast<const float(*)[3]>(mr->corner_normals.data()),
orco, orco,
r_loop_data, r_loop_data,
mr->corner_verts.size(), mr->corner_verts.size(),

View File

@ -570,7 +570,6 @@ bool ED_operator_editable_mesh(struct bContext *C);
bool ED_operator_editmesh(struct bContext *C); bool ED_operator_editmesh(struct bContext *C);
bool ED_operator_editmesh_view3d(struct bContext *C); bool ED_operator_editmesh_view3d(struct bContext *C);
bool ED_operator_editmesh_region_view3d(struct bContext *C); bool ED_operator_editmesh_region_view3d(struct bContext *C);
bool ED_operator_editmesh_auto_smooth(struct bContext *C);
bool ED_operator_editarmature(struct bContext *C); bool ED_operator_editarmature(struct bContext *C);
bool ED_operator_editcurve(struct bContext *C); bool ED_operator_editcurve(struct bContext *C);
bool ED_operator_editcurve_3d(struct bContext *C); bool ED_operator_editcurve_3d(struct bContext *C);

View File

@ -335,11 +335,6 @@ static bool edbm_bevel_calc(wmOperator *op)
Mesh *me = obedit->data; Mesh *me = obedit->data;
if (harden_normals && !(me->flag & ME_AUTOSMOOTH)) {
/* harden_normals only has a visible effect if autosmooth is on, so turn it on */
me->flag |= ME_AUTOSMOOTH;
}
EDBM_op_init(em, EDBM_op_init(em,
&bmop, &bmop,
op, op,

View File

@ -8392,7 +8392,6 @@ static bool point_normals_init(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit); BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm; BMesh *bm = em->bm;
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
@ -9019,7 +9018,6 @@ static int normals_split_merge(bContext *C, const bool do_merge)
BMEdge *e; BMEdge *e;
BMIter eiter; BMIter eiter;
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
/* Note that we need temp lnor editing data for all loops of all affected vertices, since by /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
@ -9158,7 +9156,6 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
BMLoop *l, *l_curr, *l_first; BMLoop *l, *l_curr, *l_first;
BMIter fiter; BMIter fiter;
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
@ -9407,7 +9404,6 @@ static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
continue; continue;
} }
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
@ -9632,7 +9628,6 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp"); const bool keep_sharp = RNA_boolean_get(op->ptr, "keep_sharp");
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
float(*vert_normals)[3] = static_cast<float(*)[3]>( float(*vert_normals)[3] = static_cast<float(*)[3]>(
@ -9740,7 +9735,6 @@ static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
BMLoop *l; BMLoop *l;
BMIter fiter, liter; BMIter fiter, liter;
BKE_editmesh_ensure_autosmooth(em, static_cast<Mesh *>(obedit->data));
BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data)); BKE_editmesh_lnorspace_update(em, static_cast<Mesh *>(obedit->data));
BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);

View File

@ -783,35 +783,11 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
if (me->edit_mesh) { if (BMEditMesh *em = me->edit_mesh) {
BMesh &bm = *me->edit_mesh->bm; BMesh &bm = *em->bm;
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve auto-smooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
BM_edges_sharp_from_angle_set(&bm, me->smoothresh);
}
BM_data_layer_add(&bm, &bm.ldata, CD_CUSTOMLOOPNORMAL); BM_data_layer_add(&bm, &bm.ldata, CD_CUSTOMLOOPNORMAL);
} }
else { else {
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve auto-smooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, "sharp_face"));
bke::mesh::edges_sharp_from_angle_set(me->polys(),
me->corner_verts(),
me->corner_edges(),
me->poly_normals(),
sharp_faces,
me->smoothresh,
sharp_edges.span);
sharp_edges.finish();
}
CustomData_add_layer(&me->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me->totloop); CustomData_add_layer(&me->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me->totloop);
} }
@ -1476,24 +1452,15 @@ void ED_mesh_split_faces(Mesh *mesh)
const OffsetIndices polys = mesh->polys(); const OffsetIndices polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts(); const Span<int> corner_verts = mesh->corner_verts();
const Span<int> corner_edges = mesh->corner_edges(); const Span<int> corner_edges = mesh->corner_edges();
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
const bke::AttributeAccessor attributes = mesh->attributes(); const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> mesh_sharp_edges = attributes.lookup_or_default<bool>( const VArray<bool> mesh_sharp_edges = attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false); "sharp_edge", ATTR_DOMAIN_EDGE, false);
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
Array<bool> sharp_edges(mesh->totedge); Array<bool> sharp_edges(mesh->totedge);
mesh_sharp_edges.materialize(sharp_edges); mesh_sharp_edges.materialize(sharp_edges);
bke::mesh::edges_sharp_from_angle_set(polys,
corner_verts,
corner_edges,
mesh->poly_normals(),
sharp_faces,
split_angle,
sharp_edges);
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) { for (const int poly_i : range) {
if (sharp_faces && sharp_faces[poly_i]) { if (sharp_faces && sharp_faces[poly_i]) {

View File

@ -672,9 +672,8 @@ static Mesh *bake_mesh_new_from_object(Depsgraph *depsgraph,
{ {
Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex); Mesh *me = BKE_mesh_new_from_object(depsgraph, object, false, preserve_origindex);
if (me->flag & ME_AUTOSMOOTH) { if (me->normal_domain_all_info() == ATTR_DOMAIN_CORNER) {
ED_mesh_split_faces(me); ED_mesh_split_faces(me);
CustomData_free_layers(&me->ldata, CD_NORMAL, me->totloop);
} }
return me; return me;

View File

@ -521,9 +521,6 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
false, false,
op->reports)) { op->reports)) {
if (data_type == DT_TYPE_LNOR && use_create) {
((Mesh *)ob_dst->data)->flag |= ME_AUTOSMOOTH;
}
DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY);
changed = true; changed = true;

View File

@ -1587,16 +1587,18 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
continue; continue;
} }
Mesh *mesh = reinterpret_cast<Mesh *>(data);
bool changed = false; bool changed = false;
if (ob->type == OB_MESH) { if (ob->type == OB_MESH) {
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), use_smooth); BKE_mesh_smooth_flag_set(mesh, use_smooth);
if (use_smooth) { if (use_smooth) {
const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth"); const bool use_auto_smooth = RNA_boolean_get(op->ptr, "use_auto_smooth");
if (use_auto_smooth) {
const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle"); const float auto_smooth_angle = RNA_float_get(op->ptr, "auto_smooth_angle");
BKE_mesh_auto_smooth_flag_set( BKE_mesh_sharp_edges_set_from_angle(mesh, auto_smooth_angle);
static_cast<Mesh *>(ob->data), use_auto_smooth, auto_smooth_angle);
} }
BKE_mesh_batch_cache_dirty_tag(static_cast<Mesh *>(ob->data), BKE_MESH_BATCH_DIRTY_ALL); }
BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL);
changed = true; changed = true;
} }
else if (ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY)) { else if (ELEM(ob->type, OB_SURF, OB_CURVES_LEGACY)) {

View File

@ -454,15 +454,6 @@ bool ED_operator_editmesh_region_view3d(bContext *C)
return false; return false;
} }
bool ED_operator_editmesh_auto_smooth(bContext *C)
{
Object *obedit = CTX_data_edit_object(C);
if (obedit && obedit->type == OB_MESH && (((Mesh *)(obedit->data))->flag & ME_AUTOSMOOTH)) {
return NULL != BKE_editmesh_from_object(obedit);
}
return false;
}
bool ED_operator_editarmature(bContext *C) bool ED_operator_editarmature(bContext *C)
{ {
Object *obedit = CTX_data_edit_object(C); Object *obedit = CTX_data_edit_object(C);

View File

@ -204,10 +204,7 @@ struct AddOperationExecutor {
} }
const Span<MLoopTri> surface_looptris_orig = surface_orig.looptris(); const Span<MLoopTri> surface_looptris_orig = surface_orig.looptris();
const Span<float3> corner_normals_su = { const Span<float3> corner_normals_su = surface_orig.corner_normals();
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(&surface_orig)),
surface_orig.totloop};
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig}; const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};
geometry::AddCurvesOnMeshInputs add_inputs; geometry::AddCurvesOnMeshInputs add_inputs;

View File

@ -254,10 +254,7 @@ struct DensityAddOperationExecutor {
} }
self_->new_deformed_root_positions_.extend(new_positions_cu); self_->new_deformed_root_positions_.extend(new_positions_cu);
const Span<float3> corner_normals_su = { const Span<float3> corner_normals_su = surface_orig_->corner_normals();
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(surface_orig_)),
surface_orig_->totloop};
const Span<MLoopTri> surface_looptris_orig = surface_orig_->looptris(); const Span<MLoopTri> surface_looptris_orig = surface_orig_->looptris();
const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig}; const geometry::ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris_orig};

View File

@ -115,13 +115,10 @@ struct PuffOperationExecutor {
transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_); transforms_ = CurvesSurfaceTransforms(*object_, surface_ob_);
corner_normals_su_ = {
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(surface_)),
surface_->totloop};
surface_positions_ = surface_->vert_positions(); surface_positions_ = surface_->vert_positions();
surface_corner_verts_ = surface_->corner_verts(); surface_corner_verts_ = surface_->corner_verts();
surface_looptris_ = surface_->looptris(); surface_looptris_ = surface_->looptris();
corner_normals_su_ = surface_->corner_normals();
BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2); BKE_bvhtree_from_mesh_get(&surface_bvh_, surface_, BVHTREE_FROM_LOOPTRI, 2);
BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); }); BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_); });

View File

@ -170,16 +170,13 @@ struct SlideOperationExecutor {
return; return;
} }
surface_looptris_orig_ = surface_orig_->looptris(); surface_looptris_orig_ = surface_orig_->looptris();
corner_normals_orig_su_ = surface_orig_->corner_normals();
surface_uv_map_orig_ = surface_orig_->attributes().lookup<float2>(uv_map_name, surface_uv_map_orig_ = surface_orig_->attributes().lookup<float2>(uv_map_name,
ATTR_DOMAIN_CORNER); ATTR_DOMAIN_CORNER);
if (surface_uv_map_orig_.is_empty()) { if (surface_uv_map_orig_.is_empty()) {
report_missing_uv_map_on_original_surface(stroke_extension.reports); report_missing_uv_map_on_original_surface(stroke_extension.reports);
return; return;
} }
corner_normals_orig_su_ = {
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(surface_orig_)),
surface_orig_->totloop};
surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_); surface_ob_eval_ = DEG_get_evaluated_object(ctx_.depsgraph, surface_ob_orig_);
if (surface_ob_eval_ == nullptr) { if (surface_ob_eval_ == nullptr) {
return; return;

View File

@ -1996,7 +1996,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) { if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) { FOREACH_TRANS_DATA_CONTAINER (t, tc) {
if (((Mesh *)(tc->obedit->data))->flag & ME_AUTOSMOOTH) {
BMEditMesh *em = NULL; /* BKE_editmesh_from_object(t->obedit); */ BMEditMesh *em = NULL; /* BKE_editmesh_from_object(t->obedit); */
bool do_skip = false; bool do_skip = false;
@ -2025,7 +2024,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
} }
} }
} }
}
t->context = NULL; t->context = NULL;

View File

@ -128,7 +128,6 @@ void initNormalRotation(TransInfo *t)
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
BMesh *bm = em->bm; BMesh *bm = em->bm;
BKE_editmesh_ensure_autosmooth(em, tc->obedit->data);
BKE_editmesh_lnorspace_update(em, tc->obedit->data); BKE_editmesh_lnorspace_update(em, tc->obedit->data);
storeCustomLNorValue(tc, bm); storeCustomLNorValue(tc, bm);

View File

@ -414,8 +414,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__); MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__);
blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {mlooptri, tottri}); blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, corner_verts, {mlooptri, tottri});
/* TODO: Only retrieve loop normals when necessary. */ const blender::Span<blender::float3> corner_normals = me->corner_normals();
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(me);
// Get other mesh data // Get other mesh data
const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&me->edata, const FreestyleEdge *fed = (const FreestyleEdge *)CustomData_get_layer(&me->edata,
@ -531,10 +530,10 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
v2[2] += _z_offset; v2[2] += _z_offset;
v3[2] += _z_offset; v3[2] += _z_offset;
if (_smooth && (!sharp_faces[lt->poly]) && lnors) { if (_smooth && (!sharp_faces[lt->poly])) {
copy_v3_v3(n1, lnors[lt->tri[0]]); copy_v3_v3(n1, corner_normals[lt->tri[0]]);
copy_v3_v3(n2, lnors[lt->tri[1]]); copy_v3_v3(n2, corner_normals[lt->tri[1]]);
copy_v3_v3(n3, lnors[lt->tri[2]]); copy_v3_v3(n3, corner_normals[lt->tri[2]]);
mul_mat3_m4_v3(nmat, n1); mul_mat3_m4_v3(nmat, n1);
mul_mat3_m4_v3(nmat, n2); mul_mat3_m4_v3(nmat, n2);

View File

@ -35,17 +35,9 @@ float3 compute_surface_point_normal(const MLoopTri &looptri,
const float3 &bary_coord, const float3 &bary_coord,
const Span<float3> corner_normals) const Span<float3> corner_normals)
{ {
const int l0 = looptri.tri[0]; const float3 value = bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords(
const int l1 = looptri.tri[1]; bary_coord, looptri, corner_normals);
const int l2 = looptri.tri[2]; return math::normalize(value);
const float3 &l0_normal = corner_normals[l0];
const float3 &l1_normal = corner_normals[l1];
const float3 &l2_normal = corner_normals[l2];
const float3 normal = math::normalize(
attribute_math::mix3(bary_coord, l0_normal, l1_normal, l2_normal));
return normal;
} }
static void initialize_straight_curve_positions(const float3 &p1, static void initialize_straight_curve_positions(const float3 &p1,
@ -247,7 +239,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
Vector<float3> root_positions_cu; Vector<float3> root_positions_cu;
Vector<float3> bary_coords; Vector<float3> bary_coords;
Vector<const MLoopTri *> looptris; Vector<int> looptri_indices;
Vector<float2> used_uvs; Vector<float2> used_uvs;
/* Find faces that the passed in uvs belong to. */ /* Find faces that the passed in uvs belong to. */
@ -262,7 +254,7 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
} }
const MLoopTri &looptri = inputs.surface_looptris[result.looptri_index]; const MLoopTri &looptri = inputs.surface_looptris[result.looptri_index];
bary_coords.append(result.bary_weights); bary_coords.append(result.bary_weights);
looptris.append(&looptri); looptri_indices.append(result.looptri_index);
const float3 root_position_su = attribute_math::mix3<float3>( const float3 root_position_su = attribute_math::mix3<float3>(
result.bary_weights, result.bary_weights,
surface_positions[surface_corner_verts[looptri.tri[0]]], surface_positions[surface_corner_verts[looptri.tri[0]]],
@ -347,12 +339,14 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
/* Find surface normal at root points. */ /* Find surface normal at root points. */
Array<float3> new_normals_su(added_curves_num); Array<float3> new_normals_su(added_curves_num);
threading::parallel_for(IndexRange(added_curves_num), 256, [&](const IndexRange range) { bke::mesh_surface_sample::sample_corner_attribute(
for (const int i : range) { *inputs.surface,
new_normals_su[i] = compute_surface_point_normal( looptri_indices,
*looptris[i], bary_coords[i], inputs.corner_normals_su); bary_coords,
} VArray<float3>::ForSpan(inputs.corner_normals_su),
}); IndexMask(added_curves_num),
new_normals_su.as_mutable_span());
/* TODO: Normalization. */
/* Initialize position attribute. */ /* Initialize position attribute. */
if (inputs.interpolate_shape) { if (inputs.interpolate_shape) {

View File

@ -202,7 +202,7 @@ static void updateDepsgraph(GpencilModifierData *md,
CustomData_MeshMasks mask = {0}; CustomData_MeshMasks mask = {0};
if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) { if (BKE_shrinkwrap_needs_normals(mmd->shrink_type, mmd->shrink_mode)) {
mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; mask.lmask |= CD_MASK_CUSTOMLOOPNORMAL;
} }
if (mmd->target != NULL) { if (mmd->target != NULL) {

View File

@ -1987,10 +1987,6 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) { if (orig_ob->lineart.flags & OBJECT_LRT_OWN_CREASE) {
crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold); crease_angle = cosf(M_PI - orig_ob->lineart.crease_threshold);
} }
else if (ob_info->original_me->flag & ME_AUTOSMOOTH) {
crease_angle = cosf(ob_info->original_me->smoothresh);
use_auto_smooth = true;
}
else { else {
crease_angle = la_data->conf.crease_threshold; crease_angle = la_data->conf.crease_threshold;
} }

View File

@ -8,6 +8,7 @@
#include "abc_hierarchy_iterator.h" #include "abc_hierarchy_iterator.h"
#include "intern/abc_axis_conversion.h" #include "intern/abc_axis_conversion.h"
#include "BLI_array_utils.hh"
#include "BLI_assert.h" #include "BLI_assert.h"
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
@ -213,10 +214,9 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
std::vector<Imath::V3f> points, normals; std::vector<Imath::V3f> points, normals;
std::vector<int32_t> poly_verts, loop_counts; std::vector<int32_t> poly_verts, loop_counts;
std::vector<Imath::V3f> velocities; std::vector<Imath::V3f> velocities;
bool has_flat_shaded_poly = false;
get_vertices(mesh, points); get_vertices(mesh, points);
get_topology(mesh, poly_verts, loop_counts, has_flat_shaded_poly); get_topology(mesh, poly_verts, loop_counts);
if (!frame_has_been_written_ && args_.export_params->face_sets) { if (!frame_has_been_written_ && args_.export_params->face_sets) {
write_face_sets(context.object, mesh, abc_poly_mesh_schema_); write_face_sets(context.object, mesh, abc_poly_mesh_schema_);
@ -247,7 +247,7 @@ void ABCGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
} }
if (args_.export_params->normals) { if (args_.export_params->normals) {
get_loop_normals(mesh, normals, has_flat_shaded_poly); get_loop_normals(mesh, normals);
ON3fGeomParam::Sample normals_sample; ON3fGeomParam::Sample normals_sample;
if (!normals.empty()) { if (!normals.empty()) {
@ -446,20 +446,10 @@ static void get_vertices(struct Mesh *mesh, std::vector<Imath::V3f> &points)
static void get_topology(struct Mesh *mesh, static void get_topology(struct Mesh *mesh,
std::vector<int32_t> &poly_verts, std::vector<int32_t> &poly_verts,
std::vector<int32_t> &loop_counts, std::vector<int32_t> &loop_counts)
bool &r_has_flat_shaded_poly)
{ {
const OffsetIndices polys = mesh->polys(); const OffsetIndices polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts(); const Span<int> corner_verts = mesh->corner_verts();
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
for (const int i : sharp_faces.index_range()) {
if (sharp_faces[i]) {
r_has_flat_shaded_poly = true;
break;
}
}
poly_verts.clear(); poly_verts.clear();
loop_counts.clear(); loop_counts.clear();
@ -528,34 +518,51 @@ static void get_vert_creases(struct Mesh *mesh,
} }
} }
static void get_loop_normals(struct Mesh *mesh, static void get_loop_normals(const Mesh *mesh, std::vector<Imath::V3f> &normals)
std::vector<Imath::V3f> &normals,
bool has_flat_shaded_poly)
{ {
normals.clear(); normals.clear();
/* If all polygons are smooth shaded, and there are no custom normals, we don't need to export switch (mesh->normal_domain_all_info()) {
* normals at all. This is also done by other software, see #71246. */ case ATTR_DOMAIN_POINT: {
if (!has_flat_shaded_poly && !CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL) && /* If all polygons are smooth shaded, and there are no custom normals, we don't need to
(mesh->flag & ME_AUTOSMOOTH) == 0) { * export normals at all. This is also done by other software, see #71246. */
return; break;
} }
case ATTR_DOMAIN_FACE: {
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(mesh);
normals.resize(mesh->totloop); normals.resize(mesh->totloop);
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
const OffsetIndices polys = mesh->polys();
const Span<float3> poly_normals = mesh->poly_normals();
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
float3 y_up;
copy_yup_from_zup(y_up, poly_normals[i]);
dst_normals.slice(polys[i]).fill(y_up);
}
});
break;
}
case ATTR_DOMAIN_CORNER: {
normals.resize(mesh->totloop);
MutableSpan dst_normals(reinterpret_cast<float3 *>(normals.data()), normals.size());
/* NOTE: data needs to be written in the reverse order. */ /* NOTE: data needs to be written in the reverse order. */
int abc_index = 0;
const OffsetIndices polys = mesh->polys(); const OffsetIndices polys = mesh->polys();
const Span<float3> corner_normals = mesh->corner_normals();
for (const int i : polys.index_range()) { threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
const IndexRange poly = polys[i]; const IndexRange poly = polys[i];
for (int j = poly.size() - 1; j >= 0; j--, abc_index++) { for (const int i : IndexRange(poly.size())) {
int blender_index = poly[j]; copy_yup_from_zup(dst_normals[poly.last(i)], corner_normals[poly[i]]);
copy_yup_from_zup(normals[abc_index].getValue(), lnors[blender_index]);
} }
} }
});
break;
}
default:
BLI_assert_unreachable();
}
} }
ABCMeshWriter::ABCMeshWriter(const ABCWriterConstructorArgs &args) : ABCGenericMeshWriter(args) {} ABCMeshWriter::ABCMeshWriter(const ABCWriterConstructorArgs &args) : ABCGenericMeshWriter(args) {}

View File

@ -279,7 +279,6 @@ static void process_loop_normals(CDStreamConfig &config, const N3fArraySamplePtr
} }
} }
mesh->flag |= ME_AUTOSMOOTH;
BKE_mesh_set_custom_normals(mesh, lnors); BKE_mesh_set_custom_normals(mesh, lnors);
MEM_freeN(lnors); MEM_freeN(lnors);
@ -302,7 +301,6 @@ static void process_vertex_normals(CDStreamConfig &config,
copy_zup_from_yup(vert_normals[index], vertex_normals[index].getValue()); copy_zup_from_yup(vert_normals[index], vertex_normals[index].getValue());
} }
config.mesh->flag |= ME_AUTOSMOOTH;
BKE_mesh_set_custom_normals_from_verts(config.mesh, vert_normals); BKE_mesh_set_custom_normals_from_verts(config.mesh, vert_normals);
MEM_freeN(vert_normals); MEM_freeN(vert_normals);
} }

View File

@ -616,11 +616,15 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
int last_normal_index = -1; int last_normal_index = -1;
const Span<float3> positions = me->vert_positions(); const Span<float3> positions = me->vert_positions();
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(me); const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(me);
const blender::OffsetIndices polys = me->polys(); const blender::OffsetIndices polys = me->polys();
const Span<int> corner_verts = me->corner_verts(); const Span<int> corner_verts = me->corner_verts();
/* TODO: Only retrieve when necessary. */
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(me); const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const blender::Span<blender::float3> corner_normals = me->corner_normals();
bool use_custom_normals = true; bool use_custom_normals = true;
for (const int poly_index : polys.index_range()) { for (const int poly_index : polys.index_range()) {
@ -644,7 +648,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
float normalized[3]; float normalized[3];
if (use_custom_normals) { if (use_custom_normals) {
normalize_v3_v3(normalized, lnors[corner]); normalize_v3_v3(normalized, corner_normals[corner]);
} }
else { else {
copy_v3_v3(normalized, vert_normals[corner_verts[corner]]); copy_v3_v3(normalized, vert_normals[corner_verts[corner]]);

View File

@ -1167,7 +1167,6 @@ bool MeshImporter::write_geometry(const COLLADAFW::Geometry *geom)
} }
else { else {
BKE_mesh_set_custom_normals(me, reinterpret_cast<float(*)[3]>(loop_normals.data())); BKE_mesh_set_custom_normals(me, reinterpret_cast<float(*)[3]>(loop_normals.data()));
me->flag |= ME_AUTOSMOOTH;
} }
} }

View File

@ -107,7 +107,6 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name)
if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) { if (use_custom_normals_ && loop_normals_.size() == mesh->totloop) {
BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data())); BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(loop_normals_.data()));
mesh->flag |= ME_AUTOSMOOTH;
} }
return mesh; return mesh;

View File

@ -572,8 +572,6 @@ void USDMeshReader::process_normals_face_varying(Mesh *mesh)
return; return;
} }
mesh->flag |= ME_AUTOSMOOTH;
long int loop_count = normals_.size(); long int loop_count = normals_.size();
float(*lnors)[3] = static_cast<float(*)[3]>( float(*lnors)[3] = static_cast<float(*)[3]>(
@ -627,7 +625,6 @@ void USDMeshReader::process_normals_uniform(Mesh *mesh)
} }
} }
mesh->flag |= ME_AUTOSMOOTH;
BKE_mesh_set_custom_normals(mesh, lnors); BKE_mesh_set_custom_normals(mesh, lnors);
MEM_freeN(lnors); MEM_freeN(lnors);

View File

@ -9,6 +9,7 @@
#include <pxr/usd/usdShade/material.h> #include <pxr/usd/usdShade/material.h>
#include <pxr/usd/usdShade/materialBindingAPI.h> #include <pxr/usd/usdShade/materialBindingAPI.h>
#include "BLI_array_utils.hh"
#include "BLI_assert.h" #include "BLI_assert.h"
#include "BLI_math_vector.h" #include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
@ -424,43 +425,32 @@ void USDGenericMeshWriter::assign_materials(const HierarchyContext &context,
void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh) void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
{ {
pxr::UsdTimeCode timecode = get_export_time_code(); pxr::UsdTimeCode timecode = get_export_time_code();
/* TODO: Only when necessary. */
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(mesh);
const OffsetIndices polys = mesh->polys();
const Span<int> corner_verts = mesh->corner_verts();
pxr::VtVec3fArray loop_normals; pxr::VtVec3fArray loop_normals;
loop_normals.reserve(mesh->totloop); loop_normals.resize(mesh->totloop);
if (lnors != nullptr) { MutableSpan dst_normals(reinterpret_cast<float3 *>(loop_normals.data()), loop_normals.size());
/* Export custom loop normals. */
for (int loop_idx = 0, totloop = mesh->totloop; loop_idx < totloop; ++loop_idx) { switch (mesh->normal_domain_all_info()) {
loop_normals.push_back(pxr::GfVec3f(lnors[loop_idx])); case ATTR_DOMAIN_POINT: {
const Span<int> corner_verts = mesh->corner_verts();
array_utils::gather(mesh->vert_normals(), corner_verts, dst_normals);
break;
} }
} case ATTR_DOMAIN_FACE: {
else { const OffsetIndices polys = mesh->polys();
/* Compute the loop normals based on the 'smooth' flag. */
bke::AttributeAccessor attributes = mesh->attributes();
const Span<float3> vert_normals = mesh->vert_normals();
const Span<float3> poly_normals = mesh->poly_normals(); const Span<float3> poly_normals = mesh->poly_normals();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
for (const int i : polys.index_range()) { for (const int i : polys.index_range()) {
const IndexRange poly = polys[i]; dst_normals.slice(polys[i]).fill(poly_normals[i]);
if (sharp_faces[i]) {
/* Flat shaded, use common normal for all verts. */
pxr::GfVec3f pxr_normal(&poly_normals[i].x);
for (int loop_idx = 0; loop_idx < poly.size(); ++loop_idx) {
loop_normals.push_back(pxr_normal);
}
}
else {
/* Smooth shaded, use individual vert normals. */
for (const int vert : corner_verts.slice(poly)) {
loop_normals.push_back(pxr::GfVec3f(&vert_normals[vert].x));
} }
break;
} }
case ATTR_DOMAIN_CORNER: {
array_utils::copy(mesh->corner_normals(), dst_normals);
break;
} }
default:
BLI_assert_unreachable();
} }
pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(), true); pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(), true);

View File

@ -364,8 +364,12 @@ void OBJMesh::store_normal_coords_and_indices()
normal_to_index.reserve(export_mesh_->totpoly); normal_to_index.reserve(export_mesh_->totpoly);
loop_to_normal_index_.resize(export_mesh_->totloop); loop_to_normal_index_.resize(export_mesh_->totloop);
loop_to_normal_index_.fill(-1); loop_to_normal_index_.fill(-1);
/* TODO: Only retrieve when necessary. */
const float(*lnors)[3] = BKE_mesh_corner_normals_ensure(export_mesh_); Span<float3> corner_normals;
if (export_mesh_->normal_domain_all_info() == ATTR_DOMAIN_CORNER) {
corner_normals = export_mesh_->corner_normals();
}
for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) { for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) {
const IndexRange poly = mesh_polys_[poly_index]; const IndexRange poly = mesh_polys_[poly_index];
bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[poly_index]); bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[poly_index]);

View File

@ -381,7 +381,7 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
tot_loop_idx++; tot_loop_idx++;
} }
} }
mesh->flag |= ME_AUTOSMOOTH;
BKE_mesh_set_custom_normals(mesh, loop_normals); BKE_mesh_set_custom_normals(mesh, loop_normals);
MEM_freeN(loop_normals); MEM_freeN(loop_normals);
} }

View File

@ -133,7 +133,7 @@ class obj_importer_test : public BlendfileLoadingBaseTest {
const Span<float3> positions = mesh->vert_positions(); const Span<float3> positions = mesh->vert_positions();
EXPECT_V3_NEAR(positions.first(), exp.vert_first, 0.0001f); EXPECT_V3_NEAR(positions.first(), exp.vert_first, 0.0001f);
EXPECT_V3_NEAR(positions.last(), exp.vert_last, 0.0001f); EXPECT_V3_NEAR(positions.last(), exp.vert_last, 0.0001f);
const float3 *lnors = (const float3 *)BKE_mesh_corner_normals_ensure(mesh); const float3 *lnors = &mesh->corner_normals().first();
float3 normal_first = lnors != nullptr ? lnors[0] : float3(0, 0, 0); float3 normal_first = lnors != nullptr ? lnors[0] : float3(0, 0, 0);
EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f); EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f);
const float2 *mloopuv = static_cast<const float2 *>( const float2 *mloopuv = static_cast<const float2 *>(

View File

@ -16,6 +16,7 @@
/** Workaround to forward-declare C++ type in C header. */ /** Workaround to forward-declare C++ type in C header. */
#ifdef __cplusplus #ifdef __cplusplus
# include "BKE_attribute.h"
# include "BLI_bounds_types.hh" # include "BLI_bounds_types.hh"
# include "BLI_math_vector_types.hh" # include "BLI_math_vector_types.hh"
# include "BLI_offset_indices.hh" # include "BLI_offset_indices.hh"
@ -305,6 +306,12 @@ typedef struct Mesh {
*/ */
void loose_edges_tag_none() const; void loose_edges_tag_none() const;
/**
* \warning This ignores auto-smooth currently. This has to land *after* auto-smooth is turned
* into a modifier.
*/
eAttrDomain normal_domain_all_info() const;
/** /**
* Normal direction of polygons, defined by positions and the winding direction of face corners. * Normal direction of polygons, defined by positions and the winding direction of face corners.
*/ */
@ -314,7 +321,13 @@ typedef struct Mesh {
* surrounding each vertex and the normalized position for loose vertices. * surrounding each vertex and the normalized position for loose vertices.
*/ */
blender::Span<blender::float3> vert_normals() const; blender::Span<blender::float3> vert_normals() const;
/**
* Normal direction at each face corner. Defined by a combination of face normals, vertex
* normals, the `sharp_edge` and `sharp_face` attributes, and potentially by custom normals.
*
* \note Because of the large memory requirements of storing normals per face corner, prefer
* using #poly_normals() or #vert_normals() when possible (see #normal_domain_all_info()).
*/
blender::Span<blender::float3> corner_normals() const; blender::Span<blender::float3> corner_normals() const;
#endif #endif
} Mesh; } Mesh;
@ -370,7 +383,7 @@ enum {
ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */ ME_FLAG_DEPRECATED_2 = 1 << 2, /* deprecated */
ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */ ME_FLAG_UNUSED_3 = 1 << 3, /* cleared */
ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */ ME_FLAG_UNUSED_4 = 1 << 4, /* cleared */
ME_AUTOSMOOTH = 1 << 5, ME_AUTOSMOOTH = 1 << 5, /* deprecated */
ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */ ME_FLAG_UNUSED_6 = 1 << 6, /* cleared */
ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */ ME_FLAG_UNUSED_7 = 1 << 7, /* cleared */
ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8, ME_REMESH_REPROJECT_VERTEX_COLORS = 1 << 8,

View File

@ -2099,7 +2099,7 @@ int rna_Mesh_poly_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_p
static void rna_Mesh_corner_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) static void rna_Mesh_corner_normals_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{ {
const Mesh *mesh = rna_mesh(ptr); const Mesh *mesh = rna_mesh(ptr);
const float(*normals)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); const float(*normals)[3] = BKE_mesh_corner_normals_ensure(mesh);
if (!normals) { if (!normals) {
iter->valid = false; iter->valid = false;
return; return;
@ -2110,16 +2110,13 @@ static void rna_Mesh_corner_normals_begin(CollectionPropertyIterator *iter, Poin
static int rna_Mesh_corner_normals_length(PointerRNA *ptr) static int rna_Mesh_corner_normals_length(PointerRNA *ptr)
{ {
const Mesh *mesh = rna_mesh(ptr); const Mesh *mesh = rna_mesh(ptr);
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
return 0;
}
return mesh->totloop; return mesh->totloop;
} }
int rna_Mesh_corner_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr) int rna_Mesh_corner_normals_lookup_int(PointerRNA *ptr, int index, PointerRNA *r_ptr)
{ {
const Mesh *mesh = rna_mesh(ptr); const Mesh *mesh = rna_mesh(ptr);
const float(*normals)[3] = CustomData_get_layer(&mesh->ldata, CD_NORMAL); const float(*normals)[3] = BKE_mesh_corner_normals_ensure(mesh);
if (index < 0 || index >= mesh->totloop || !normals) { if (index < 0 || index >= mesh->totloop || !normals) {
return false; return false;
} }
@ -4669,24 +4666,6 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
/* End Symmetry */ /* End Symmetry */
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH);
RNA_def_property_ui_text(
prop,
"Auto Smooth",
"Auto smooth (based on smooth/sharp faces/edges and angle between faces), "
"or use custom split normals data if available");
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "smoothresh");
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_text(prop,
"Auto Smooth Angle",
"Maximum angle between face normals that will be considered as smooth "
"(unused if custom split normals data are available)");
RNA_def_property_update(prop, 0, "rna_Mesh_update_geom_and_params");
RNA_define_verify_sdna(false); RNA_define_verify_sdna(false);
prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE); prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "", 0); RNA_def_property_boolean_sdna(prop, NULL, "", 0);

View File

@ -194,11 +194,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
Object *ob = ctx->object; Object *ob = ctx->object;
if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
BKE_modifier_set_error(ob, md, "Enable 'Auto Smooth' in Object Data Properties");
harden_normals = false;
}
BM_mesh_bevel(bm, BM_mesh_bevel(bm,
value, value,
offset_type, offset_type,

View File

@ -118,8 +118,6 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
if (dtmd->ob_source != nullptr) { if (dtmd->ob_source != nullptr) {
CustomData_MeshMasks cddata_masks = {0}; CustomData_MeshMasks cddata_masks = {0};
BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks); BKE_object_data_transfer_dttypes_to_cdmask(dtmd->data_types, &cddata_masks);
BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(
dtmd->vmap_mode, dtmd->emap_mode, dtmd->lmap_mode, dtmd->pmap_mode, &cddata_masks);
DEG_add_object_relation( DEG_add_object_relation(
ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier"); ctx->node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
@ -222,10 +220,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
BKE_modifier_set_error(ctx->object, md, "%s", report_str); BKE_modifier_set_error(ctx->object, md, "%s", report_str);
MEM_freeN((void *)report_str); MEM_freeN((void *)report_str);
} }
else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) {
BKE_modifier_set_error(
ctx->object, (ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties");
}
return result; return result;
} }

View File

@ -303,10 +303,11 @@ static void displaceModifier_do(DisplaceModifierData *dmd,
if (CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)) { if (CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)) {
vert_clnors = static_cast<float(*)[3]>( vert_clnors = static_cast<float(*)[3]>(
MEM_malloc_arrayN(verts_num, sizeof(*vert_clnors), __func__)); MEM_malloc_arrayN(verts_num, sizeof(*vert_clnors), __func__));
BKE_mesh_normals_loop_to_vertex(verts_num, BKE_mesh_normals_loop_to_vertex(
verts_num,
mesh->corner_verts().data(), mesh->corner_verts().data(),
mesh->totloop, mesh->totloop,
BKE_mesh_corner_normals_ensure(mesh), reinterpret_cast<const float(*)[3]>(mesh->corner_normals().data()),
vert_clnors); vert_clnors);
} }
else { else {

View File

@ -66,7 +66,6 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
{ {
MultiresModifierData *mmd = (MultiresModifierData *)md; MultiresModifierData *mmd = (MultiresModifierData *)md;
if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) { if (mmd->flags & eMultiresModifierFlag_UseCustomNormals) {
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
} }
} }
@ -216,8 +215,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
return result; return result;
} }
const bool use_clnors = mmd->flags & eMultiresModifierFlag_UseCustomNormals && const bool use_clnors = mmd->flags & eMultiresModifierFlag_UseCustomNormals &&
mesh->flag & ME_AUTOSMOOTH && mesh->normal_domain_all_info() == ATTR_DOMAIN_CORNER;
CustomData_has_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
/* NOTE: Orco needs final coordinates on CPU side, which are expected to be /* NOTE: Orco needs final coordinates on CPU side, which are expected to be
* accessible via mesh vertices. For this reason we do not evaluate multires to * accessible via mesh vertices. For this reason we do not evaluate multires to
* grids when orco is requested. */ * grids when orco is requested. */
@ -252,11 +250,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
} }
else { else {
if (use_clnors) { if (use_clnors) {
CustomData_add_layer(&mesh->ldata, void *data = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
CD_NORMAL, memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
CD_DUPLICATE,
const_cast<float(*)[3]>(BKE_mesh_corner_normals_ensure(mesh)),
mesh->totloop);
} }
result = multires_as_mesh(mmd, ctx, mesh, subdiv); result = multires_as_mesh(mmd, ctx, mesh, subdiv);

View File

@ -237,6 +237,9 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
blender::MutableSpan<int> corner_edges, blender::MutableSpan<int> corner_edges,
const blender::OffsetIndices<int> polys) const blender::OffsetIndices<int> polys)
{ {
using namespace blender;
const bke::AttributeAccessor attributes = mesh->attributes();
Object *ob_target = enmd->target; Object *ob_target = enmd->target;
const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
@ -328,8 +331,8 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
corner_verts, corner_edges, nos.data(), &mesh->ldata, polys, mesh->poly_normals())) { corner_verts, corner_edges, nos.data(), &mesh->ldata, polys, mesh->poly_normals())) {
BKE_mesh_tag_face_winding_changed(mesh); BKE_mesh_tag_face_winding_changed(mesh);
} }
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
blender::bke::mesh::normals_loop_custom_set(vert_positions, blender::bke::mesh::normals_loop_custom_set(vert_positions,
edges, edges,
polys, polys,
@ -365,6 +368,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
blender::MutableSpan<int> corner_edges, blender::MutableSpan<int> corner_edges,
const blender::OffsetIndices<int> polys) const blender::OffsetIndices<int> polys)
{ {
using namespace blender;
const bke::AttributeAccessor attributes = mesh->attributes();
Object *ob_target = enmd->target; Object *ob_target = enmd->target;
const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
@ -435,8 +440,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
corner_verts, corner_edges, nos.data(), &mesh->ldata, polys, mesh->poly_normals())) { corner_verts, corner_edges, nos.data(), &mesh->ldata, polys, mesh->poly_normals())) {
BKE_mesh_tag_face_winding_changed(mesh); BKE_mesh_tag_face_winding_changed(mesh);
} }
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
blender::bke::mesh::normals_loop_custom_set(positions, blender::bke::mesh::normals_loop_custom_set(positions,
edges, edges,
polys, polys,
@ -486,22 +491,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
return mesh; return mesh;
} }
/* XXX TODO(Rohan Rathi):
* Once we fully switch to Mesh evaluation of modifiers,
* we can expect to get that flag from the COW copy.
* But for now, it is lost in the DM intermediate step,
* so we need to directly check orig object's data. */
#if 0
if (!(mesh->flag & ME_AUTOSMOOTH))
#else
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
BKE_modifier_set_error(
ob, (ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
Mesh *result; Mesh *result;
if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) { if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
/* We need to duplicate data here, otherwise setting custom normals /* We need to duplicate data here, otherwise setting custom normals
@ -536,8 +525,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
clnors = static_cast<short(*)[2]>( clnors = static_cast<short(*)[2]>(
CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, corner_verts.size())); CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, corner_verts.size()));
loop_normals.reinitialize(corner_verts.size()); loop_normals.reinitialize(corner_verts.size());
const bool *sharp_faces = static_cast<const bool *>( const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); "sharp_face", ATTR_DOMAIN_FACE, false);
blender::bke::mesh::normals_calc_loop(positions, blender::bke::mesh::normals_calc_loop(positions,
edges, edges,
polys, polys,
@ -546,10 +535,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
{}, {},
result->vert_normals(), result->vert_normals(),
result->poly_normals(), result->poly_normals(),
sharp_edges.span.data(), VArray<bool>::ForSpan(sharp_edges.span),
sharp_faces, sharp_faces,
true,
result->smoothresh,
clnors, clnors,
nullptr, nullptr,
loop_normals); loop_normals);

View File

@ -155,8 +155,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte
CustomData_MeshMasks mask = {0}; CustomData_MeshMasks mask = {0};
if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) { if (BKE_shrinkwrap_needs_normals(smd->shrinkType, smd->shrinkMode)) {
mask.vmask |= CD_MASK_NORMAL; mask.lmask |= CD_MASK_CUSTOMLOOPNORMAL;
mask.lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
} }
if (smd->target != NULL) { if (smd->target != NULL) {

View File

@ -65,7 +65,6 @@ static void requiredDataMask(ModifierData *md, CustomData_MeshMasks *r_cddata_ma
{ {
SubsurfModifierData *smd = (SubsurfModifierData *)md; SubsurfModifierData *smd = (SubsurfModifierData *)md;
if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) { if (smd->flags & eSubsurfModifierFlag_UseCustomNormals) {
r_cddata_masks->lmask |= CD_MASK_NORMAL;
r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL; r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
} }
if (smd->flags & eSubsurfModifierFlag_UseCrease) { if (smd->flags & eSubsurfModifierFlag_UseCrease) {
@ -262,11 +261,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
} }
const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh); const bool use_clnors = BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh);
if (use_clnors) { if (use_clnors) {
CustomData_add_layer(&mesh->ldata, void *data = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
CD_NORMAL, memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
CD_DUPLICATE,
const_cast<float(*)[3]>(BKE_mesh_corner_normals_ensure(mesh)),
mesh->totloop);
} }
/* TODO(sergey): Decide whether we ever want to use CCG for subsurf, /* TODO(sergey): Decide whether we ever want to use CCG for subsurf,
* maybe when it is a last modifier in the stack? */ * maybe when it is a last modifier in the stack? */

View File

@ -51,11 +51,8 @@ static Mesh *triangulate_mesh(Mesh *mesh,
bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0; bool keep_clnors = (flag & MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS) != 0;
if (keep_clnors) { if (keep_clnors) {
CustomData_add_layer(&mesh->ldata, void *data = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CONSTRUCT, mesh->totloop);
CD_NORMAL, memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
CD_DUPLICATE,
const_cast<float(*)[3]>(BKE_mesh_corner_normals_ensure(mesh)),
mesh->totloop);
} }
BMeshCreateParams bmesh_create_params{}; BMeshCreateParams bmesh_create_params{};

View File

@ -80,11 +80,10 @@ struct WeightedNormalData {
blender::Span<int> loop_to_poly; blender::Span<int> loop_to_poly;
short (*clnors)[2]; short (*clnors)[2];
bool has_clnors; /* True if clnors already existed, false if we had to create them. */ bool has_clnors; /* True if clnors already existed, false if we had to create them. */
float split_angle;
blender::OffsetIndices<int> polys; blender::OffsetIndices<int> polys;
blender::Span<blender::float3> poly_normals; blender::Span<blender::float3> poly_normals;
const bool *sharp_faces; blender::VArray<bool> sharp_faces;
const int *poly_strength; const int *poly_strength;
const MDeformVert *dvert; const MDeformVert *dvert;
@ -203,7 +202,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
ModePair *mode_pair = wn_data->mode_pair; ModePair *mode_pair = wn_data->mode_pair;
const bool has_clnors = wn_data->has_clnors; const bool has_clnors = wn_data->has_clnors;
const float split_angle = wn_data->split_angle;
MLoopNorSpaceArray lnors_spacearr = {nullptr}; MLoopNorSpaceArray lnors_spacearr = {nullptr};
const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
@ -229,10 +227,8 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_to_poly, loop_to_poly,
wn_data->vert_normals, wn_data->vert_normals,
wn_data->poly_normals, wn_data->poly_normals,
wn_data->sharp_edges.data(), blender::VArray<bool>::ForSpan(wn_data->sharp_edges),
wn_data->sharp_faces, wn_data->sharp_faces,
true,
split_angle,
has_clnors ? clnors : nullptr, has_clnors ? clnors : nullptr,
&lnors_spacearr, &lnors_spacearr,
loop_normals); loop_normals);
@ -395,10 +391,8 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
loop_to_poly, loop_to_poly,
wn_data->vert_normals, wn_data->vert_normals,
poly_normals, poly_normals,
wn_data->sharp_edges.data(), blender::VArray<bool>::ForSpan(wn_data->sharp_edges),
wn_data->sharp_faces, wn_data->sharp_faces,
true,
split_angle,
has_clnors ? clnors : nullptr, has_clnors ? clnors : nullptr,
nullptr, nullptr,
loop_normals); loop_normals);
@ -521,24 +515,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md; WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
Object *ob = ctx->object; Object *ob = ctx->object;
/* XXX TODO(Rohan Rathi): Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
* Once we fully switch to Mesh evaluation of modifiers,
* we can expect to get that flag from the COW copy.
* But for now, it is lost in the DM intermediate step,
* so we need to directly check orig object's data. */
#if 0
if (!(mesh->flag & ME_AUTOSMOOTH))
#else
if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH))
#endif
{
BKE_modifier_set_error(
ctx->object, (ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties");
return mesh;
}
Mesh *result;
result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
const int verts_num = result->totvert; const int verts_num = result->totvert;
const blender::Span<blender::float3> positions = mesh->vert_positions(); const blender::Span<blender::float3> positions = mesh->vert_positions();
@ -564,7 +541,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
weight = (weight - 1) * 25; weight = (weight - 1) * 25;
} }
const float split_angle = mesh->smoothresh;
short(*clnors)[2] = static_cast<short(*)[2]>( short(*clnors)[2] = static_cast<short(*)[2]>(
CustomData_get_layer_for_write(&result->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop)); CustomData_get_layer_for_write(&result->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop));
@ -599,12 +575,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
wn_data.loop_to_poly = loop_to_poly_map; wn_data.loop_to_poly = loop_to_poly_map;
wn_data.clnors = clnors; wn_data.clnors = clnors;
wn_data.has_clnors = has_clnors; wn_data.has_clnors = has_clnors;
wn_data.split_angle = split_angle;
wn_data.polys = polys; wn_data.polys = polys;
wn_data.poly_normals = mesh->poly_normals(); wn_data.poly_normals = mesh->poly_normals();
wn_data.sharp_faces = static_cast<const bool *>( wn_data.sharp_faces = attributes.lookup_or_default<bool>("sharp_face", ATTR_DOMAIN_FACE, false);
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named( wn_data.poly_strength = static_cast<const int *>(CustomData_get_layer_named(
&result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID)); &result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID));

View File

@ -315,12 +315,8 @@ static void node_geo_exec(GeoNodeExecParams params)
/* Retrieve face corner normals from each mesh. It's necessary to use face corner normals /* Retrieve face corner normals from each mesh. It's necessary to use face corner normals
* because face normals or vertex normals may lose information (custom normals, auto smooth) in * because face normals or vertex normals may lose information (custom normals, auto smooth) in
* some cases. */ * some cases. */
const Span<float3> corner_normals_orig( const Span<float3> corner_normals_orig = surface_mesh_orig->corner_normals();
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(surface_mesh_orig)), const Span<float3> corner_normals_eval = surface_mesh_eval->corner_normals();
surface_mesh_orig->totloop);
const Span<float3> corner_normals_eval(
reinterpret_cast<const float3 *>(BKE_mesh_corner_normals_ensure(surface_mesh_eval)),
surface_mesh_eval->totloop);
std::atomic<int> invalid_uv_count = 0; std::atomic<int> invalid_uv_count = 0;

View File

@ -332,25 +332,41 @@ static void compute_normal_outputs(const Mesh &mesh,
const Span<int> looptri_indices, const Span<int> looptri_indices,
MutableSpan<float3> r_normals) MutableSpan<float3> r_normals)
{ {
Array<float3> corner_normals(mesh.totloop); /* TODO: Normalization. */
BKE_mesh_calc_normals_split_ex( switch (mesh.normal_domain_all_info()) {
const_cast<Mesh *>(&mesh), nullptr, reinterpret_cast<float(*)[3]>(corner_normals.data())); case ATTR_DOMAIN_POINT: {
const Span<float3> vert_normals = mesh.vert_normals();
bke::mesh_surface_sample::sample_point_attribute(mesh,
looptri_indices,
bary_coords,
VArray<float3>::ForSpan(vert_normals),
IndexMask(looptri_indices.index_range()),
r_normals);
const Span<MLoopTri> looptris = mesh.looptris(); break;
}
threading::parallel_for(bary_coords.index_range(), 512, [&](const IndexRange range) { case ATTR_DOMAIN_FACE: {
for (const int i : range) { const Span<float3> poly_normals = mesh.poly_normals();
const int looptri_index = looptri_indices[i]; bke::mesh_surface_sample::sample_face_attribute(mesh,
const MLoopTri &looptri = looptris[looptri_index]; looptri_indices,
const float3 &bary_coord = bary_coords[i]; VArray<float3>::ForSpan(poly_normals),
IndexMask(looptri_indices.index_range()),
const float3 normal = math::normalize( r_normals);
bke::mesh_surface_sample::sample_corner_attrribute_with_bary_coords( break;
bary_coord, looptri, corner_normals.as_span())); }
case ATTR_DOMAIN_CORNER: {
r_normals[i] = normal; const Span<float3> corner_normals = mesh.corner_normals();
bke::mesh_surface_sample::sample_corner_attribute(mesh,
looptri_indices,
bary_coords,
VArray<float3>::ForSpan(corner_normals),
IndexMask(looptri_indices.index_range()),
r_normals);
break;
}
default:
BLI_assert_unreachable();
} }
});
} }
static void compute_legacy_normal_outputs(const Mesh &mesh, static void compute_legacy_normal_outputs(const Mesh &mesh,

View File

@ -487,14 +487,14 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
} }
const TSpace *tspace = nullptr; const TSpace *tspace = nullptr;
const float(*loop_normals)[3] = nullptr; blender::Span<blender::float3> corner_normals;
if (tangent) { if (tangent) {
BKE_mesh_calc_loop_tangents(me_eval, true, NULL, 0); BKE_mesh_calc_loop_tangents(me_eval, true, nullptr, 0);
tspace = static_cast<const TSpace *>(CustomData_get_layer(&me_eval->ldata, CD_TANGENT)); tspace = static_cast<const TSpace *>(CustomData_get_layer(&me_eval->ldata, CD_TANGENT));
BLI_assert(tspace); BLI_assert(tspace);
loop_normals = BKE_mesh_corner_normals_ensure(me_eval); corner_normals = me_eval->corner_normals();
} }
const blender::Span<blender::float3> vert_normals = me->vert_normals(); const blender::Span<blender::float3> vert_normals = me->vert_normals();
@ -515,10 +515,10 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval
triangles[i].tspace[2] = &tspace[lt->tri[2]]; triangles[i].tspace[2] = &tspace[lt->tri[2]];
} }
if (loop_normals) { if (!corner_normals.is_empty()) {
triangles[i].loop_normal[0] = loop_normals[lt->tri[0]]; triangles[i].loop_normal[0] = corner_normals[lt->tri[0]];
triangles[i].loop_normal[1] = loop_normals[lt->tri[1]]; triangles[i].loop_normal[1] = corner_normals[lt->tri[1]];
triangles[i].loop_normal[2] = loop_normals[lt->tri[2]]; triangles[i].loop_normal[2] = corner_normals[lt->tri[2]];
} }
if (calculate_normal) { if (calculate_normal) {

View File

@ -505,6 +505,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
const blender::Span<int> corner_verts = temp_mesh->corner_verts(); const blender::Span<int> corner_verts = temp_mesh->corner_verts();
const blender::Span<blender::float3> vert_normals = temp_mesh->vert_normals(); const blender::Span<blender::float3> vert_normals = temp_mesh->vert_normals();
const blender::Span<blender::float3> poly_normals = temp_mesh->poly_normals(); const blender::Span<blender::float3> poly_normals = temp_mesh->poly_normals();
const blender::Span<blender::float3> corner_normals = temp_mesh->corner_normals();
const blender::Span<MLoopTri> looptris = temp_mesh->looptris(); const blender::Span<MLoopTri> looptris = temp_mesh->looptris();
if (require_tangent) { if (require_tangent) {
@ -523,7 +524,7 @@ static void do_multires_bake(MultiresBakeRender *bkr,
0, 0,
reinterpret_cast<const float(*)[3]>(vert_normals.data()), reinterpret_cast<const float(*)[3]>(vert_normals.data()),
reinterpret_cast<const float(*)[3]>(poly_normals.data()), reinterpret_cast<const float(*)[3]>(poly_normals.data()),
BKE_mesh_corner_normals_ensure(temp_mesh), reinterpret_cast<const float(*)[3]>(corner_normals.data()),
(const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* May be nullptr. */ (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* May be nullptr. */
/* result */ /* result */
&dm->loopData, &dm->loopData,