Start moving ME_SMOOTH flag to generic "sharp_face" attribute
This commit is contained in:
parent
433d436b84
commit
54ae189d86
|
@ -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++) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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]]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -206,8 +206,6 @@ static void generate_ocean_geometry_polys(void *__restrict userdata,
|
|||
|
||||
mp->loopstart = fi * 4;
|
||||
mp->totloop = 4;
|
||||
|
||||
mp->flag |= ME_SMOOTH;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue