Start moving ME_SMOOTH flag to generic "sharp_face" attribute

This commit is contained in:
Hans Goudey 2023-01-04 23:56:20 -05:00
parent 433d436b84
commit 54ae189d86
34 changed files with 190 additions and 100 deletions

View File

@ -895,6 +895,23 @@ static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_
return std::nullopt;
}
static std::optional<BL::IntAttribute> find_sharp_face_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_BOOLEAN) {
continue;
}
if (b_attribute.name() != "sharp_face") {
continue;
}
return BL::BoolAttribute{b_attribute};
}
return std::nullopt;
}
static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh &b_mesh,
@ -986,6 +1003,15 @@ static void create_mesh(Scene *scene,
return 0;
};
std::optional<BL::BoolAttribute> sharp_faces = find_sharp_face_attribute(b_mesh);
auto get_face_sharp = [&](const int poly_index) -> bool {
if (sharp_faces) {
return sharp_faces->data[poly_index].value();
}
return 0;
};
/* create faces */
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
if (!subdivision) {
@ -995,7 +1021,7 @@ static void create_mesh(Scene *scene,
int3 vi = get_int3(t.vertices());
int shader = get_material_index(poly_index);
bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals;
bool smooth = !get_face_sharp(poly_index) || use_loop_normals;
if (use_loop_normals) {
BL::Array<float, 9> loop_normals = t.split_normals();
@ -1021,7 +1047,7 @@ static void create_mesh(Scene *scene,
const MPoly &b_poly = polys[i];
int n = b_poly.totloop;
int shader = get_material_index(i);
bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals;
bool smooth = !get_face_sharp(poly_index) || use_loop_normals;
vi.resize(n);
for (int i = 0; i < n; i++) {

View File

@ -605,7 +605,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = []
for collection in (
# Built-in names.
{"position": None, "shade_smooth": None, "normal": None, "crease": None},
{"position": None, "normal": None, "crease": None},
mesh.attributes,
mesh.uv_layers,
None if ob is None else ob.vertex_groups,

View File

@ -47,6 +47,7 @@ void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert,
const struct MLoop *mloop,
const struct MLoopTri *looptri,
uint looptri_len,
const bool *sharp_faces,
struct CustomData *loopdata,
bool calc_active_tangent,

View File

@ -76,6 +76,7 @@ typedef struct ShrinkwrapTreeData {
const struct MPoly *polys;
const float (*vert_normals)[3];
const float (*poly_normals)[3];
const bool *sharp_faces;
const float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;

View File

@ -112,7 +112,6 @@ static void fill_mesh_topology(const int vert_offset,
MPoly &poly = polys[ring_poly_offset + i_profile];
poly.loopstart = ring_segment_loop_offset;
poly.totloop = 4;
poly.flag = ME_SMOOTH;
MLoop &loop_a = loops[ring_segment_loop_offset];
loop_a.v = ring_vert_offset + i_profile;

View File

@ -922,16 +922,6 @@ static void tag_component_positions_changed(void *owner)
}
}
static bool get_shade_smooth(const MPoly &mpoly)
{
return mpoly.flag & ME_SMOOTH;
}
static void set_shade_smooth(MPoly &mpoly, bool value)
{
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
}
static float2 get_loop_uv(const MLoopUV &uv)
{
return float2(uv.uv);
@ -1284,18 +1274,17 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
nullptr,
AttributeValidator{&material_index_clamp});
static BuiltinCustomDataLayerProvider shade_smooth(
"shade_smooth",
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider sharp_face("sharp_face",
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_PROP_BOOL,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
face_access,
make_array_read_attribute<bool>,
make_array_write_attribute<bool>,
nullptr);
static BuiltinCustomDataLayerProvider crease(
"crease",
@ -1325,7 +1314,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
return ComponentAttributeProviders(
{&position, &id, &material_index, &shade_smooth, &normal, &crease},
{&position, &id, &material_index, &sharp_face, &normal, &crease},
{&uvs,
&corner_custom_data,
&vertex_groups,

View File

@ -1483,7 +1483,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
const int count = indices[2] != indices[3] ? 4 : 3;
mpoly[i].loopstart = loop_offset;
mpoly[i].totloop = count;
mpoly[i].flag = ME_SMOOTH;
mloop[loop_offset].v = uint32_t(indices[0]);
mloop[loop_offset + 1].v = uint32_t(indices[1]);

View File

@ -1464,16 +1464,17 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
{
MutableSpan<MPoly> polys = me->polys_for_write();
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
if (use_smooth) {
for (MPoly &poly : polys) {
poly.flag |= ME_SMOOTH;
}
attributes.remove("sharp_face");
}
else {
for (MPoly &poly : polys) {
poly.flag &= ~ME_SMOOTH;
}
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
sharp_faces.span.fill(true);
sharp_faces.finish();
}
}

View File

@ -198,6 +198,9 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>(
"material_index", ATTR_DOMAIN_FACE);
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_add_layer_named(
&mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, DATA_("UVMap")));
@ -283,8 +286,8 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
}
if (is_smooth) {
polys[dst_poly].flag |= ME_SMOOTH;
if (!is_smooth) {
sharp_faces.span[dst_poly] = true;
}
dst_poly++;
dst_loop += 3;
@ -368,8 +371,8 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
}
if (is_smooth) {
polys[dst_poly].flag |= ME_SMOOTH;
if (!is_smooth) {
sharp_faces.span[dst_poly] = true;
}
dst_poly++;
dst_loop += 4;
@ -388,6 +391,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
material_indices.finish();
sharp_faces.finish();
return mesh;
}

View File

@ -237,7 +237,7 @@ struct SGLSLMeshToTangent {
if (precomputedLoopNormals) {
return mikk::float3(precomputedLoopNormals[loop_index]);
}
if ((mpoly[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
if (sharp_faces && sharp_faces[lt->poly]) { /* flat */
if (precomputedFaceNormals) {
return mikk::float3(precomputedFaceNormals[lt->poly]);
}
@ -279,6 +279,7 @@ struct SGLSLMeshToTangent {
const MPoly *mpoly; /* indices */
const MLoop *mloop; /* indices */
const MVert *mvert; /* vertex coordinates */
const bool *sharp_faces;
const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
@ -391,6 +392,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
const MLoop *mloop,
const MLoopTri *looptri,
const uint looptri_len,
const bool *sharp_faces,
CustomData *loopdata,
bool calc_active_tangent,
@ -495,6 +497,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert,
mesh2tangent->mpoly = mpoly;
mesh2tangent->mloop = mloop;
mesh2tangent->looptri = looptri;
mesh2tangent->sharp_faces = sharp_faces;
/* NOTE: we assume we do have tessellated loop normals at this point
* (in case it is object-enabled), have to check this is valid. */
mesh2tangent->precomputedLoopNormals = loop_normals;
@ -579,6 +582,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
BKE_mesh_loops(me_eval),
BKE_mesh_runtime_looptri_ensure(me_eval),
uint(BKE_mesh_runtime_looptri_len(me_eval)),
static_cast<const bool *>(
CustomData_get_layer_named(&me_eval->pdata, CD_PROP_BOOL, "sharp_face")),
&me_eval->ldata,
calc_active_tangent,
tangent_names,

View File

@ -116,6 +116,8 @@ bool BKE_shrinkwrap_init_tree(
data->mesh = mesh;
data->polys = BKE_mesh_polys(mesh);
data->vert_normals = BKE_mesh_vertex_normals_ensure(mesh);
data->sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_face"));
if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
@ -1175,7 +1177,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
const float(*vert_normals)[3] = tree->vert_normals;
/* Interpolate smooth normals if enabled. */
if ((tree->polys[tri->poly].flag & ME_SMOOTH) != 0) {
if (!(tree->sharp_faces && tree->sharp_faces[tri->poly])) {
const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v,
treeData->loop[tri->tri[1]].v,
treeData->loop[tri->tri[2]].v};

View File

@ -567,6 +567,9 @@ MeshRenderData *mesh_render_data_create(Object *object,
CustomData_get_layer_named(&me->edata, CD_PROP_BOOL, ".select_edge"));
mr->select_poly = static_cast<const bool *>(
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".select_poly"));
mr->sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, "sharp_face"));
}
else {
/* #BMesh */

View File

@ -756,7 +756,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData *
const Span<MPoly> polys = mesh->polys();
for (const int i : polys.index_range()) {
uint32_t flag = 0;
if ((polys[i].flag & ME_SMOOTH) != 0) {
if (!(mr->sharp_faces && mr->sharp_faces[i])) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
if (mr->select_poly && mr->select_poly[i]) {
@ -785,7 +785,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh,
/* Selection and hiding from bmesh. */
uint32_t flag = (f) ? compute_coarse_face_flag_bm(f, mr->efa_act) : 0;
/* Smooth from mesh. */
if ((polys[i].flag & ME_SMOOTH) != 0) {
if ((mr->sharp_faces && mr->sharp_faces[i])) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
flags_data[i] = uint(polys[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);

View File

@ -91,6 +91,7 @@ struct MeshRenderData {
const bool *select_vert;
const bool *select_edge;
const bool *select_poly;
const bool *sharp_faces;
float (*loop_normals)[3];
int *lverts, *ledges;

View File

@ -72,11 +72,11 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
if (mr->loop_normals) {
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
else if (mr->sharp_faces && mr->sharp_faces[mp_index]) {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[mp_index]);
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
}
/* Flag for paint mode overlay.
@ -197,11 +197,11 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
if (mr->loop_normals) {
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
else if (mp->flag & ME_SMOOTH) {
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
else if (mr->sharp_faces && mr->sharp_faces[mp_index]) {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[mp_index]);
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
}
/* Flag for paint mode overlay.

View File

@ -1463,16 +1463,28 @@ void ED_mesh_split_faces(Mesh *mesh)
polys.size(),
split_angle);
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) {
const MPoly &poly = polys[poly_i];
if (!(poly.flag & ME_SMOOTH)) {
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
edges[loop.e].flag |= ME_SHARP;
}
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
if (const std::optional<bool> value = sharp_faces.get_if_single()) {
if (value) {
for (MEdge &edge : edges) {
edge.flag |= ME_SHARP;
}
}
});
}
else {
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) {
const MPoly &poly = polys[poly_i];
if (sharp_faces[poly_i]) {
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
edges[loop.e].flag |= ME_SHARP;
}
}
}
});
}
Vector<int64_t> split_indices;
const IndexMask split_mask = index_mask_ops::find_indices_based_on_predicate(

View File

@ -25,6 +25,7 @@
#include "BLT_translation.h"
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
@ -117,6 +118,7 @@ static bool object_remesh_poll(bContext *C)
static int voxel_remesh_exec(bContext *C, wmOperator *op)
{
using namespace blender;
Object *ob = CTX_data_active_object(C);
Mesh *mesh = static_cast<Mesh *>(ob->data);
@ -131,8 +133,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
/* Output mesh will be all smooth or all flat shading. */
const Span<MPoly> polys = mesh->polys();
const bool smooth_normals = polys.first().flag & ME_SMOOTH;
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool smooth_normals = !sharp_faces[0];
float isovalue = 0.0f;
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {

View File

@ -418,6 +418,7 @@ struct ProjPaintState {
const MPoly *mpoly_eval;
const bool *select_poly_eval;
const int *material_indices;
const bool *sharp_faces_eval;
const MLoop *mloop_eval;
const MLoopTri *mlooptri_eval;
@ -1730,7 +1731,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
const MPoly *mp = &ps->mpoly_eval[lt->poly];
float no[3], angle_cos;
if (mp->flag & ME_SMOOTH) {
if (!(ps->sharp_faces_eval && ps->sharp_faces_eval[lt->poly])) {
const float *no1, *no2, *no3;
no1 = ps->vert_normals[lt_vtri[0]];
no2 = ps->vert_normals[lt_vtri[1]];
@ -4083,6 +4084,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p
}
ps->mloop_eval = BKE_mesh_loops(ps->me_eval);
ps->mpoly_eval = BKE_mesh_polys(ps->me_eval);
ps->sharp_faces_eval = static_cast<const bool *>(
CustomData_get_layer_named(&ps->me_eval->pdata, CD_PROP_BOOL, "sharp_face"));
ps->select_poly_eval = (const bool *)CustomData_get_layer_named(
&ps->me_eval->pdata, CD_PROP_BOOL, ".select_poly");
ps->material_indices = (const int *)CustomData_get_layer_named(

View File

@ -399,6 +399,7 @@ static bool testEdgeMark(Mesh *me, const FreestyleEdge *fed, const MLoopTri *lt,
void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
{
using namespace blender;
char *name = ob->id.name + 2;
const Span<MVert> mesh_verts = me->verts();
@ -507,14 +508,16 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
FrsMaterial tmpMat;
const blender::VArray<int> material_indices = me->attributes().lookup_or_default<int>(
const bke::AttributeAccessor attributes = me->attributes();
const VArray<int> material_indices = attributes.lookup_or_default<int>(
"material_index", ATTR_DOMAIN_FACE, 0);
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
// We parse the vlak nodes again and import meshes while applying the clipping
// by the near and far view planes.
for (int a = 0; a < tottri; a++) {
const MLoopTri *lt = &mlooptri[a];
const MPoly *mp = &mesh_polys[lt->poly];
Material *mat = BKE_object_material_get(ob, material_indices[lt->poly] + 1);
copy_v3_v3(v1, mesh_verts[mesh_loops[lt->tri[0]].v].co);
@ -529,7 +532,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id)
v2[2] += _z_offset;
v3[2] += _z_offset;
if (_smooth && (mp->flag & ME_SMOOTH) && lnors) {
if (_smooth && (!sharp_faces[lt->poly]) && lnors) {
copy_v3_v3(n1, lnors[lt->tri[0]]);
copy_v3_v3(n2, lnors[lt->tri[1]]);
copy_v3_v3(n3, lnors[lt->tri[2]]);

View File

@ -833,7 +833,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
src_component_types, GEO_COMPONENT_TYPE_MESH, true, attributes_to_propagate);
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("shade_smooth");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
OrderedAttributes ordered_attributes;

View File

@ -205,7 +205,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data)
/* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded,
* this is encoded in custom loop normals. See T71246. */
poly.flag |= ME_SMOOTH;
/* NOTE: Alembic data is stored in the reverse order. */
rev_loop_index = loop_index + (face_size - 1);

View File

@ -614,6 +614,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
std::vector<BCPolygonNormalsIndices> &polygons_normals,
Mesh *me)
{
using namespace blender;
std::map<Normal, uint> shared_normal_indices;
int last_normal_index = -1;
@ -624,6 +625,10 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
const float(*lnors)[3] = nullptr;
bool use_custom_normals = false;
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
BKE_mesh_calc_normals_split(me);
if (CustomData_has_layer(&me->ldata, CD_NORMAL)) {
lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL);
@ -632,7 +637,7 @@ void GeometryExporter::create_normals(std::vector<Normal> &normals,
for (const int poly_index : polys.index_range()) {
const MPoly *mpoly = &polys[poly_index];
bool use_vertex_normals = use_custom_normals || mpoly->flag & ME_SMOOTH;
bool use_vertex_normals = use_custom_normals || !sharp_faces[poly_index];
if (!use_vertex_normals) {
/* For flat faces use face normal as vertex normal: */

View File

@ -325,7 +325,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh)
/* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded,
* this is encoded in custom loop normals. */
poly.flag |= ME_SMOOTH;
if (is_left_handed_) {
int loop_end_index = loop_index + (face_size - 1);

View File

@ -413,12 +413,15 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_
}
else {
/* Compute the loop normals based on the 'smooth' flag. */
bke::AttributeAccessor attributes = mesh->attributes();
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh);
const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh);
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
for (const int i : polys.index_range()) {
const MPoly &poly = polys[i];
if ((poly.flag & ME_SMOOTH) == 0) {
if (sharp_faces[i]) {
/* Flat shaded, use common normal for all verts. */
pxr::GfVec3f pxr_normal(face_normals[i]);
for (int loop_idx = 0; loop_idx < poly.totloop; ++loop_idx) {

View File

@ -44,6 +44,8 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
mesh_edges_ = export_mesh_->edges();
mesh_polys_ = export_mesh_->polys();
mesh_loops_ = export_mesh_->loops();
sharp_faces_ = export_mesh_->attributes().lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
}
else {
/* Curves and NURBS surfaces need a new mesh when they're
@ -76,6 +78,8 @@ void OBJMesh::set_mesh(Mesh *mesh)
mesh_edges_ = mesh->edges();
mesh_polys_ = mesh->polys();
mesh_loops_ = mesh->loops();
sharp_faces_ = export_mesh_->attributes().lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
}
void OBJMesh::clear()
@ -243,7 +247,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const
bool OBJMesh::is_ith_poly_smooth(const int poly_index) const
{
return mesh_polys_[poly_index].flag & ME_SMOOTH;
return !sharp_faces_[poly_index];
}
const char *OBJMesh::get_object_name() const
@ -392,7 +396,7 @@ void OBJMesh::store_normal_coords_and_indices()
CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL));
for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) {
const MPoly &mpoly = mesh_polys_[poly_index];
bool need_per_loop_normals = lnors != nullptr || (mpoly.flag & ME_SMOOTH);
bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[poly_index]);
if (need_per_loop_normals) {
for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; ++loop_of_poly) {
float3 loop_normal;

View File

@ -11,6 +11,7 @@
#include "BLI_math_vec_types.hh"
#include "BLI_utility_mixins.hh"
#include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@ -41,6 +42,8 @@ class OBJMesh : NonCopyable {
Span<MPoly> mesh_polys_;
Span<MLoop> mesh_loops_;
VArray<bool> sharp_faces_;
/**
* Final transform of an object obtained from export settings (up_axis, forward_axis) and the
* object's world transform matrix.

View File

@ -183,9 +183,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
MutableSpan<MPoly> polys = mesh->polys_for_write();
MutableSpan<MLoop> loops = mesh->loops_for_write();
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<int> material_indices =
mesh->attributes_for_write().lookup_or_add_for_write_only_span<int>("material_index",
ATTR_DOMAIN_FACE);
attributes.lookup_or_add_for_write_only_span<int>("material_index", ATTR_DOMAIN_FACE);
bke::SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
const int64_t tot_face_elems{mesh->totpoly};
int tot_loop_idx = 0;
@ -201,8 +203,8 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
MPoly &mpoly = polys[poly_idx];
mpoly.totloop = curr_face.corner_count_;
mpoly.loopstart = tot_loop_idx;
if (curr_face.shaded_smooth) {
mpoly.flag |= ME_SMOOTH;
if (!curr_face.shaded_smooth) {
sharp_faces.span[poly_idx] = true;
}
material_indices.span[poly_idx] = curr_face.material_index;
/* Importing obj files without any materials would result in negative indices, which is not
@ -228,6 +230,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups)
}
material_indices.finish();
sharp_faces.finish();
}
void MeshFromGeometry::create_vertex_groups(Object *obj)

View File

@ -98,8 +98,8 @@ typedef struct MPoly {
/** #MPoly.flag */
enum {
ME_SMOOTH = (1 << 0),
#ifdef DNA_DEPRECATED_ALLOW
ME_SMOOTH = (1 << 0),
/** Deprecated selection status. Now stored in ".select_poly" attribute. */
ME_FACE_SEL = (1 << 1),
#endif

View File

@ -649,6 +649,32 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value)
hide_poly[index] = value;
}
static bool rna_MeshPolygon_use_smooth_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
const int index = rna_MeshPolygon_index_get(ptr);
return sharp_faces == NULL ? false : sharp_faces[index];
}
static void rna_MeshPolygon_use_smooth_set(PointerRNA *ptr, bool value)
{
Mesh *mesh = rna_mesh(ptr);
bool *sharp_faces = (bool *)CustomData_duplicate_referenced_layer_named(
&mesh->pdata, CD_PROP_BOOL, "sharp_face", mesh->totpoly);
if (!sharp_faces) {
if (value) {
/* Skip adding layer if it doesn't exist already anyway and we're not hiding an element. */
return;
}
sharp_faces = (bool *)CustomData_add_layer_named(
&mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, "sharp_face");
}
const int index = rna_MeshPolygon_index_get(ptr);
sharp_faces[index] = !value;
}
static bool rna_MeshPolygon_select_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
@ -1510,10 +1536,15 @@ static int rna_MeshLoopTriangle_material_index_get(PointerRNA *ptr)
static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr)
{
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
if (!sharp_faces) {
return true;
}
const Mesh *me = rna_mesh(ptr);
const MLoopTri *ltri = (MLoopTri *)ptr->data;
const MPoly *polys = BKE_mesh_polys(me);
return polys[ltri->poly].flag & ME_SMOOTH;
return sharp_faces[ltri->poly];
}
/* path construction */
@ -2561,8 +2592,9 @@ static void rna_def_mpolygon(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth", "");
RNA_def_property_boolean_funcs(
prop, "rna_MeshPolygon_use_smooth_get", "rna_MeshPolygon_use_smooth_set");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "use_freestyle_mark", PROP_BOOLEAN, PROP_NONE);

View File

@ -206,8 +206,6 @@ static void generate_ocean_geometry_polys(void *__restrict userdata,
mp->loopstart = fi * 4;
mp->totloop = 4;
mp->flag |= ME_SMOOTH;
}
}

View File

@ -198,15 +198,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx)
MEM_freeN(output);
}
if (rmd->flag & MOD_REMESH_SMOOTH_SHADING) {
MPoly *mpoly = BKE_mesh_polys_for_write(result);
int i, totpoly = result->totpoly;
/* Apply smooth shading to output faces */
for (i = 0; i < totpoly; i++) {
mpoly[i].flag |= ME_SMOOTH;
}
}
BKE_mesh_smooth_flag_set(result, (rmd->flag & MOD_REMESH_SMOOTH_SHADING));
BKE_mesh_copy_parameters_for_eval(result, mesh);
BKE_mesh_calc_edges(result, true, false);

View File

@ -247,8 +247,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ScrewVertConnect *vc, *vc_tmp, *vert_connect = nullptr;
const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0;
/* don't do anything? */
if (!totvert) {
return BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0, 0);
@ -890,7 +888,6 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
else {
origindex[mpoly_index] = ORIGINDEX_NONE;
dst_material_index[mpoly_index] = mat_nr;
mp_new->flag = mpoly_flag;
}
mp_new->loopstart = mpoly_index * 4;
mp_new->totloop = 4;
@ -1034,6 +1031,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
ltmd->merge_dist);
}
BKE_mesh_smooth_flag_set(result, ltmd->flag & MOD_SCREW_SMOOTH_SHADING);
return result;
}

View File

@ -11,8 +11,8 @@ static void node_declare(NodeDeclarationBuilder &b)
static void node_geo_exec(GeoNodeExecParams params)
{
Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth");
params.set_output("Smooth", std::move(shade_smooth_field));
Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("sharp_face");
params.set_output("Smooth", fn::invert_boolean_field(shade_smooth_field));
}
} // namespace blender::nodes::node_geo_input_shade_smooth_cc

View File

@ -16,34 +16,35 @@ static void node_declare(NodeDeclarationBuilder &b)
static void set_smooth(Mesh &mesh,
const Field<bool> &selection_field,
const Field<bool> &shade_field)
const Field<bool> &sharp_field)
{
if (mesh.totpoly == 0) {
return;
}
MutableAttributeAccessor attributes = mesh.attributes_for_write();
AttributeWriter<bool> smooth = attributes.lookup_or_add_for_write<bool>("shade_smooth",
ATTR_DOMAIN_FACE);
AttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write<bool>("sharp_face",
ATTR_DOMAIN_FACE);
bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE};
fn::FieldEvaluator evaluator{field_context, mesh.totpoly};
evaluator.set_selection(selection_field);
evaluator.add_with_destination(shade_field, smooth.varray);
evaluator.add_with_destination(sharp_field, sharp_faces.varray);
evaluator.evaluate();
smooth.finish();
sharp_faces.finish();
}
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
Field<bool> shade_field = params.extract_input<Field<bool>>("Shade Smooth");
Field<bool> smooth_field = params.extract_input<Field<bool>>("Shade Smooth");
geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
if (Mesh *mesh = geometry_set.get_mesh_for_write()) {
set_smooth(*mesh, selection_field, shade_field);
/* TODO: Do this with nodes instead. */
set_smooth(*mesh, selection_field, fn::invert_boolean_field(smooth_field));
}
});
params.set_output("Geometry", std::move(geometry_set));